Compare commits

..

28 Commits

Author SHA1 Message Date
00f78f53d7 feat(i18n): wire services page and sub-components to translations
Some checks failed
Build & Push / build-and-push (push) Failing after 2m38s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:01:33 -04:00
1705b618c3 feat(i18n): add Italian and Spanish translations for about, services, and case study pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:01:25 -04:00
0189c56bec feat(i18n): wire work case study page to translations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:00:40 -04:00
901f76349a feat(i18n): add French translations for about, services, and case study pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:00:31 -04:00
ce6f029093 feat(i18n): wire about page visible content to translations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:00:12 -04:00
9ffd0885a2 feat(i18n): add English translation keys for about, services, and case study pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:57:56 -04:00
a8af84e864 fix(seo): canonical URL, og:locale:alternate, JSON-LD languages, sitemap x-default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:55:10 -04:00
d68dd6ffc3 feat(i18n): add Italian and Spanish support to configure API fallback briefs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:13:00 -04:00
db5bbc9e25 fix(i18n): replace hardcoded VoiceAgent locale ternary with translation key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:12:43 -04:00
3f203e4c46 feat(i18n): add Italian and Spanish Gemini voice agent system prompts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:11:39 -04:00
890f2184e1 feat(i18n): redesign nav locale switcher from binary toggle to multi-locale dropdown
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:11:17 -04:00
23a84cd31b feat(i18n): add full Spanish translation file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:11:05 -04:00
f2efa442bf feat(i18n): add full Italian translation file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:10:55 -04:00
cb6ee4783c feat(i18n): add IT/ES to metadata alternates, sitemap, and Payload CMS config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:08:30 -04:00
8a7267e769 feat(i18n): add Italian and Spanish to locale config and middleware
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:07:16 -04:00
09b91b1292 fix: consent mode v2 compliance + visual enhancements across sections
Some checks failed
Build & Push / build-and-push (push) Failing after 52s
Google Consent Mode v2: region-specific defaults (granted globally,
denied for EEA/UK), update all 4 consent types on accept/decline,
add url_passthrough and ads_data_redaction for better measurement.

Visual: unified 48px grid texture across all light sections, animated
constellation SVG in Process section, radial glow on Philosophy,
removed broken SVG connector lines and unused imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 16:19:24 -04:00
1b09059467 feat: add cookie consent banner for GDPR compliance
All checks were successful
Build & Push / build-and-push (push) Successful in 2m56s
Slides up on first visit, remembers choice in localStorage.
Accept → grants analytics_storage, Decline → keeps denied.
Returning visitors get their previous choice restored silently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 21:11:47 -04:00
5710d27663 feat: add GA4 custom event tracking for configurator and voice agent
All checks were successful
Build & Push / build-and-push (push) Successful in 1m23s
Events tracked:
- configurator_step_completed (with step number)
- configurator_brief_generated (with services and AI flag)
- voice_agent_started
- voice_agent_brief_generated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:57:31 -04:00
2e23e26fc1 fix: pass NEXT_PUBLIC_GA_ID as Docker build arg for GA4 to work
All checks were successful
Build & Push / build-and-push (push) Successful in 1m29s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:52:06 -04:00
518f86265e feat: deep SEO optimization — metadata, OG tags, sitemap, structured data, GA4
All checks were successful
Build & Push / build-and-push (push) Successful in 1m28s
- Add metadataBase and localized generateMetadata to all pages (EN/FR)
- Add Open Graph and Twitter card defaults with branded OG image
- Add canonical URLs and hreflang alternates on every page
- Create robots.ts (allow all, block /admin/ and /api/)
- Create sitemap.ts with all routes x 2 locales and hreflang
- Add Organization, WebSite, and CreativeWork JSON-LD structured data
- Add GA4 (G-LD348WF8EM) with Consent Mode v2 (default denied for EEA)
- Add llms.txt for AI discoverability
- Add production nginx config for letsbe.biz

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:38:52 -04:00
57faddc051 feat: add favicon and apple touch icon, center discovery CTA button
All checks were successful
Build & Push / build-and-push (push) Successful in 1m46s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 19:15:41 -04:00
24d8ab73f5 style: increase hero SVG geometric opacity for better visibility
All checks were successful
Build & Push / build-and-push (push) Successful in 1m41s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 18:34:09 -04:00
2d5e588b2e copy: rewrite site messaging to lead with design, temper infrastructure
All checks were successful
Build & Push / build-and-push (push) Successful in 1m43s
Complete copy overhaul across all pages (EN + FR):
- Hero: "Your website. Your software. Your entire digital world."
- Services: "Design. Build. Grow." with reordered pillars
- Philosophy: "We do things differently" — craft leads, ownership closes
- About: remove all Côte d'Azur/Riviera references, new story narrative
- Services page: less jargon, outcome-focused language, honest AI claims
- SEO metadata: includes all three pillars (design, AI, infrastructure)
- Trust bar, CTA, footer, configurator, case study CTAs all updated
- French translations updated to match all English changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:49:44 -04:00
029d3d7970 docs: add site copy redesign spec
Complete design spec for rewriting all user-facing copy to lead with
web design/development, position infrastructure as supporting
differentiator, remove geographic references, and temper AI claims.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:42:53 -04:00
2943d90ab1 fix: show project card images in full color, add hover zoom
All checks were successful
Build & Push / build-and-push (push) Successful in 1m22s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:46:48 -04:00
40e9a257f7 feat: add hero background images to case study detail pages
Some checks failed
Build & Push / build-and-push (push) Has been cancelled
Each project page now has its image behind the hero text with a
dark gradient overlay for readability. Tags use a glass-morphism
style on the image background.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:46:21 -04:00
1f6bb7d066 feat: replace geometric placeholders with real project and brand images
All checks were successful
Build & Push / build-and-push (push) Successful in 1m35s
- Monaco Ocean: monaco_high_res.jpg in featured card
- Port Nimara: anguilla.png in small card
- Port Amador: panama.png in small card
- Philosophy section: philosophy_image.png replaces AbstractGeometry
- About "Our Story": our_story.png replaces StoryGeometry
- Removed all geometric placeholder components (GeometricPlaceholder,
  AbstractGeometry, StoryGeometry)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:32:09 -04:00
bcc09542b7 fix: respond to request_contact immediately, send confirmation as text
All checks were successful
Build & Push / build-and-push (push) Successful in 1m43s
The deferred tool response approach caused Gemini to timeout waiting.
Now request_contact responds immediately (telling the agent to wait),
and the confirm button sends a text message through the live WebSocket
to trigger complete_brief.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 15:52:53 -04:00
54 changed files with 3140 additions and 1211 deletions

View File

@@ -24,3 +24,6 @@ NEXT_PUBLIC_CALCOM_URL=https://cal.letsbe.biz
# ── Site URL ── # ── Site URL ──
NEXT_PUBLIC_SITE_URL=https://staging.letsbe.biz NEXT_PUBLIC_SITE_URL=https://staging.letsbe.biz
# ── Google Analytics ──
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX

View File

@@ -38,5 +38,6 @@ jobs:
PAYLOAD_SECRET=${{ secrets.PAYLOAD_SECRET }} PAYLOAD_SECRET=${{ secrets.PAYLOAD_SECRET }}
NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }} NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
NEXT_PUBLIC_CALCOM_URL=${{ secrets.NEXT_PUBLIC_CALCOM_URL }} NEXT_PUBLIC_CALCOM_URL=${{ secrets.NEXT_PUBLIC_CALCOM_URL }}
NEXT_PUBLIC_GA_ID=${{ vars.NEXT_PUBLIC_GA_ID }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE }}:buildcache cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE }}:buildcache,mode=max cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE }}:buildcache,mode=max

3
.gitignore vendored
View File

@@ -31,3 +31,6 @@ public/media/
# superpowers # superpowers
.superpowers/ .superpowers/
# private credentials
private/

View File

@@ -18,11 +18,13 @@ ARG DATABASE_URI
ARG PAYLOAD_SECRET ARG PAYLOAD_SECRET
ARG NEXT_PUBLIC_SITE_URL ARG NEXT_PUBLIC_SITE_URL
ARG NEXT_PUBLIC_CALCOM_URL ARG NEXT_PUBLIC_CALCOM_URL
ARG NEXT_PUBLIC_GA_ID
ENV DATABASE_URI=${DATABASE_URI} ENV DATABASE_URI=${DATABASE_URI}
ENV PAYLOAD_SECRET=${PAYLOAD_SECRET} ENV PAYLOAD_SECRET=${PAYLOAD_SECRET}
ENV NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL} ENV NEXT_PUBLIC_SITE_URL=${NEXT_PUBLIC_SITE_URL}
ENV NEXT_PUBLIC_CALCOM_URL=${NEXT_PUBLIC_CALCOM_URL} ENV NEXT_PUBLIC_CALCOM_URL=${NEXT_PUBLIC_CALCOM_URL}
ENV NEXT_PUBLIC_GA_ID=${NEXT_PUBLIC_GA_ID}
RUN npm run build RUN npm run build

View File

@@ -0,0 +1,151 @@
# SEO Optimization — Design Spec
**Date:** 2026-04-07
**Domain:** letsbe.biz
**Stack:** Next.js 16 App Router, next-intl (en/fr, `as-needed` prefix), Payload CMS
## Current State
The site has a single `metadata` export in the layout with a generic title/description. No robots.txt, no sitemap, no OG tags, no hreflang, no structured data, no analytics. The services page has a static English-only metadata export. Case study pages and the homepage have no metadata at all.
## 1. Metadata Foundation
### metadataBase
Add `metadataBase: new URL('https://letsbe.biz')` to `src/app/(frontend)/[locale]/layout.tsx`. Required for OG images and canonical URLs to resolve as absolute URLs.
### i18n SEO keys
Add a `meta` section to both `en.json` and `fr.json`:
```json
{
"meta": {
"home": { "title": "...", "description": "..." },
"about": { "title": "...", "description": "..." },
"services": { "title": "...", "description": "..." },
"work": {
"monaco-ocean": { "title": "...", "description": "..." },
"port-nimara": { "title": "...", "description": "..." },
"port-amador": { "title": "...", "description": "..." }
}
}
}
```
### Per-page generateMetadata
Convert every page to use `generateMetadata({ params })`:
- Read locale from params
- Call `getTranslations({ locale, namespace: 'meta' })` for localized title/description
- Set `alternates.canonical` (e.g., `https://letsbe.biz/about` for en, `https://letsbe.biz/fr/about` for fr)
- Set `alternates.languages` for hreflang:
- `en` → unprefixed path
- `fr``/fr/` prefixed path
- `x-default` → unprefixed (English)
### Layout metadata
Convert the layout's static `metadata` to `generateMetadata()` so it can set locale-aware defaults, `metadataBase`, and default OG/Twitter config.
## 2. Social Sharing (Open Graph / Twitter)
### Default OG in layout
```ts
openGraph: {
type: 'website',
siteName: 'LetsBe.',
locale: locale === 'fr' ? 'fr_FR' : 'en_US',
images: [{ url: '/images/og-default.png', width: 1200, height: 630 }],
}
twitter: {
card: 'summary_large_image',
}
```
### OG image
Create a 1200x630 OG default image using sharp — the logo centered on a branded background (the site's surface color with the blue accent). Place at `public/images/og-default.png`.
### Per-page OG
Case study pages override with their hero image. Other pages use the default.
## 3. Crawl Infrastructure
### robots.ts
`src/app/robots.ts`:
- Allow all user agents
- Disallow `/admin/`, `/api/`
- Sitemap: `https://letsbe.biz/sitemap.xml`
### sitemap.ts
`src/app/sitemap.ts`:
- Static routes: `/`, `/about`, `/services`
- Dynamic routes: `/work/monaco-ocean`, `/work/port-nimara`, `/work/port-amador`
- Each entry includes both locale variants in `alternates.languages`
- `lastModified` set to build date
- `changeFrequency` and `priority` set appropriately
## 4. Structured Data (JSON-LD)
Inject via `<script type="application/ld+json">` in layout and page components.
### Organization (layout)
```json
{
"@type": "Organization",
"name": "LetsBe.",
"url": "https://letsbe.biz",
"logo": "https://letsbe.biz/images/letsbe-logo-short.png",
"sameAs": ["linkedin-url", "x-url"]
}
```
### WebSite (homepage)
```json
{
"@type": "WebSite",
"name": "LetsBe.",
"url": "https://letsbe.biz"
}
```
### Service (services page)
One `Service` entry per pillar (Design, Software, Infrastructure).
### CreativeWork (case study pages)
Per-project with title, description, image, creator → Organization.
## 5. Google Analytics + Consent Mode
### GA4 integration
- Measurement ID: `G-LD348WF8EM`
- Use Next.js `@next/third-parties/google` GoogleAnalytics component (or `next/script` if the package isn't available)
- Place in the layout, render only in production (`process.env.NODE_ENV === 'production'`)
### Consent Mode v2
Set default consent state before GA loads:
```js
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
wait_for_update: 500,
});
```
This lets GA4 run in cookieless mode (modeled conversions, basic pageviews) without requiring a cookie banner. A full consent banner can be added later to unlock full measurement.
### Environment variable
`NEXT_PUBLIC_GA_ID=G-LD348WF8EM` in `.env` / `.env.production`.
## Files to Create/Modify
| File | Action |
|------|--------|
| `src/app/(frontend)/[locale]/layout.tsx` | Convert to generateMetadata, add OG, add JSON-LD Organization |
| `src/app/(frontend)/[locale]/page.tsx` | Add generateMetadata, add JSON-LD WebSite |
| `src/app/(frontend)/[locale]/about/page.tsx` | Add generateMetadata |
| `src/app/(frontend)/[locale]/services/page.tsx` | Replace static metadata with generateMetadata, add JSON-LD Service |
| `src/app/(frontend)/[locale]/work/[slug]/page.tsx` | Add generateMetadata, add JSON-LD CreativeWork |
| `src/i18n/messages/en.json` | Add `meta` section |
| `src/i18n/messages/fr.json` | Add `meta` section |
| `src/app/robots.ts` | Create |
| `src/app/sitemap.ts` | Create |
| `public/images/og-default.png` | Create (generated via sharp) |
| `src/components/analytics/GoogleAnalytics.tsx` | Create (GA4 + consent mode) |
| `.env.production` | Add `NEXT_PUBLIC_GA_ID` |

View File

@@ -0,0 +1,220 @@
# Site Copy Redesign — Design Spec
**Date:** 2026-04-07
**Goal:** Rewrite all user-facing copy to lead with web design/development, position infrastructure as a supporting differentiator, and remove all Côte d'Azur / French Riviera geographic references.
## Messaging Strategy
**Approach:** "The Complete Partner" — design-forward but immediately signals full-service depth. The client comes for the website, then discovers they can also get custom software, hosting, and AI from the same team.
**Target client:** SMB founders whose current website doesn't represent their business well.
**Tone:** Conversational yet polished — confident and warm, not stiff or fluffy. Light technical credibility signals, not jargon-heavy.
**Hierarchy:**
1. Web design & development (leads)
2. Custom software (extends)
3. Hosting & infrastructure (supports, positioned as differentiator not lead)
4. AI (prominent, practical, honest about capabilities)
**Geographic references:** Remove ALL Côte d'Azur / French Riviera references. LetsBe is an American company.
---
## Copy Changes By Section
### 1. SEO Metadata
**Site title:** "LetsBe. | Web Design, AI & Digital Infrastructure Studio"
**Site description:** "Custom web design, purpose-built software, AI integration, and private infrastructure — designed, built, and managed by one dedicated team."
**Services page description:** "Custom web design, purpose-built software, AI automation, and private infrastructure — three pillars of digital excellence under one roof."
### 2. Homepage — Hero
**Headline:** "Your website. Your software. Your *entire* digital world."
*(accent word: "entire" in italic/primary blue)*
**Subtitle:** "Custom websites, purpose-built software, and the infrastructure to run it all — designed, built, and managed by one dedicated team."
**Primary CTA:** "Start Your Project"
**Secondary CTA:** "See Our Work"
**Trust line:** "Trusted by businesses worldwide"
### 3. Homepage — Trust Bar
| Card | Title | Description |
|------|-------|-------------|
| 1 | Designed From Scratch | No templates, no page builders. Every site is custom-designed and hand-built for your brand. |
| 2 | One Team, Start to Finish | No freelancer juggling. One team handles design, code, hosting, and support. |
| 3 | AI Built In | Intelligent features and automation woven directly into your website and software. |
| 4 | You Own Everything | Your code, your data, your servers. We build it, you own it — no lock-in, no surprises. |
### 4. Homepage — Services Overview
**Eyebrow:** "What We Do"
**Title:** "Design. Build. Grow."
| Pillar | Title | Features |
|--------|-------|----------|
| 01 | Web Design & Development | Custom Website Design, Responsive Development, SEO & Performance, Content Management |
| 02 | Software & Platforms | Business Management Tools, CRMs & Dashboards, Booking & Scheduling Systems, API Integrations |
| 03 | Hosting & Infrastructure | Dedicated Servers, Email & Cloud Storage, Security & Monitoring, Ongoing Support |
**AI callout (italic):** "And we layer AI into everything — from intelligent features in your website to automation that connects all your tools."
### 5. Homepage — Philosophy
**Eyebrow:** "Why Us"
**Title:** "We do things differently."
**Subtitle:** "Most agencies hand you a template and call it custom. We think your business deserves better — real design, real engineering, and a team that sticks around after launch."
| Pillar | Title | Description |
|--------|-------|-------------|
| 01 | Craft Over Convenience | We write clean, hand-built code optimized for speed and search engines. No page builders, no bloated themes, no shortcuts. |
| 02 | One Relationship | From first design to ongoing support — one team that knows your business inside and out. No handoffs, no telephone-game briefs. |
| 03 | Built to Be Yours | Everything we build, you own. Your code, your data, your infrastructure — no lock-in, no platform dependencies, no surprises. |
**Pull quote:** "We build technology that works for your business — not the other way around." — Matt Ciaccio, Founder
### 6. Homepage — CTA Banner
**Eyebrow:** "Let's Talk"
**Title:** "Ready to build something great?"
**Subtitle:** "Tell us what you're working on. No pitch decks, no pressure — just an honest conversation about what's possible."
**Primary CTA:** "Start Your Project"
**Email:** hello@letsbe.biz
**Fine print:** "No commitment required."
### 7. Footer
**Tagline:** "Custom websites, software, and digital platforms — designed and built for businesses that refuse to settle."
**Location:** "American-founded. Serving clients worldwide."
### 8. About Page — Hero
**Eyebrow:** "About LetsBe."
**Headline:** "Great businesses deserve great digital partners."
**Subtitle:** "We design and build custom websites, software, and digital platforms for businesses that care about quality — and want a team that does too."
### 9. About Page — Our Story
**Eyebrow:** "Our Story"
**Heading:** "Built for businesses like yours."
**Para 1:** "LetsBe. started with a simple belief: that ambitious businesses deserve digital tools as carefully considered as the work they do. Not templates. Not off-the-shelf platforms. Real design and engineering, built from scratch."
**Para 2:** "Our early clients were founders and operators who needed more than a website — they needed a technical partner who could design, build, host, and maintain everything under one roof. Those projects shaped how we work today."
**Para 3:** "We build platforms meant to be owned, not rented. We document everything, we hand over codebases that outlast the engagement, and we never lock clients into systems they can't leave. That's not a feature — it's how we think business should work."
**Pull quote:** "Build fewer things. Build them better. Build them to last." — LetsBe. founding principle
### 10. About Page — What We Believe
**Eyebrow:** "Our Beliefs"
**Heading:** "What We Believe"
**Intro:** "Three principles behind every project we take on."
| # | Title | Description |
|---|-------|-------------|
| 1 | Craftsmanship First | The gap between a website that works and one that lasts is craft. We sweat the typography, the transitions, the performance, the edge cases. Every interface we ship is something we'd be proud to sign. |
| 2 | One Team, Everything | Design, development, hosting, infrastructure — one team, one point of contact, one standard of quality. No handoffs between agencies. No juggling freelancers. Just people who care about the whole thing. |
| 3 | Built to Be Yours | Everything we build, you own — the code, the data, the infrastructure. No vendor lock-in, no platform dependencies. We hand over work that outlasts the engagement. |
### 11. About Page — Quote
**Quote:** "We don't just build websites — we build the foundation your business runs on."
**Attribution:** "— LetsBe. founding philosophy"
### 12. About Page — CTA
**Eyebrow:** "Work With Us"
**Heading:** "Let's build something together."
**Subtitle:** "Whether you have a clear brief or just an early idea, we'd love to talk through what's possible."
### 13. Services Page — Hero
**Eyebrow:** "Our Services"
**Headline:** "Everything your business needs online."
**Subtitle:** "We design custom websites, build purpose-built software, and manage the infrastructure behind it all — one team, one standard of quality, nothing outsourced."
### 14. Services Page — Pillar 01: Web Design & Development
**Description:** "Your website shouldn't look like everyone else's — and it shouldn't be built like everyone else's either. We design and build custom websites and web applications from a blank canvas, crafting every layout, every interaction, and every page with intention. The result is fast, search-engine-friendly, and built to grow with your business. Whether you need a marketing site that converts, a web application your team relies on, or an e-commerce platform that scales — we build it from scratch, and we build it to last."
| Feature | Title | Description |
|---------|-------|-------------|
| Design | Custom Design | Every layout, component, and interaction is designed for your brand. No themes, no templates, no shortcuts. |
| Apps | Web Applications | Modern, responsive applications built with the latest technologies — fast, reliable, and ready to scale. |
| E-commerce | E-Commerce | Custom storefronts, checkout flows, and multi-currency platforms built for serious online retail. |
| Performance | Performance & SEO | Fast load times, clean code, and search engine optimization built into the foundation — not bolted on after. |
### 15. Services Page — Pillar 02: Software & Platforms
**Description:** "Off-the-shelf software makes assumptions about how your business works. We don't. When spreadsheets and generic tools stop cutting it, we build the exact system your team needs — designed around your workflow, not someone else's. From CRMs tailored to your sales process, to management platforms that replace three different subscriptions, to integrations that connect your existing tools — everything we build is yours, fully documented, and built to last."
| Feature | Title | Description |
|---------|-------|-------------|
| CRM | CRM & Management Tools | Relationship and pipeline management built around how your team actually works — not how a generic platform thinks you should. |
| Software | Custom Software | From booking platforms to internal tools to full SaaS products — purpose-built for your business. |
| APIs | Integrations & APIs | We connect your existing tools and build the bridges between systems so everything works together. |
| Internal | Dashboards & Automation | Admin panels, reporting tools, and workflow automation that give your team an unfair advantage. |
### 16. Services Page — Pillar 03: Hosting & Infrastructure
**Description:** "Your website and software need a home — and we think you should own it. We set up and manage dedicated servers, email, cloud storage, and all the infrastructure your business runs on. No shared hosting, no mysterious third-party dependencies. You know where your data lives, who has access, and that someone is watching the dashboard around the clock."
| Feature | Title | Description |
|---------|-------|-------------|
| Hosting | Dedicated Hosting | Private servers managed for your business — no shared hosting, no noisy neighbors, no surprises. |
| Data | Your Data, Your Control | You own your data and know exactly where it lives. Full access, full transparency, no lock-in. |
| Security | Security & Protection | Serious security, proactive monitoring, and protection built into your infrastructure from day one. |
| DevOps | Monitoring & Support | Proactive monitoring, regular updates, and ongoing support so you never have to worry about uptime. |
### 17. Services Page — AI Layer
**Eyebrow:** "Intelligent Layer"
**Title:** "AI Built Into Everything"
**Italic subtitle:** "Your platform, made smarter."
**Body:** "We integrate AI directly into the websites and software we build for you. Not as a buzzword or an add-on — as practical features that save your team time and give your customers a better experience."
| Capability | Title | Description |
|------------|-------|-------------|
| Teammate | AI Teammate | An AI assistant built into your workflow — automates repetitive tasks, surfaces the info your team needs, and connects your tools. |
| Customer | Customer-Facing AI | Smart features for your customers — intelligent search, personalized recommendations, and conversational interfaces that work around the clock. |
| Data | Data Intelligence | AI that helps you understand your data — automated reports, trend spotting, and insights you can actually act on. |
**Bottom note:** "Every AI feature is tailored to your business — your data stays on your servers."
### 18. Services Page — CTA
**Eyebrow:** "Let's Talk"
**Heading:** "Ready to get started?"
**Subtitle:** "Walk through a few questions and we'll put together a project brief tailored to you — no commitment required, just clarity."
**Primary CTA:** "Start Your Project"
**Email:** hello@letsbe.biz
**Fine print:** "No commitment required — just a conversation about what's possible."
### 19. Configurator — Service Options
**Web Design & Development:** "Custom websites and web applications — designed from scratch, built to perform, and optimized to get found."
**Custom Software:** "CRMs, management platforms, and business tools built around the way your team actually works."
**Private Infrastructure:** "Dedicated hosting, email, cloud storage, and the infrastructure your business runs on — fully owned by you."
**AI Toggle:** "Practical AI features and automation built directly into your website and software."
### 20. Case Study Pages — CTA
**Eyebrow:** "Your Turn"
**Heading:** "Ready to build something like this?"
**Body:** "Every project starts with a conversation. Tell us what you're working on and we'll figure out the best way to bring it to life."
**CTA:** "Start your project"
---
## Implementation Notes
- **i18n files** (`src/i18n/messages/en.json`): Most homepage, nav, footer, configurator, and process section copy lives here. Update the JSON keys.
- **Hardcoded pages**: About (`src/app/(frontend)/[locale]/about/page.tsx`), Services (`src/app/(frontend)/[locale]/services/page.tsx`, `src/components/sections/services/ServicesHero.tsx`, `src/components/sections/services/AILayer.tsx`, `src/components/sections/services/ServicesCTA.tsx`), and Case Studies (`src/app/(frontend)/[locale]/work/[slug]/page.tsx`) have inline English copy — edit directly.
- **French translations** (`src/i18n/messages/fr.json`): Update French translations to match the new English copy for all i18n'd sections.
- **SEO metadata**: Update in `src/app/(frontend)/[locale]/layout.tsx` and `src/app/(frontend)/[locale]/services/page.tsx`.
- **No structural/layout changes** — this is a copy-only update.

60
nginx/letsbe.biz.conf Normal file
View File

@@ -0,0 +1,60 @@
# Redirect www → non-www
server {
listen 80;
listen [::]:80;
server_name www.letsbe.biz;
# Certbot will upgrade this to https after cert is issued
return 301 http://letsbe.biz$request_uri;
}
# Main site
server {
listen 80;
listen [::]:80;
server_name letsbe.biz;
# Certbot will add SSL config after:
# sudo certbot --nginx -d letsbe.biz -d www.letsbe.biz
location / {
proxy_pass http://127.0.0.1:6974;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 86400;
}
# Static assets — long cache
location /_next/static/ {
proxy_pass http://127.0.0.1:6974;
proxy_cache_valid 200 365d;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# Public assets
location /images/ {
proxy_pass http://127.0.0.1:6974;
proxy_cache_valid 200 30d;
add_header Cache-Control "public, max-age=2592000";
}
# Payload media uploads
location /media/ {
proxy_pass http://127.0.0.1:6974;
proxy_cache_valid 200 30d;
add_header Cache-Control "public, max-age=2592000";
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
client_max_body_size 50M;
}

27
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@calcom/embed-react": "^1.5.3", "@calcom/embed-react": "^1.5.3",
"@google/genai": "^1.46.0", "@google/genai": "^1.48.0",
"@payloadcms/db-postgres": "^3.80.0", "@payloadcms/db-postgres": "^3.80.0",
"@payloadcms/next": "^3.80.0", "@payloadcms/next": "^3.80.0",
"@payloadcms/richtext-lexical": "^3.80.0", "@payloadcms/richtext-lexical": "^3.80.0",
@@ -1435,9 +1435,9 @@
} }
}, },
"node_modules/@google/genai": { "node_modules/@google/genai": {
"version": "1.46.0", "version": "1.48.0",
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.46.0.tgz", "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.48.0.tgz",
"integrity": "sha512-ewPMN5JkKfgU5/kdco9ZhXBHDPhVqZpMQqIFQhwsHLf8kyZfx1cNpw1pHo1eV6PGEW7EhIBFi3aYZraFndAXqg==", "integrity": "sha512-plonYK4ML2PrxsRD9SeqmFt76eREWkQdPCglOA6aYDzL1AAbE+7PUnT54SvpWGfws13L0AZEqGSpL7+1IPnTxQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"google-auth-library": "^10.3.0", "google-auth-library": "^10.3.0",
@@ -3633,14 +3633,6 @@
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@types/unist": { "node_modules/@types/unist": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@@ -6714,17 +6706,6 @@
} }
} }
}, },
"node_modules/next-intl/node_modules/@swc/helpers": {
"version": "0.5.20",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.20.tgz",
"integrity": "sha512-2egEBHUMasdypIzrprsu8g+OEVd7Vp2MM3a2eVlM/cyFYto0nGz5BX5BTgh/ShZZI9ed+ozEq+Ngt+rgmUs8tw==",
"license": "Apache-2.0",
"optional": true,
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
},
"node_modules/next/node_modules/postcss": { "node_modules/next/node_modules/postcss": {
"version": "8.4.31", "version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",

View File

@@ -11,7 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@calcom/embed-react": "^1.5.3", "@calcom/embed-react": "^1.5.3",
"@google/genai": "^1.46.0", "@google/genai": "^1.48.0",
"@payloadcms/db-postgres": "^3.80.0", "@payloadcms/db-postgres": "^3.80.0",
"@payloadcms/next": "^3.80.0", "@payloadcms/next": "^3.80.0",
"@payloadcms/richtext-lexical": "^3.80.0", "@payloadcms/richtext-lexical": "^3.80.0",

BIN
public/images/anguilla.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/images/our_story.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/images/panama.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

31
public/llms.txt Normal file
View File

@@ -0,0 +1,31 @@
# LetsBe.
> Bespoke digital studio — custom web design, software, AI integration, and private infrastructure.
LetsBe. is a digital studio founded by Matt Ciaccio, serving clients worldwide from the Côte d'Azur, France. We design and build custom websites, purpose-built software, and manage private digital infrastructure — all under one roof.
## Services
- **Web Design & Development**: Custom websites and web applications designed from scratch, built for performance and SEO.
- **Software & Platforms**: CRMs, management tools, dashboards, booking systems, and API integrations built around your workflow.
- **Hosting & Infrastructure**: Dedicated servers, email, cloud storage, security, and monitoring — fully owned by the client.
- **AI Integration**: Intelligent features, automation, and data intelligence woven into websites and software.
## Selected Work
- [Monaco Ocean Protection Challenge](/work/monaco-ocean): AI-powered judging and analytics platform for a Mediterranean conservation event.
- [Port Nimara](/work/port-nimara): Custom website and CRM for marina lead management and operations.
- [Port Amador](/work/port-amador): Website and private digital infrastructure for a premium marina.
## Key Pages
- [Home](https://letsbe.biz)
- [Services](https://letsbe.biz/services)
- [About](https://letsbe.biz/about)
- [Start a Project](https://letsbe.biz/#configure)
## Contact
- Email: hello@letsbe.biz
- LinkedIn: https://www.linkedin.com/company/letsbe-digital
- X: https://x.com/letsbe_digital

View File

@@ -1,163 +1,50 @@
import { setRequestLocale } from 'next-intl/server'; import Image from 'next/image';
import type { Metadata } from 'next';
import { getTranslations, setRequestLocale } from 'next-intl/server';
import { Shield, PenTool, Users } from 'lucide-react'; import { Shield, PenTool, Users } from 'lucide-react';
import ScrollReveal from '@/components/ui/ScrollReveal'; import ScrollReveal from '@/components/ui/ScrollReveal';
import Button from '@/components/ui/Button'; import Button from '@/components/ui/Button';
import CornerBracket from '@/components/icons/CornerBracket'; import CornerBracket from '@/components/icons/CornerBracket';
import { routing } from '@/i18n/routing'; import { routing } from '@/i18n/routing';
const BASE_URL = 'https://letsbe.biz';
// ─── Metadata ─────────────────────────────────────────────────────────────────
type PageProps = {
params: Promise<{ locale: string }>;
};
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'meta.about' });
const path = locale === 'en' ? '/about' : `/${locale}/about`;
return {
title: t('title'),
description: t('description'),
alternates: {
canonical: `${BASE_URL}${path}`,
languages: {
'en': `${BASE_URL}/about`,
'fr': `${BASE_URL}/fr/about`,
'it': `${BASE_URL}/it/about`,
'es': `${BASE_URL}/es/about`,
'x-default': `${BASE_URL}/about`,
},
},
};
}
// ─── Static Generation ──────────────────────────────────────────────────────── // ─── Static Generation ────────────────────────────────────────────────────────
export function generateStaticParams() { export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale })); return routing.locales.map((locale) => ({ locale }));
} }
// ─── Data ─────────────────────────────────────────────────────────────────────
const PILLARS = [
{
id: 'ownership',
Icon: Shield,
title: 'Ownership & Privacy',
description:
'We build on infrastructure you control. No vendor lock-in, no opaque SaaS dependencies quietly holding your data hostage. Your platform, your servers, your rules — backed by engineering that makes it maintainable.',
},
{
id: 'craftsmanship',
Icon: PenTool,
title: 'Craftsmanship',
description:
'The gap between a website that works and one that endures is craft. We sweat the typography, the transitions, the query performance, the edge cases. Every interface we ship is something we would be proud to sign.',
},
{
id: 'one-team',
Icon: Users,
title: 'One Team, Everything',
description:
'Strategy, design, engineering, infrastructure — under one roof, one point of contact, one shared standard of quality. No handoffs between agencies. No telephone-game briefs. Just people who care about the whole thing.',
},
];
// ─── Sub-components ─────────────────────────────────────────────────────────── // ─── Sub-components ───────────────────────────────────────────────────────────
function StoryGeometry() {
return (
<div
className="absolute inset-0 overflow-hidden rounded-xl"
aria-hidden="true"
>
{/* Primary gradient circle — top right */}
<div
className="absolute rounded-full"
style={{
width: '70%',
height: '70%',
top: '-15%',
right: '-15%',
background:
'radial-gradient(circle, rgba(91,164,217,0.10) 0%, rgba(0,100,148,0.05) 55%, transparent 100%)',
}}
/>
{/* Secondary circle — bottom left */}
<div
className="absolute rounded-full"
style={{
width: '55%',
height: '55%',
bottom: '-10%',
left: '-8%',
background:
'radial-gradient(circle, rgba(46,196,160,0.07) 0%, transparent 70%)',
}}
/>
{/* Diagonal grid texture */}
<div
className="absolute inset-0 opacity-[0.025]"
style={{
backgroundImage:
'repeating-linear-gradient(-45deg, var(--color-primary-dark) 0, var(--color-primary-dark) 1px, transparent 0, transparent 50%)',
backgroundSize: '28px 28px',
}}
/>
{/* Tilted rectangle — left center */}
<div
className="absolute rounded-lg"
style={{
width: '24%',
height: '34%',
top: '18%',
left: '6%',
border: '1.5px solid rgba(91,164,217,0.12)',
transform: 'rotate(-6deg)',
}}
/>
{/* Dot field — right center */}
<div
className="absolute"
style={{
width: '28%',
height: '28%',
top: '30%',
right: '8%',
backgroundImage:
'radial-gradient(circle, rgba(91,164,217,0.22) 1.5px, transparent 1.5px)',
backgroundSize: '10px 10px',
}}
/>
{/* Dashed arc */}
<svg
className="absolute"
style={{ top: '15%', left: '28%', opacity: 0.07 }}
width="160"
height="160"
viewBox="0 0 160 160"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="80"
cy="80"
r="68"
stroke="var(--color-primary-dark)"
strokeWidth="1"
strokeDasharray="7 5"
/>
</svg>
{/* Small accent square */}
<div
className="absolute rounded-sm"
style={{
width: '5%',
height: '5%',
bottom: '26%',
right: '26%',
background: 'rgba(91,164,217,0.18)',
transform: 'rotate(14deg)',
}}
/>
{/* Teal accent line — bottom */}
<div
className="absolute"
style={{
width: '30%',
height: '2px',
bottom: '14%',
left: '50%',
transform: 'translateX(-50%)',
background:
'linear-gradient(to right, transparent, rgba(46,196,160,0.35), transparent)',
}}
/>
</div>
);
}
function PillarCard({ function PillarCard({
Icon, Icon,
title, title,
@@ -205,6 +92,14 @@ export default async function AboutPage({ params }: Props) {
const { locale } = await params; const { locale } = await params;
setRequestLocale(locale); setRequestLocale(locale);
const t = await getTranslations({ locale, namespace: 'aboutPage' });
const PILLARS = [
{ id: 'craftsmanship', Icon: PenTool, title: t('pillars.craftsmanship.title'), description: t('pillars.craftsmanship.description') },
{ id: 'one-team', Icon: Users, title: t('pillars.oneTeam.title'), description: t('pillars.oneTeam.description') },
{ id: 'ownership', Icon: Shield, title: t('pillars.ownership.title'), description: t('pillars.ownership.description') },
];
return ( return (
<main> <main>
@@ -214,21 +109,18 @@ export default async function AboutPage({ params }: Props) {
<div className="max-w-4xl mx-auto flex flex-col items-center text-center gap-8"> <div className="max-w-4xl mx-auto flex flex-col items-center text-center gap-8">
<ScrollReveal variant="fadeIn"> <ScrollReveal variant="fadeIn">
<span className="label-md text-primary">About LetsBe.</span> <span className="label-md text-primary">{t('hero.eyebrow')}</span>
</ScrollReveal> </ScrollReveal>
<ScrollReveal variant="fadeUp" delay={0.1}> <ScrollReveal variant="fadeUp" delay={0.1}>
<h1 className="font-serif font-semibold text-on-surface text-5xl md:text-6xl lg:text-[4rem] leading-[1.05] tracking-[-0.03em]"> <h1 className="font-serif font-semibold text-on-surface text-5xl md:text-6xl lg:text-[4rem] leading-[1.05] tracking-[-0.03em]">
Digital Sovereignty {t('hero.title')}
<br />
is not a luxury.
</h1> </h1>
</ScrollReveal> </ScrollReveal>
<ScrollReveal variant="fadeUp" delay={0.2}> <ScrollReveal variant="fadeUp" delay={0.2}>
<p className="text-outline text-xl leading-relaxed max-w-2xl"> <p className="text-outline text-xl leading-relaxed max-w-2xl">
We build digital platforms for businesses that refuse to compromise on ownership, {t('hero.subtitle')}
on quality, or on the partner they trust to build it with them.
</p> </p>
</ScrollReveal> </ScrollReveal>
@@ -245,33 +137,16 @@ export default async function AboutPage({ params }: Props) {
<div className="lg:col-span-5 flex flex-col gap-10"> <div className="lg:col-span-5 flex flex-col gap-10">
<ScrollReveal variant="slideLeft" className="flex flex-col gap-4"> <ScrollReveal variant="slideLeft" className="flex flex-col gap-4">
<span className="label-md text-primary">Our Story</span> <span className="label-md text-primary">{t('story.eyebrow')}</span>
<h2 className="font-serif text-4xl md:text-[2.75rem] font-semibold text-on-surface leading-[1.1] tracking-[-0.02em]"> <h2 className="font-serif text-4xl md:text-[2.75rem] font-semibold text-on-surface leading-[1.1] tracking-[-0.02em]">
Born on the<br /> {t('story.title')}
Côte d&rsquo;Azur.
</h2> </h2>
</ScrollReveal> </ScrollReveal>
<ScrollReveal variant="fadeUp" delay={0.1} className="flex flex-col gap-5 text-outline leading-relaxed text-[0.9375rem]"> <ScrollReveal variant="fadeUp" delay={0.1} className="flex flex-col gap-5 text-outline leading-relaxed text-[0.9375rem]">
<p> <p>{t('story.p1')}</p>
LetsBe. was founded on the French Riviera by a small team of engineers and <p>{t('story.p2')}</p>
designers who shared a single conviction: that ambitious businesses deserve digital <p>{t('story.p3')}</p>
infrastructure as carefully considered as the work they do.
</p>
<p>
We started by building for founders and institutions along the coast port
authorities, conservation organisations, maritime operators each one operating
in a context where reliability, elegance, and discretion were not optional extras.
Those early projects shaped everything we believe about what a digital partner
should be.
</p>
<p>
Today we work with clients across Europe and the Mediterranean on platforms that
are built to be owned, not rented. We do not believe in locking clients into
systems they cannot see, services they cannot leave, or vendors whose priorities
will drift from theirs. We build on open infrastructure, we document everything,
and we hand over codebases that outlast the engagement.
</p>
</ScrollReveal> </ScrollReveal>
</div> </div>
@@ -283,7 +158,13 @@ export default async function AboutPage({ params }: Props) {
className="relative bg-surface rounded-xl overflow-hidden" className="relative bg-surface rounded-xl overflow-hidden"
style={{ minHeight: '460px' }} style={{ minHeight: '460px' }}
> >
<StoryGeometry /> <Image
src="/images/our_story.png"
alt="Our story"
fill
className="object-cover rounded-xl"
sizes="(max-width: 1024px) 100vw, 58vw"
/>
{/* Inset rim */} {/* Inset rim */}
<div <div
@@ -311,13 +192,13 @@ export default async function AboutPage({ params }: Props) {
/> />
</div> </div>
<blockquote className="font-serif italic text-lg text-on-surface leading-relaxed pr-8"> <blockquote className="font-serif italic text-lg text-on-surface leading-relaxed pr-8">
&ldquo;Build fewer things. Build them better. Build them to last.&rdquo; "{t('story.quote')}"
</blockquote> </blockquote>
<div <div
className="w-8 h-px bg-primary/40 my-4" className="w-8 h-px bg-primary/40 my-4"
aria-hidden="true" aria-hidden="true"
/> />
<p className="label-md text-outline">LetsBe. founding principle</p> <p className="label-md text-outline">{t('story.quoteAttrib')}</p>
</div> </div>
</ScrollReveal> </ScrollReveal>
@@ -331,13 +212,12 @@ export default async function AboutPage({ params }: Props) {
<div className="container mx-auto px-6"> <div className="container mx-auto px-6">
<ScrollReveal variant="fadeUp" className="flex flex-col items-center text-center gap-4 mb-16"> <ScrollReveal variant="fadeUp" className="flex flex-col items-center text-center gap-4 mb-16">
<span className="label-md text-primary">Our Beliefs</span> <span className="label-md text-primary">{t('pillars.eyebrow')}</span>
<h2 className="font-serif font-semibold text-on-surface text-4xl md:text-5xl leading-[1.1] tracking-[-0.02em] max-w-2xl"> <h2 className="font-serif font-semibold text-on-surface text-4xl md:text-5xl leading-[1.1] tracking-[-0.02em] max-w-2xl">
What We Believe {t('pillars.title')}
</h2> </h2>
<p className="text-outline text-lg leading-relaxed max-w-xl mt-1"> <p className="text-outline text-lg leading-relaxed max-w-xl mt-1">
Three principles that inform every decision we make, every line of code we write, and {t('pillars.subtitle')}
every client relationship we enter.
</p> </p>
</ScrollReveal> </ScrollReveal>
@@ -367,12 +247,11 @@ export default async function AboutPage({ params }: Props) {
/> />
<blockquote className="font-serif italic text-white text-3xl md:text-[2.25rem] leading-[1.3] tracking-[-0.02em]"> <blockquote className="font-serif italic text-white text-3xl md:text-[2.25rem] leading-[1.3] tracking-[-0.02em]">
&ldquo;Our mission is to bring the precision of architecture to the fluidity of the "{t('quote.text')}"
web.&rdquo;
</blockquote> </blockquote>
<p className="label-md text-white/40"> <p className="label-md text-white/40">
&mdash; LetsBe. founding philosophy &mdash; {t('quote.attrib')}
</p> </p>
</div> </div>
@@ -387,26 +266,25 @@ export default async function AboutPage({ params }: Props) {
<div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-8"> <div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-8">
<div className="flex flex-col gap-3 items-center"> <div className="flex flex-col gap-3 items-center">
<span className="label-md text-primary">Work With Us</span> <span className="label-md text-primary">{t('cta.eyebrow')}</span>
<h2 className="font-serif font-semibold text-on-surface text-3xl md:text-4xl leading-[1.1] tracking-[-0.02em]"> <h2 className="font-serif font-semibold text-on-surface text-3xl md:text-4xl leading-[1.1] tracking-[-0.02em]">
Let&rsquo;s build something together. {t('cta.title')}
</h2> </h2>
<p className="text-outline text-lg leading-relaxed max-w-lg"> <p className="text-outline text-lg leading-relaxed max-w-lg">
Whether you have a clear brief or an early-stage idea, we would be glad to talk {t('cta.subtitle')}
through what is possible.
</p> </p>
</div> </div>
<div className="flex flex-col sm:flex-row items-center gap-4"> <div className="flex flex-col sm:flex-row items-center gap-4">
<Button variant="primary" size="lg" arrow href="/#configure"> <Button variant="primary" size="lg" arrow href="/#configure">
Start your project {t('cta.primary')}
</Button> </Button>
<Button <Button
variant="secondary" variant="secondary"
size="lg" size="lg"
href="mailto:hello@letsbe.biz" href="mailto:hello@letsbe.biz"
> >
Book a call {t('cta.secondary')}
</Button> </Button>
</div> </div>

View File

@@ -1,28 +1,85 @@
import type { Metadata } from 'next' import type { Metadata } from 'next'
import Script from 'next/script' import Script from 'next/script'
import { NextIntlClientProvider } from 'next-intl' import { NextIntlClientProvider } from 'next-intl'
import { getMessages, setRequestLocale } from 'next-intl/server' import { getMessages, getTranslations, setRequestLocale } from 'next-intl/server'
import { notFound } from 'next/navigation' import { notFound } from 'next/navigation'
import { routing } from '@/i18n/routing' import { routing } from '@/i18n/routing'
import Nav from '@/components/layout/Nav' import Nav from '@/components/layout/Nav'
import Footer from '@/components/layout/Footer' import Footer from '@/components/layout/Footer'
import GoogleAnalytics from '@/components/analytics/GoogleAnalytics'
import CookieConsent from '@/components/analytics/CookieConsent'
import '@/styles/globals.css' import '@/styles/globals.css'
export const metadata: Metadata = { const BASE_URL = 'https://letsbe.biz'
title: 'LetsBe. | Bespoke Digital Studio & AI Infrastructure',
description:
'Bespoke digital ecosystems, private infrastructure, and AI automation for ambitious businesses on the Côte d\'Azur.',
}
type Props = { type Props = {
children: React.ReactNode children: React.ReactNode
params: Promise<{ locale: string }> params: Promise<{ locale: string }>
} }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params
const t = await getTranslations({ locale, namespace: 'meta' })
const ogLocaleMap: Record<string, string> = { en: 'en_US', fr: 'fr_FR', it: 'it_IT', es: 'es_ES' }
const currentOgLocale = ogLocaleMap[locale] ?? 'en_US'
const otherOgLocales = Object.values(ogLocaleMap).filter((l) => l !== currentOgLocale)
return {
metadataBase: new URL(BASE_URL),
title: {
default: t('home.title'),
template: '%s',
},
description: t('home.description'),
openGraph: {
type: 'website',
siteName: t('siteName'),
locale: currentOgLocale,
images: [{ url: '/images/og-default.png', width: 1200, height: 630 }],
},
other: {
'og:locale:alternate': otherOgLocales,
},
twitter: {
card: 'summary_large_image',
},
robots: {
index: true,
follow: true,
},
}
}
export function generateStaticParams() { export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale })) return routing.locales.map((locale) => ({ locale }))
} }
// ─── JSON-LD: Organization ───────────────────────────────────────────────────
const organizationJsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'LetsBe.',
url: BASE_URL,
logo: `${BASE_URL}/images/letsbe-logo-short.png`,
sameAs: [
'https://www.linkedin.com/company/letsbe-digital',
'https://x.com/letsbe_digital',
],
contactPoint: {
'@type': 'ContactPoint',
email: 'hello@letsbe.biz',
contactType: 'customer service',
},
availableLanguage: [
{ '@type': 'Language', name: 'English', alternateName: 'en' },
{ '@type': 'Language', name: 'French', alternateName: 'fr' },
{ '@type': 'Language', name: 'Italian', alternateName: 'it' },
{ '@type': 'Language', name: 'Spanish', alternateName: 'es' },
],
}
export default async function LocaleLayout({ children, params }: Props) { export default async function LocaleLayout({ children, params }: Props) {
const { locale } = await params const { locale } = await params
@@ -38,6 +95,10 @@ export default async function LocaleLayout({ children, params }: Props) {
<head> <head>
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationJsonLd) }}
/>
{process.env.NODE_ENV === 'development' && ( {process.env.NODE_ENV === 'development' && (
<Script <Script
src="//unpkg.com/react-grab/dist/index.global.js" src="//unpkg.com/react-grab/dist/index.global.js"
@@ -47,10 +108,12 @@ export default async function LocaleLayout({ children, params }: Props) {
)} )}
</head> </head>
<body className="font-sans text-on-surface bg-surface antialiased"> <body className="font-sans text-on-surface bg-surface antialiased">
<GoogleAnalytics />
<NextIntlClientProvider messages={messages}> <NextIntlClientProvider messages={messages}>
<Nav /> <Nav />
{children} {children}
<Footer /> <Footer />
<CookieConsent />
</NextIntlClientProvider> </NextIntlClientProvider>
</body> </body>
</html> </html>

View File

@@ -1,4 +1,5 @@
import { setRequestLocale } from 'next-intl/server' import type { Metadata } from 'next'
import { getTranslations, setRequestLocale } from 'next-intl/server'
import Hero from '@/components/sections/Hero' import Hero from '@/components/sections/Hero'
import TrustBar from '@/components/sections/TrustBar' import TrustBar from '@/components/sections/TrustBar'
import ServicesOverview from '@/components/sections/ServicesOverview' import ServicesOverview from '@/components/sections/ServicesOverview'
@@ -9,16 +10,52 @@ import Configurator from '@/components/sections/Configurator'
import Discovery from '@/components/sections/Discovery' import Discovery from '@/components/sections/Discovery'
import CTABanner from '@/components/sections/CTABanner' import CTABanner from '@/components/sections/CTABanner'
const BASE_URL = 'https://letsbe.biz'
type Props = { type Props = {
params: Promise<{ locale: string }> params: Promise<{ locale: string }>
} }
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params
const t = await getTranslations({ locale, namespace: 'meta.home' })
const path = locale === 'en' ? '' : `/${locale}`
return {
title: t('title'),
description: t('description'),
alternates: {
canonical: `${BASE_URL}${path}`,
languages: {
'en': BASE_URL,
'fr': `${BASE_URL}/fr`,
'it': `${BASE_URL}/it`,
'es': `${BASE_URL}/es`,
'x-default': BASE_URL,
},
},
}
}
export default async function HomePage({ params }: Props) { export default async function HomePage({ params }: Props) {
const { locale } = await params const { locale } = await params
setRequestLocale(locale) setRequestLocale(locale)
const websiteJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'LetsBe.',
url: BASE_URL,
inLanguage: locale,
}
return ( return (
<main> <main>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteJsonLd) }}
/>
<Hero /> <Hero />
<TrustBar /> <TrustBar />
<ServicesOverview /> <ServicesOverview />

View File

@@ -1,148 +1,40 @@
import { setRequestLocale } from 'next-intl/server';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import { getTranslations, setRequestLocale } from 'next-intl/server';
import ServicesHero from '@/components/sections/services/ServicesHero'; import ServicesHero from '@/components/sections/services/ServicesHero';
import ServicePillar from '@/components/sections/services/ServicePillar'; import ServicePillar from '@/components/sections/services/ServicePillar';
import AILayer from '@/components/sections/services/AILayer'; import AILayer from '@/components/sections/services/AILayer';
import ServicesCTA from '@/components/sections/services/ServicesCTA'; import ServicesCTA from '@/components/sections/services/ServicesCTA';
// Icon names passed as strings — resolved in client component // Icon names passed as strings — resolved in client component
const BASE_URL = 'https://letsbe.biz';
// ─── Metadata ───────────────────────────────────────────────────────────────── // ─── Metadata ─────────────────────────────────────────────────────────────────
export const metadata: Metadata = { type PageProps = {
title: 'Services | LetsBe. — Bespoke Digital Studio', params: Promise<{ locale: string }>;
description:
'From bespoke web design to private infrastructure and AI automation — three pillars of digital excellence, engineered for ambitious businesses.',
}; };
// ─── Service data ────────────────────────────────────────────────────────────── export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'meta.services' });
export const SERVICE_PILLARS = [ const path = locale === 'en' ? '/services' : `/${locale}/services`;
{
id: 'design-development',
numeral: '01',
title: 'Web Design & Development',
description:
'Your digital presence is not a template waiting to be filled — it is an engineered expression of your brand. We design and build bespoke websites and web applications from a blank canvas, crafting every interaction, every transition, and every responsive breakpoint with intention. Our work is fast by architecture, not by accident: semantic markup, optimised asset pipelines, and edge-deployed rendering that scores at the top of the Core Web Vitals chart. Whether you need a high-conversion marketing site, a complex SaaS application, or a multi-region e-commerce platform, we deliver a digital product that is built to last and built to grow.',
background: 'bg-surface' as const,
features: [
{
icon: 'Palette',
title: 'Bespoke UI/UX Design',
description:
'Custom Figma-to-code workflows. Every layout, component, and motion decision serves your brand — never a theme, never a shortcut.',
},
{
icon: 'Globe',
title: 'Modern Web Applications',
description:
'React, Next.js, and edge-deployed architecture for SPAs, SSR, and full-stack applications that scale without compromise.',
},
{
icon: 'ShoppingCart',
title: 'E-commerce & Platforms',
description:
'Headless storefronts, custom checkout flows, and multi-currency platforms engineered for high-volume retail.',
},
{
icon: 'Zap',
title: 'Performance Optimisation',
description:
'LCP under one second, zero layout shift. We audit, refactor, and rebuild performance into the foundation of your product.',
},
],
},
{
id: 'custom-systems',
numeral: '02',
title: 'Custom Systems',
description:
'Off-the-shelf software makes assumptions about your business. We don\'t. When your operations outgrow spreadsheets and generic SaaS platforms, we build the exact system your team needs — with the data model, the permission structure, and the workflow logic that reflects how you actually work. From CRM platforms tailored to your sales cycle, to internal management tools that replace three different subscriptions, to API architecture that connects your existing stack into a coherent whole — every system we build is owned by you, documented in full, and maintained without vendor dependency.',
background: 'bg-surface-low' as const,
features: [
{
icon: 'Database',
title: 'CRM & Management',
description:
'Purpose-built relationship and pipeline management with the fields, views, and automation rules your team will actually use.',
},
{
icon: 'Code2',
title: 'Bespoke Software',
description:
'Full-stack business applications: from quoting and booking platforms to complex multi-tenant SaaS products.',
},
{
icon: 'GitBranch',
title: 'API Architecture',
description:
'RESTful and GraphQL APIs, webhook integrations, and the middleware layer that makes your disparate tools speak the same language.',
},
{
icon: 'Wrench',
title: 'Internal Tooling',
description:
'Admin dashboards, reporting portals, and workflow automation that give your team unfair operational advantages.',
},
],
},
{
id: 'infrastructure',
numeral: '03',
title: 'Digital Infrastructure',
description:
'Data sovereignty is not a feature — it is a right. We provision and manage private cloud infrastructure that removes your reliance on opaque hyperscalers and shared-hosting providers. Your data lives where you say it lives, on servers you control, with access policies your legal team can actually review. We handle the full infrastructure lifecycle: dedicated server provisioning, containerised deployments with Docker and Kubernetes, automated backup strategies, TLS certificate management, and 24/7 uptime monitoring. When the European data-residency audit arrives, you will be the only business in the room with a clean answer.',
background: 'bg-surface' as const,
features: [
{
icon: 'Server',
title: 'Dedicated Hosting',
description:
'Private VPS and bare-metal environments in EU data centres — no shared neighbours, no noisy-neighbour risk.',
},
{
icon: 'Shield',
title: 'Data Sovereignty',
description:
'GDPR-aligned architecture with data-residency guarantees, audit trails, and full client ownership of storage and credentials.',
},
{
icon: 'Lock',
title: 'Security Hardening',
description:
'WAF configuration, DDoS mitigation, secrets management, and penetration-testing-ready hardened deployment pipelines.',
},
{
icon: 'Settings',
title: 'DevOps & Maintenance',
description:
'CI/CD pipelines, container orchestration, rolling deployments, and proactive monitoring so your team ships without fear.',
},
],
},
] as const;
// ─── AI Layer data ───────────────────────────────────────────────────────────── return {
title: t('title'),
export const AI_CAPABILITIES = [ description: t('description'),
{ alternates: {
id: 'ai-teammate', canonical: `${BASE_URL}${path}`,
title: 'AI Teammate', languages: {
description: 'en': `${BASE_URL}/services`,
'An operational assistant embedded directly into your workflow. Retrieves and summarises emails, drafts responses, executes tasks across connected tools, and surfaces the information your team needs before they know they need it.', 'fr': `${BASE_URL}/fr/services`,
}, 'it': `${BASE_URL}/it/services`,
{ 'es': `${BASE_URL}/es/services`,
id: 'customer-facing-ai', 'x-default': `${BASE_URL}/services`,
title: 'Customer-Facing AI', },
description: },
'Intelligent conversational interfaces that handle enquiries, qualify leads, make product recommendations, and personalise the user journey — at scale, around the clock, without extra headcount.', };
}, }
{
id: 'data-intelligence',
title: 'Data Intelligence',
description:
'Automated analytics pipelines, predictive modelling, and scheduled reporting that transform the data your systems collect into decisions your leadership team can act on.',
},
] as const;
// ─── Page ────────────────────────────────────────────────────────────────────── // ─── Page ──────────────────────────────────────────────────────────────────────
@@ -154,19 +46,37 @@ export default async function ServicesPage({ params }: Props) {
const { locale } = await params; const { locale } = await params;
setRequestLocale(locale); setRequestLocale(locale);
const t = await getTranslations({ locale, namespace: 'servicesPage' })
const backgrounds = ['bg-surface', 'bg-surface-low', 'bg-surface'] as const
const pillars = [0, 1, 2].map((i) => ({
id: t(`pillars.${i}.id`),
numeral: t(`pillars.${i}.numeral`),
title: t(`pillars.${i}.title`),
description: t(`pillars.${i}.description`),
background: backgrounds[i],
features: [0, 1, 2, 3].map((j) => ({
icon: t(`pillars.${i}.features.${j}.icon`),
title: t(`pillars.${i}.features.${j}.title`),
description: t(`pillars.${i}.features.${j}.description`),
})),
}))
const aiCapabilities = [0, 1, 2].map((i) => ({
id: t(`ai.capabilities.${i}.id`),
title: t(`ai.capabilities.${i}.title`),
description: t(`ai.capabilities.${i}.description`),
}))
return ( return (
<main> <main>
<ServicesHero /> <ServicesHero />
{SERVICE_PILLARS.map((pillar, index) => ( {pillars.map((pillar, index) => (
<ServicePillar <ServicePillar key={pillar.id} pillar={pillar} index={index} />
key={pillar.id}
pillar={pillar}
index={index}
/>
))} ))}
<AILayer capabilities={AI_CAPABILITIES} /> <AILayer capabilities={aiCapabilities} />
<ServicesCTA /> <ServicesCTA />
</main> </main>

View File

@@ -1,69 +1,83 @@
import Image from 'next/image';
import type { Metadata } from 'next';
import { notFound } from 'next/navigation'; import { notFound } from 'next/navigation';
import { setRequestLocale } from 'next-intl/server'; import { getTranslations, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing'; import { routing } from '@/i18n/routing';
import ScrollReveal from '@/components/ui/ScrollReveal'; import ScrollReveal from '@/components/ui/ScrollReveal';
import Button from '@/components/ui/Button'; import Button from '@/components/ui/Button';
import CornerBracket from '@/components/icons/CornerBracket'; import CornerBracket from '@/components/icons/CornerBracket';
import Chip from '@/components/ui/Chip';
const BASE_URL = 'https://letsbe.biz';
// ─── Types ──────────────────────────────────────────────────────────────────── // ─── Types ────────────────────────────────────────────────────────────────────
interface Project { interface Project {
title: string; image: string;
subtitle: string;
description: string;
challenge: string;
approach: string;
outcome: string;
techStack: string[]; techStack: string[];
tags: string[]; }
// ─── Slug-to-work-key mapping ─────────────────────────────────────────────────
const SLUG_TO_KEY: Record<string, string> = {
'monaco-ocean': 'monaco',
'port-nimara': 'portNimara',
'port-amador': 'portAmador',
} }
// ─── Data (will come from Payload CMS) ──────────────────────────────────────── // ─── Data (will come from Payload CMS) ────────────────────────────────────────
const PROJECTS: Record<string, Project> = { const PROJECTS: Record<string, Project> = {
'monaco-ocean': { 'monaco-ocean': {
title: 'Monaco Ocean Protection Challenge', image: '/images/monaco_high_res.jpg',
subtitle: 'AI-Powered Judging & Analytics Platform',
description:
"A comprehensive judging and analytics system with advanced AI jury integration for one of the Mediterranean's most prestigious conservation events.",
challenge:
'The Monaco Ocean Protection Challenge needed a modern platform to manage submissions, coordinate judges across time zones, and provide AI-assisted evaluation of conservation proposals — all while maintaining the prestige and security expected of a Monaco institution.',
approach:
'We built a custom platform from the ground up using Next.js and a private PostgreSQL infrastructure. The AI jury module uses natural language processing to pre-screen submissions and generate summary reports, while human judges retain full control over final decisions.',
outcome:
"The platform processed over 200 submissions in its first season, reducing judge workload by 40% through AI-assisted pre-screening. The client praised the system's reliability and the elegance of its interface.",
techStack: ['Next.js', 'PostgreSQL', 'OpenAI API', 'Docker', 'Private Cloud'], techStack: ['Next.js', 'PostgreSQL', 'OpenAI API', 'Docker', 'Private Cloud'],
tags: ['AI Integration', 'Platform'],
}, },
'port-nimara': { 'port-nimara': {
title: 'Port Nimara', image: '/images/anguilla.png',
subtitle: 'Maritime Digital Hub',
description: 'Scalable digital hub for maritime logistics.',
challenge:
'Port Nimara needed a modern digital presence that could serve as both a marketing website and an operational hub for berth inquiries, event management, and partner communications.',
approach:
'We designed and developed a performant Nuxt.js application with a headless CMS for content management, integrated with their existing maritime scheduling systems via custom API middleware.',
outcome:
'The new platform increased online berth inquiries by 3x and provided the port authority with real-time content management capabilities they previously lacked.',
techStack: ['Nuxt.js', 'Directus CMS', 'Node.js', 'Docker'], techStack: ['Nuxt.js', 'Directus CMS', 'Node.js', 'Docker'],
tags: ['Website', 'Infrastructure'],
}, },
'port-amador': { 'port-amador': {
title: 'Port Amador', image: '/images/panama.png',
subtitle: 'Premium Nautical Experience',
description: 'Premium digital experience for elite nautical services.',
challenge:
'Port Amador required a luxury-grade digital experience that matched the exclusivity of their nautical services, with multi-language support and seamless booking integration.',
approach:
'We crafted a bespoke website with cinematic imagery, smooth animations, and an integrated booking flow. The site was built on modern web technologies with a focus on performance and SEO for the competitive luxury maritime market.',
outcome:
"The redesigned platform elevated Port Amador's digital presence to match their premium positioning, with a 60% improvement in page load times and significantly increased organic traffic.",
techStack: ['Next.js', 'Tailwind CSS', 'Framer Motion', 'Vercel'], techStack: ['Next.js', 'Tailwind CSS', 'Framer Motion', 'Vercel'],
tags: ['Website', 'Infrastructure'],
}, },
}; };
// ─── Metadata ─────────────────────────────────────────────────────────────────
type PageProps = {
params: Promise<{ locale: string; slug: string }>;
};
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const { locale, slug } = await params;
const project = PROJECTS[slug];
if (!project) return {};
const workKey = SLUG_TO_KEY[slug];
if (!workKey) return {};
const t = await getTranslations({ locale, namespace: 'meta.work' });
const path = locale === 'en' ? `/work/${slug}` : `/${locale}/work/${slug}`;
return {
title: t(`${slug}.title` as any),
description: t(`${slug}.description` as any),
openGraph: {
images: [{ url: project.image }],
},
alternates: {
canonical: `${BASE_URL}${path}`,
languages: {
'en': `${BASE_URL}/work/${slug}`,
'fr': `${BASE_URL}/fr/work/${slug}`,
'it': `${BASE_URL}/it/work/${slug}`,
'es': `${BASE_URL}/es/work/${slug}`,
'x-default': `${BASE_URL}/work/${slug}`,
},
},
};
}
// ─── Static Generation ──────────────────────────────────────────────────────── // ─── Static Generation ────────────────────────────────────────────────────────
export function generateStaticParams() { export function generateStaticParams() {
@@ -119,43 +133,91 @@ export default async function CaseStudyPage({ params }: Props) {
const project = PROJECTS[slug]; const project = PROJECTS[slug];
if (!project) notFound(); if (!project) notFound();
const workKey = SLUG_TO_KEY[slug];
if (!workKey) notFound();
const t = await getTranslations({ locale, namespace: 'caseStudy' });
const tw = await getTranslations({ locale, namespace: 'work' });
// Get translated content
const title = tw(`projects.${workKey}.title`)
const tags = tw.raw(`projects.${workKey}.tags`) as string[]
const subtitle = t(`projects.${slug}.subtitle`)
const description = t(`projects.${slug}.description`)
const challenge = t(`projects.${slug}.challenge`)
const approach = t(`projects.${slug}.approach`)
const outcome = t(`projects.${slug}.outcome`)
const caseStudyJsonLd = {
'@context': 'https://schema.org',
'@type': 'CreativeWork',
name: title,
description: description,
image: `${BASE_URL}${project.image}`,
inLanguage: locale,
creator: {
'@type': 'Organization',
name: 'LetsBe.',
url: BASE_URL,
},
};
return ( return (
<main> <main>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(caseStudyJsonLd) }}
/>
{/* ── Hero ── */} {/* ── Hero ── */}
<section className="bg-surface-low py-24"> <section className="relative min-h-[420px] md:min-h-[480px] flex items-end overflow-hidden">
<div className="container mx-auto px-6"> {/* Background image */}
<div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-6"> <Image
src={project.image}
alt=""
fill
className="object-cover"
sizes="100vw"
priority
/>
{/* Dark overlay for text readability */}
<div className="absolute inset-0 bg-gradient-to-t from-[rgba(25,28,29,0.85)] via-[rgba(25,28,29,0.55)] to-[rgba(25,28,29,0.3)]" />
<div className="relative z-10 container mx-auto px-6 pb-16 pt-32">
<div className="max-w-3xl mx-auto flex flex-col items-center text-center gap-5">
{/* Tags */} {/* Tags */}
<ScrollReveal variant="fadeIn"> <ScrollReveal variant="fadeIn">
<div className="flex flex-wrap items-center justify-center gap-2"> <div className="flex flex-wrap items-center justify-center gap-2">
{project.tags.map((tag) => ( {tags.map((tag) => (
<Chip key={tag} size="md"> <span
key={tag}
className="inline-flex items-center bg-white/15 backdrop-blur-sm text-white/90 text-[0.75rem] font-semibold px-3 py-1 rounded-full leading-none tracking-wide"
>
{tag} {tag}
</Chip> </span>
))} ))}
</div> </div>
</ScrollReveal> </ScrollReveal>
{/* Title */} {/* Title */}
<ScrollReveal variant="fadeUp" delay={0.08}> <ScrollReveal variant="fadeUp" delay={0.08}>
<h1 className="font-serif font-semibold text-on-surface text-4xl md:text-5xl lg:text-[3.25rem] leading-[1.1] tracking-[-0.02em]"> <h1 className="font-serif font-semibold text-white text-4xl md:text-5xl lg:text-[3.25rem] leading-[1.1] tracking-[-0.02em]">
{project.title} {title}
</h1> </h1>
</ScrollReveal> </ScrollReveal>
{/* Subtitle */} {/* Subtitle */}
<ScrollReveal variant="fadeUp" delay={0.16}> <ScrollReveal variant="fadeUp" delay={0.16}>
<p className="label-md text-primary tracking-widest"> <p className="label-md text-white/70 tracking-widest">
{project.subtitle} {subtitle}
</p> </p>
</ScrollReveal> </ScrollReveal>
{/* Description */} {/* Description */}
<ScrollReveal variant="fadeUp" delay={0.22}> <ScrollReveal variant="fadeUp" delay={0.22}>
<p className="text-outline text-lg leading-relaxed max-w-2xl"> <p className="text-white/80 text-lg leading-relaxed max-w-2xl">
{project.description} {description}
</p> </p>
</ScrollReveal> </ScrollReveal>
@@ -182,10 +244,10 @@ export default async function CaseStudyPage({ params }: Props) {
<div className="flex flex-col gap-16 md:gap-20"> <div className="flex flex-col gap-16 md:gap-20">
<ContentSection <ContentSection
label="The Challenge" label={t('labels.challenge')}
index="01" index="01"
heading="The problem we set out to solve" heading={t('labels.challengeHeading')}
body={project.challenge} body={challenge}
/> />
{/* Divider */} {/* Divider */}
@@ -201,10 +263,10 @@ export default async function CaseStudyPage({ params }: Props) {
</ScrollReveal> </ScrollReveal>
<ContentSection <ContentSection
label="Our Approach" label={t('labels.approach')}
index="02" index="02"
heading="How we thought about it" heading={t('labels.approachHeading')}
body={project.approach} body={approach}
/> />
{/* Divider */} {/* Divider */}
@@ -220,10 +282,10 @@ export default async function CaseStudyPage({ params }: Props) {
</ScrollReveal> </ScrollReveal>
<ContentSection <ContentSection
label="The Outcome" label={t('labels.outcome')}
index="03" index="03"
heading="What we delivered" heading={t('labels.outcomeHeading')}
body={project.outcome} body={outcome}
/> />
</div> </div>
@@ -237,7 +299,7 @@ export default async function CaseStudyPage({ params }: Props) {
<div className="container mx-auto px-6"> <div className="container mx-auto px-6">
<div className="max-w-3xl mx-auto"> <div className="max-w-3xl mx-auto">
<ScrollReveal variant="fadeUp" className="flex flex-col gap-5"> <ScrollReveal variant="fadeUp" className="flex flex-col gap-5">
<p className="label-md text-outline">Built with</p> <p className="label-md text-outline">{t('labels.builtWith')}</p>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{project.techStack.map((tech) => ( {project.techStack.map((tech) => (
<span <span
@@ -267,20 +329,19 @@ export default async function CaseStudyPage({ params }: Props) {
<div className="absolute -top-3 -right-3" aria-hidden="true"> <div className="absolute -top-3 -right-3" aria-hidden="true">
<CornerBracket size={24} position="top-right" color="var(--color-teal)" /> <CornerBracket size={24} position="top-right" color="var(--color-teal)" />
</div> </div>
<p className="label-md text-primary px-4">Next Step</p> <p className="label-md text-primary px-4">{t('labels.yourTurn')}</p>
</div> </div>
<h2 className="font-serif font-semibold text-on-surface text-3xl md:text-4xl leading-[1.1] tracking-[-0.02em]"> <h2 className="font-serif font-semibold text-on-surface text-3xl md:text-4xl leading-[1.1] tracking-[-0.02em]">
Ready to build your own landmark? {t('labels.ctaTitle')}
</h2> </h2>
<p className="text-outline text-lg leading-relaxed max-w-xl"> <p className="text-outline text-lg leading-relaxed max-w-xl">
Every project we take on is a collaboration built on trust, precision, and a shared {t('labels.ctaSubtitle')}
belief that great digital work is never accidental.
</p> </p>
<Button variant="primary" size="lg" arrow href="/#configure"> <Button variant="primary" size="lg" arrow href="/#configure">
Start your project {t('labels.ctaButton')}
</Button> </Button>
</div> </div>

View File

@@ -156,9 +156,12 @@ When site analysis data is provided in the context, you MUST include a dedicated
- Explain how the proposed solution addresses each issue found - Explain how the proposed solution addresses each issue found
This section demonstrates that LetsBe has already begun analyzing the client's situation before the first call. Never invent data not present in the context — only reference what the analysis actually returned.`; This section demonstrates that LetsBe has already begun analyzing the client's situation before the first call. Never invent data not present in the context — only reference what the analysis actually returned.`;
const langInstruction = body.locale === 'fr' const langInstructions: Record<string, string> = {
? '\n\nIMPORTANT: Write the entire brief in French. All headings, body text, and next steps must be in French.' fr: '\n\nIMPORTANT: Write the entire brief in French. All headings, body text, and next steps must be in French.',
: ''; it: '\n\nIMPORTANT: Write the entire brief in Italian. All headings, body text, and next steps must be in Italian.',
es: '\n\nIMPORTANT: Write the entire brief in Spanish. All headings, body text, and next steps must be in Spanish.',
};
const langInstruction = langInstructions[body.locale ?? ''] ?? '';
const userPrompt = `Generate a personalized project brief for the following prospect. The brief should: const userPrompt = `Generate a personalized project brief for the following prospect. The brief should:
1. Address the client by first name (${displayName}) 1. Address the client by first name (${displayName})
@@ -221,7 +224,7 @@ ${context}`;
function generateFallbackBrief(body: ConfigureRequestBody): string { function generateFallbackBrief(body: ConfigureRequestBody): string {
const { services, aiEnabled, aiTypes, industry, scope, timeline, name, company } = body; const { services, aiEnabled, aiTypes, industry, scope, timeline, name, company } = body;
const isFr = body.locale === 'fr'; const locale = body.locale ?? 'en';
const SERVICE_NAMES_FR: Record<string, string> = { const SERVICE_NAMES_FR: Record<string, string> = {
web: 'Design & Développement Web', web: 'Design & Développement Web',
@@ -246,70 +249,170 @@ function generateFallbackBrief(body: ConfigureRequestBody): string {
exploring: 'en phase d\'exploration', exploring: 'en phase d\'exploration',
}; };
const svcNames = isFr ? SERVICE_NAMES_FR : SERVICE_NAMES; const SERVICE_NAMES_IT: Record<string, string> = {
const indNames = isFr ? INDUSTRY_NAMES_FR : INDUSTRY_NAMES; web: 'Web Design & Sviluppo',
const tlNames = isFr ? TIMELINE_NAMES_FR : TIMELINE_NAMES; systems: 'Software Su Misura',
infrastructure: 'Infrastruttura Privata',
};
const INDUSTRY_NAMES_IT: Record<string, string> = {
maritime: 'Marittimo & Nautica', hospitality: 'Ospitalità', technology: 'Tecnologia',
realestate: 'Immobiliare', finance: 'Finanza', ngo: 'ONG & No-Profit', other: 'Altro',
};
const TIMELINE_NAMES_IT: Record<string, string> = {
asap: 'il prima possibile', '1-3months': '13 mesi', '3-6months': '36 mesi', exploring: 'in fase di esplorazione',
};
const SERVICE_NAMES_ES: Record<string, string> = {
web: 'Diseño & Desarrollo Web',
systems: 'Software a Medida',
infrastructure: 'Infraestructura Privada',
};
const INDUSTRY_NAMES_ES: Record<string, string> = {
maritime: 'Marítimo & Náutico', hospitality: 'Hostelería', technology: 'Tecnología',
realestate: 'Inmobiliario', finance: 'Finanzas', ngo: 'ONG & Sin Ánimo de Lucro', other: 'Otro',
};
const TIMELINE_NAMES_ES: Record<string, string> = {
asap: 'lo antes posible', '1-3months': '13 meses', '3-6months': '36 meses', exploring: 'en fase de exploración',
};
const svcMap: Record<string, Record<string, string>> = { fr: SERVICE_NAMES_FR, it: SERVICE_NAMES_IT, es: SERVICE_NAMES_ES };
const indMap: Record<string, Record<string, string>> = { fr: INDUSTRY_NAMES_FR, it: INDUSTRY_NAMES_IT, es: INDUSTRY_NAMES_ES };
const tlMap: Record<string, Record<string, string>> = { fr: TIMELINE_NAMES_FR, it: TIMELINE_NAMES_IT, es: TIMELINE_NAMES_ES };
const svcNames = svcMap[locale] ?? SERVICE_NAMES;
const indNames = indMap[locale] ?? INDUSTRY_NAMES;
const tlNames = tlMap[locale] ?? TIMELINE_NAMES;
const serviceNames = services.map((s) => svcNames[s] ?? s); const serviceNames = services.map((s) => svcNames[s] ?? s);
const joiner = isFr ? ' et ' : ' and ';
const servicesList = serviceNames.length <= 2
? serviceNames.join(joiner)
: `${serviceNames.slice(0, -1).join(', ')}${isFr ? ' et ' : ', and '}${serviceNames[serviceNames.length - 1]}`;
const industryLabel = industry ? indNames[industry] ?? industry : (isFr ? 'votre secteur' : 'your industry');
const displayCompany = company.trim() || (isFr ? 'votre organisation' : 'your organization');
const displayName = name.split(' ')[0] || (isFr ? 'bonjour' : 'there');
const joiners: Record<string, { and: string; commaAnd: string }> = {
fr: { and: ' et ', commaAnd: ' et ' },
it: { and: ' e ', commaAnd: ' e ' },
es: { and: ' y ', commaAnd: ' y ' },
};
const j = joiners[locale] ?? { and: ' and ', commaAnd: ', and ' };
const servicesList = serviceNames.length <= 2
? serviceNames.join(j.and)
: `${serviceNames.slice(0, -1).join(', ')}${j.commaAnd}${serviceNames[serviceNames.length - 1]}`;
const industryFallbacks: Record<string, string> = { fr: 'votre secteur', it: 'il tuo settore', es: 'tu sector' };
const companyFallbacks: Record<string, string> = { fr: 'votre organisation', it: 'la tua organizzazione', es: 'tu organización' };
const nameFallbacks: Record<string, string> = { fr: 'bonjour', it: 'ciao', es: 'hola' };
const industryLabel = industry ? indNames[industry] ?? industry : (industryFallbacks[locale] ?? 'your industry');
const displayCompany = company.trim() || (companyFallbacks[locale] ?? 'your organization');
const displayName = name.split(' ')[0] || (nameFallbacks[locale] ?? 'there');
const timelineFallbacks: Record<string, string> = {
fr: 'un calendrier à convenir', it: 'un calendario da definire', es: 'un calendario a convenir',
};
const timelineStr = timeline const timelineStr = timeline
? tlNames[timeline]?.toLowerCase() ?? (isFr ? 'un calendrier à convenir' : 'a timeline to be agreed upon') ? tlNames[timeline]?.toLowerCase() ?? (timelineFallbacks[locale] ?? 'a timeline to be agreed upon')
: (isFr ? 'un calendrier à convenir' : 'a timeline to be agreed upon'); : (timelineFallbacks[locale] ?? 'a timeline to be agreed upon');
const hasWeb = services.includes('web'); const hasWeb = services.includes('web');
const hasSystems = services.includes('systems'); const hasSystems = services.includes('systems');
const hasInfra = services.includes('infrastructure'); const hasInfra = services.includes('infrastructure');
let sections = ''; // Build sections per locale
const sectionTemplates: Record<string, () => string> = {
fr: () => {
let s = '';
if (hasWeb) {
s += `\n**Design & Développement Web**\nNous concevrons et développerons un site web sur mesure pour ${displayCompany} — sans templates, sans constructeurs de pages. Moderne, responsive, rapide et optimisé pour le référencement dès le premier jour.\n`;
}
if (hasSystems) {
s += `\n**Logiciels Sur Mesure**\nNous développerons un système conçu pour correspondre exactement au fonctionnement de ${displayCompany} — modèle de données personnalisé, accès par rôles et intégrations avec vos outils existants.\n`;
}
if (hasInfra) {
s += `\n**Infrastructure Privée**\nNous mettrons en place un environnement serveur dédié pour ${displayCompany} avec email, stockage cloud et outils métier que vous possédez et contrôlez entièrement.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
s += `\n**Intégration IA**\nNous intégrerons ${aiLabels.toLowerCase()} dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`;
} else if (aiEnabled) {
s += `\n**Intégration IA**\nNous intégrerons l'IA dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`;
}
if (scope?.trim()) {
s += `\n**Vos Objectifs**\nVous avez partagé : "${scope.trim()}" — nous orienterons nos sessions de découverte autour de ces priorités.\n`;
}
return s;
},
it: () => {
let s = '';
if (hasWeb) {
s += `\n**Web Design & Sviluppo**\nProgetteremo e svilupperemo un sito web su misura per ${displayCompany} da zero — nessun template, nessun page builder. Moderno, responsive, veloce e ottimizzato per i motori di ricerca fin dal primo giorno.\n`;
}
if (hasSystems) {
s += `\n**Software Su Misura**\nRealizzaremo un sistema progettato su misura per come opera ${displayCompany} — modello dati personalizzato, accesso basato sui ruoli e integrazioni con i tuoi strumenti esistenti.\n`;
}
if (hasInfra) {
s += `\n**Infrastruttura Privata**\nConfigureremo un ambiente server dedicato per ${displayCompany} con email, cloud storage e strumenti aziendali che possiedi e controlli interamente.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
s += `\n**Integrazione IA**\nIntegreremo ${aiLabels.toLowerCase()} nei tuoi sistemi — in profondità, non in superficie. L'approccio esatto sarà definito durante la fase di scoperta.\n`;
} else if (aiEnabled) {
s += `\n**Integrazione IA**\nIntegreremo l'IA nei tuoi sistemi — in profondità, non in superficie. L'approccio esatto sarà definito durante la fase di scoperta.\n`;
}
if (scope?.trim()) {
s += `\n**I Tuoi Obiettivi**\nHai condiviso: "${scope.trim()}" — struttureremo le nostre sessioni di scoperta attorno a queste priorità.\n`;
}
return s;
},
es: () => {
let s = '';
if (hasWeb) {
s += `\n**Diseño & Desarrollo Web**\nDiseñaremos y desarrollaremos un sitio web a medida para ${displayCompany} desde cero — sin plantillas, sin constructores de páginas. Moderno, responsive, rápido y optimizado para motores de búsqueda desde el primer día.\n`;
}
if (hasSystems) {
s += `\n**Software a Medida**\nDesarrollaremos un sistema diseñado específicamente para cómo opera ${displayCompany} — modelo de datos personalizado, acceso basado en roles e integraciones con tus herramientas existentes.\n`;
}
if (hasInfra) {
s += `\n**Infraestructura Privada**\nConfiguraremos un entorno de servidor dedicado para ${displayCompany} con correo electrónico, almacenamiento en la nube y herramientas empresariales que posees y controlas completamente.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
s += `\n**Integración IA**\nIntegraremos ${aiLabels.toLowerCase()} en tus sistemas — de forma profunda, no superficial. El enfoque exacto se definirá durante la fase de descubrimiento.\n`;
} else if (aiEnabled) {
s += `\n**Integración IA**\nIntegraremos la IA en tus sistemas — de forma profunda, no superficial. El enfoque exacto se definirá durante la fase de descubrimiento.\n`;
}
if (scope?.trim()) {
s += `\n**Tus Objetivos**\nCompartiste: "${scope.trim()}" — orientaremos nuestras sesiones de descubrimiento en torno a estas prioridades.\n`;
}
return s;
},
en: () => {
let s = '';
if (hasWeb) {
s += `\n**Web Design & Development**\nWe'll design and build a custom website for ${displayCompany} from scratch — no templates, no page builders. Modern, responsive, fast, and optimized for search engines from day one.\n`;
}
if (hasSystems) {
s += `\n**Custom Software**\nWe'll build a purpose-made system tailored to how ${displayCompany} actually operates — custom data model, role-based access, and integrations with your existing tools.\n`;
}
if (hasInfra) {
s += `\n**Private Infrastructure**\nWe'll set up a dedicated server environment for ${displayCompany} with email, cloud storage, and business tools that you fully own and control.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
s += `\n**AI Integration**\nWe'll layer ${aiLabels.toLowerCase()} into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`;
} else if (aiEnabled) {
s += `\n**AI Integration**\nWe'll layer AI integration into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`;
}
if (scope?.trim()) {
s += `\n**Your Goals**\nYou shared: "${scope.trim()}" — we'll frame our discovery sessions around these priorities.\n`;
}
return s;
},
};
if (isFr) { const sections = (sectionTemplates[locale] ?? sectionTemplates['en'])();
if (hasWeb) {
sections += `\n**Design & Développement Web**\nNous concevrons et développerons un site web sur mesure pour ${displayCompany} — sans templates, sans constructeurs de pages. Moderne, responsive, rapide et optimisé pour le référencement dès le premier jour.\n`;
}
if (hasSystems) {
sections += `\n**Logiciels Sur Mesure**\nNous développerons un système conçu pour correspondre exactement au fonctionnement de ${displayCompany} — modèle de données personnalisé, accès par rôles et intégrations avec vos outils existants.\n`;
}
if (hasInfra) {
sections += `\n**Infrastructure Privée**\nNous mettrons en place un environnement serveur dédié pour ${displayCompany} avec email, stockage cloud et outils métier que vous possédez et contrôlez entièrement.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
sections += `\n**Intégration IA**\nNous intégrerons ${aiLabels.toLowerCase()} dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`;
} else if (aiEnabled) {
sections += `\n**Intégration IA**\nNous intégrerons l'IA dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`;
}
if (scope?.trim()) {
sections += `\n**Vos Objectifs**\nVous avez partagé : "${scope.trim()}" — nous orienterons nos sessions de découverte autour de ces priorités.\n`;
}
} else {
if (hasWeb) {
sections += `\n**Web Design & Development**\nWe'll design and build a custom website for ${displayCompany} from scratch — no templates, no page builders. Modern, responsive, fast, and optimized for search engines from day one.\n`;
}
if (hasSystems) {
sections += `\n**Custom Software**\nWe'll build a purpose-made system tailored to how ${displayCompany} actually operates — custom data model, role-based access, and integrations with your existing tools.\n`;
}
if (hasInfra) {
sections += `\n**Private Infrastructure**\nWe'll set up a dedicated server environment for ${displayCompany} with email, cloud storage, and business tools that you fully own and control.\n`;
}
if (aiEnabled && aiTypes.length > 0) {
const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ');
sections += `\n**AI Integration**\nWe'll layer ${aiLabels.toLowerCase()} into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`;
} else if (aiEnabled) {
sections += `\n**AI Integration**\nWe'll layer AI integration into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`;
}
if (scope?.trim()) {
sections += `\n**Your Goals**\nYou shared: "${scope.trim()}" — we'll frame our discovery sessions around these priorities.\n`;
}
}
if (isFr) { if (locale === 'fr') {
return `**Brief Projet pour ${displayCompany}** return `**Brief Projet pour ${displayCompany}**
Préparé pour : ${name} Préparé pour : ${name}
Date : ${new Date().toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' })} Date : ${new Date().toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' })}
@@ -341,6 +444,70 @@ Au plaisir de construire quelque chose de formidable ensemble.
— L'équipe LetsBe`; — L'équipe LetsBe`;
} }
if (locale === 'it') {
return `**Brief Progetto per ${displayCompany}**
Preparato per: ${name}
Data: ${new Date().toLocaleDateString('it-IT', { year: 'numeric', month: 'long', day: 'numeric' })}
---
**Panoramica**
Ciao ${displayName}, in base al tuo interesse per ${servicesList} nel settore ${industryLabel}, ecco un brief preliminare per guidare la nostra prima conversazione.
Affronteremo questo come un progetto unificato — ogni componente che lavora insieme, interamente di tua proprietà e sotto il tuo controllo.
${sections}
**Il Nostro Approccio**
Iniziamo con una fase di Scoperta (23 sessioni) per comprendere le tue esigenze prima di scrivere una sola riga di codice.
**Tempistiche**
Consegna prevista: ${timelineStr}. Una roadmap dettagliata seguirà la fase di Scoperta.
**Prossimi Passi**
1. Prenota una chiamata introduttiva gratuita di 30 minuti
2. Ti invieremo un documento di scoping dettagliato entro 48 ore
3. La Scoperta inizia — senza impegno
Non vediamo l'ora di costruire qualcosa di straordinario insieme.
— Il Team LetsBe`;
}
if (locale === 'es') {
return `**Brief de Proyecto para ${displayCompany}**
Preparado para: ${name}
Fecha: ${new Date().toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' })}
---
**Resumen**
Hola ${displayName}, basándonos en tu interés en ${servicesList} para el sector ${industryLabel}, aquí tienes un brief preliminar para guiar nuestra primera conversación.
Abordaremos esto como un proyecto unificado — cada componente trabajando en conjunto, totalmente de tu propiedad y bajo tu control.
${sections}
**Nuestro Enfoque**
Comenzamos con una fase de Descubrimiento (23 sesiones) para comprender tus requisitos antes de escribir cualquier línea de código.
**Plazo**
Entrega objetivo: ${timelineStr}. Una hoja de ruta detallada seguirá a la fase de Descubrimiento.
**Próximos Pasos**
1. Reserva una llamada introductoria gratuita de 30 minutos
2. Te enviaremos un documento de alcance detallado en 48 horas
3. El Descubrimiento comienza — sin compromiso
Con ganas de construir algo extraordinario juntos.
— El Equipo LetsBe`;
}
return `**Project Brief for ${displayCompany}** return `**Project Brief for ${displayCompany}**
Prepared for: ${name} Prepared for: ${name}
Date: ${new Date().toLocaleDateString('en-GB', { year: 'numeric', month: 'long', day: 'numeric' })} Date: ${new Date().toLocaleDateString('en-GB', { year: 'numeric', month: 'long', day: 'numeric' })}

View File

@@ -35,7 +35,8 @@ export async function POST(request: NextRequest) {
rateLimitMap.set(ip, Date.now()); rateLimitMap.set(ip, Date.now());
const { locale } = (await request.json()) as { locale?: string }; const { locale } = (await request.json()) as { locale?: string };
const result = generateEphemeralToken(locale === 'fr' ? 'fr' : 'en'); const supportedLocales = ['en', 'fr', 'it', 'es'];
const result = generateEphemeralToken(supportedLocales.includes(locale ?? '') ? locale! : 'en');
return NextResponse.json({ return NextResponse.json({
success: true, success: true,

BIN
src/app/apple-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

14
src/app/robots.ts Normal file
View File

@@ -0,0 +1,14 @@
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/admin/', '/api/'],
},
],
sitemap: 'https://letsbe.biz/sitemap.xml',
}
}

44
src/app/sitemap.ts Normal file
View File

@@ -0,0 +1,44 @@
import type { MetadataRoute } from 'next'
const BASE_URL = 'https://letsbe.biz'
const STATIC_ROUTES = ['', '/about', '/services']
const PROJECT_SLUGS = ['monaco-ocean', 'port-nimara', 'port-amador']
export default function sitemap(): MetadataRoute.Sitemap {
const now = new Date()
const staticEntries: MetadataRoute.Sitemap = STATIC_ROUTES.map((route) => ({
url: `${BASE_URL}${route}`,
lastModified: now,
changeFrequency: route === '' ? 'weekly' : 'monthly',
priority: route === '' ? 1.0 : 0.8,
alternates: {
languages: {
en: `${BASE_URL}${route}`,
fr: `${BASE_URL}/fr${route}`,
it: `${BASE_URL}/it${route}`,
es: `${BASE_URL}/es${route}`,
'x-default': `${BASE_URL}${route}`,
},
},
}))
const projectEntries: MetadataRoute.Sitemap = PROJECT_SLUGS.map((slug) => ({
url: `${BASE_URL}/work/${slug}`,
lastModified: now,
changeFrequency: 'monthly' as const,
priority: 0.7,
alternates: {
languages: {
en: `${BASE_URL}/work/${slug}`,
fr: `${BASE_URL}/fr/work/${slug}`,
it: `${BASE_URL}/it/work/${slug}`,
es: `${BASE_URL}/es/work/${slug}`,
'x-default': `${BASE_URL}/work/${slug}`,
},
},
}))
return [...staticEntries, ...projectEntries]
}

View File

@@ -0,0 +1,82 @@
'use client'
import { useState, useEffect } from 'react'
const CONSENT_KEY = 'cookie_consent'
type ConsentState = 'granted' | 'denied'
function updateConsent(state: ConsentState) {
if (typeof window !== 'undefined' && typeof window.gtag === 'function') {
window.gtag('consent', 'update', {
analytics_storage: state,
ad_storage: state,
ad_user_data: state,
ad_personalization: state,
})
}
}
export default function CookieConsent() {
const [visible, setVisible] = useState(false)
useEffect(() => {
const stored = localStorage.getItem(CONSENT_KEY)
if (stored === 'granted' || stored === 'denied') {
// Restore previous choice
updateConsent(stored)
} else {
// No choice yet — show banner
setVisible(true)
}
}, [])
const handleAccept = () => {
localStorage.setItem(CONSENT_KEY, 'granted')
updateConsent('granted')
setVisible(false)
}
const handleDecline = () => {
localStorage.setItem(CONSENT_KEY, 'denied')
updateConsent('denied')
setVisible(false)
}
if (!visible) return null
return (
<div
role="dialog"
aria-label="Cookie consent"
style={{ animation: 'cookie-slide-up 0.5s ease-out' }}
className="fixed bottom-0 left-0 right-0 z-50 p-4 sm:p-6"
>
<div className="max-w-xl mx-auto rounded-2xl bg-surface-high border border-outline-variant/20 shadow-[0_-4px_32px_rgba(25,28,29,0.12)] p-5 sm:p-6">
<div className="flex flex-col sm:flex-row sm:items-center gap-4">
<p className="text-sm text-outline leading-relaxed flex-1">
We use cookies to understand how visitors use our site.
No personal data is shared with third parties.
</p>
<div className="flex items-center gap-2.5 flex-shrink-0">
<button
type="button"
onClick={handleDecline}
className="px-4 py-2 rounded-xl text-sm font-medium text-outline transition-colors hover:bg-on-surface/5 cursor-pointer"
>
Decline
</button>
<button
type="button"
onClick={handleAccept}
className="px-5 py-2 rounded-xl text-sm font-medium text-white transition-all hover:-translate-y-px active:translate-y-0 cursor-pointer shadow-[0_4px_16px_rgba(0,100,148,0.25)]"
style={{ background: 'linear-gradient(135deg, #006494, #5BA4D9)' }}
>
Accept
</button>
</div>
</div>
</div>
</div>
)
}

View File

@@ -0,0 +1,55 @@
import Script from 'next/script'
const GA_ID = process.env.NEXT_PUBLIC_GA_ID
export default function GoogleAnalytics() {
if (!GA_ID || process.env.NODE_ENV !== 'production') return null
return (
<>
{/* Consent Mode v2 — region-specific defaults */}
<Script id="gtag-consent" strategy="beforeInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Default: granted for regions without consent requirements
gtag('consent', 'default', {
analytics_storage: 'granted',
ad_storage: 'granted',
ad_user_data: 'granted',
ad_personalization: 'granted',
});
// EEA + UK: denied until user consents (GDPR)
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
wait_for_update: 500,
region: ['AT','BE','BG','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MT','NL','PL','PT','RO','SE','SI','SK','IS','LI','NO','GB'],
});
// Improve measurement when consent is denied
gtag('set', 'url_passthrough', true);
gtag('set', 'ads_data_redaction', true);
`}
</Script>
{/* Google tag (gtag.js) */}
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`}
strategy="afterInteractive"
/>
<Script id="gtag-init" strategy="afterInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_ID}');
`}
</Script>
</>
)
}

View File

@@ -259,7 +259,7 @@ export default function VoiceAgent({ locale, onComplete }: VoiceAgentProps) {
style={{ background: 'linear-gradient(135deg, #006494, #5BA4D9)' }} style={{ background: 'linear-gradient(135deg, #006494, #5BA4D9)' }}
> >
<Mic size={16} /> <Mic size={16} />
{locale === 'fr' ? 'Démarrer la conversation' : 'Start Conversation'} {t('voice.startConversation')}
</button> </button>
)} )}

View File

@@ -149,7 +149,6 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
const turnCompleteRef = useRef(true); const turnCompleteRef = useRef(true);
const briefSubmittedRef = useRef(false); const briefSubmittedRef = useRef(false);
const pendingContactRef = useRef<PendingContact | null>(null); const pendingContactRef = useRef<PendingContact | null>(null);
const pendingContactCallIdRef = useRef('');
const reconnectTranscriptRef = useRef<TranscriptEntry[]>([]); const reconnectTranscriptRef = useRef<TranscriptEntry[]>([]);
const statusRef = useRef<ConnectionStatus>('idle'); const statusRef = useRef<ConnectionStatus>('idle');
const wsRef = useRef<WebSocket | null>(null); const wsRef = useRef<WebSocket | null>(null);
@@ -217,9 +216,9 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
const contact = { name: contactName, email: contactEmail }; const contact = { name: contactName, email: contactEmail };
setPendingContact(contact); setPendingContact(contact);
pendingContactRef.current = contact; pendingContactRef.current = contact;
pendingContactCallIdRef.current = callId; // Respond immediately so Gemini doesn't timeout waiting for a tool response.
// Don't return a tool response yet — wait for user confirmation via confirmContact() // The agent is told to wait user confirmation comes as a text message via confirmContact().
return '__DEFERRED__'; return JSON.stringify({ success: true, message: 'Contact card is now shown on screen. Wait for the user to review and confirm before calling complete_brief. Do not proceed until you hear confirmation.' });
} }
if (name === 'complete_brief') { if (name === 'complete_brief') {
@@ -293,7 +292,6 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
setSelections({}); setSelections({});
setPendingContact(null); setPendingContact(null);
pendingContactRef.current = null; pendingContactRef.current = null;
pendingContactCallIdRef.current = '';
} }
setCompletedBrief(null); setCompletedBrief(null);
setCompletedFormData(null); setCompletedFormData(null);
@@ -463,13 +461,9 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
const responses = []; const responses = [];
for (const call of calls) { for (const call of calls) {
const result = await handleToolCall(call.name, call.args ?? {}, call.id); const result = await handleToolCall(call.name, call.args ?? {}, call.id);
if (result !== '__DEFERRED__') { responses.push({ id: call.id, name: call.name, response: { result } });
responses.push({ id: call.id, name: call.name, response: { result } });
}
}
if (responses.length > 0) {
ws.send(JSON.stringify({ toolResponse: { functionResponses: responses } }));
} }
ws.send(JSON.stringify({ toolResponse: { functionResponses: responses } }));
} }
} }
}; };
@@ -543,7 +537,6 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
setAgentAmplitude(0); setAgentAmplitude(0);
setCanReconnect(false); setCanReconnect(false);
reconnectTranscriptRef.current = []; reconnectTranscriptRef.current = [];
pendingContactCallIdRef.current = '';
setStatus('idle'); setStatus('idle');
}, []); }, []);
@@ -558,19 +551,18 @@ export default function VoiceAgentProvider({ locale, children }: VoiceAgentProvi
const confirmContact = useCallback(() => { const confirmContact = useCallback(() => {
if (!pendingContactRef.current) return; if (!pendingContactRef.current) return;
// Send confirmation back through WebSocket so the agent knows // Send a text message to let the agent know the user confirmed their details
if (wsRef.current?.readyState === WebSocket.OPEN) { if (wsRef.current?.readyState === WebSocket.OPEN) {
const { name, email } = pendingContactRef.current;
wsRef.current.send(JSON.stringify({ wsRef.current.send(JSON.stringify({
toolResponse: { realtimeInput: {
functionResponses: [{ text: `The user has confirmed their contact details on screen. Name: ${name}, Email: ${email}. You may now call complete_brief.`,
id: pendingContactCallIdRef.current,
name: 'request_contact',
response: { result: JSON.stringify({ confirmed: true, name: pendingContactRef.current.name, email: pendingContactRef.current.email }) },
}],
}, },
})); }));
console.log('[VoiceAgent] Contact confirmed, notified agent');
} else {
console.warn('[VoiceAgent] Cannot confirm contact — WebSocket not open');
} }
pendingContactCallIdRef.current = '';
}, []); }, []);
const reconnect = useCallback(async () => { const reconnect = useCallback(async () => {

View File

@@ -3,6 +3,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { useLocale, useTranslations } from 'next-intl'; import { useLocale, useTranslations } from 'next-intl';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { trackEvent } from '@/lib/analytics';
import StepServices from './StepServices'; import StepServices from './StepServices';
import StepDetails from './StepDetails'; import StepDetails from './StepDetails';
import StepContact from './StepContact'; import StepContact from './StepContact';
@@ -90,7 +91,11 @@ export default function WizardContainer() {
const goNext = () => { const goNext = () => {
setDirection(1); setDirection(1);
setCurrentStep((prev) => Math.min(prev + 1, 4) as 1 | 2 | 3 | 4); setCurrentStep((prev) => {
const next = Math.min(prev + 1, 4) as 1 | 2 | 3 | 4;
trackEvent('configurator_step_completed', { step: prev });
return next;
});
}; };
const goBack = () => { const goBack = () => {
@@ -131,6 +136,10 @@ export default function WizardContainer() {
setDirection(1); setDirection(1);
setIsGenerating(false); setIsGenerating(false);
setCurrentStep(4); setCurrentStep(4);
trackEvent('configurator_brief_generated', {
services: formData.services.join(','),
ai_enabled: formData.aiEnabled,
});
} catch { } catch {
setSubmitError(t('errors.network')); setSubmitError(t('errors.network'));
setIsGenerating(false); setIsGenerating(false);

View File

@@ -24,15 +24,15 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
}} }}
> >
{/* ━━━ BACKGROUND: Faint structural grid ━━━ */} {/* ━━━ BACKGROUND: Faint structural grid ━━━ */}
<g data-layer="background" opacity="0.5"> <g data-layer="background" opacity="0.85">
{/* Horizontal datum lines */} {/* Horizontal datum lines */}
<line x1="0" y1="200" x2="1000" y2="200" stroke="#1C2B3A" strokeOpacity="0.04" strokeWidth="0.5" strokeDasharray="8 24" /> <line x1="0" y1="200" x2="1000" y2="200" stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.5" strokeDasharray="8 24" />
<line x1="0" y1="420" x2="1000" y2="420" stroke="#1C2B3A" strokeOpacity="0.03" strokeWidth="0.5" strokeDasharray="6 20" /> <line x1="0" y1="420" x2="1000" y2="420" stroke="#1C2B3A" strokeOpacity="0.07" strokeWidth="0.5" strokeDasharray="6 20" />
<line x1="0" y1="640" x2="1000" y2="640" stroke="#1C2B3A" strokeOpacity="0.04" strokeWidth="0.5" strokeDasharray="8 24" /> <line x1="0" y1="640" x2="1000" y2="640" stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.5" strokeDasharray="8 24" />
{/* Vertical datum lines */} {/* Vertical datum lines */}
<line x1="500" y1="0" x2="500" y2="800" stroke="#1C2B3A" strokeOpacity="0.03" strokeWidth="0.5" strokeDasharray="6 20" /> <line x1="500" y1="0" x2="500" y2="800" stroke="#1C2B3A" strokeOpacity="0.07" strokeWidth="0.5" strokeDasharray="6 20" />
<line x1="680" y1="0" x2="680" y2="800" stroke="#1C2B3A" strokeOpacity="0.03" strokeWidth="0.5" strokeDasharray="4 18" /> <line x1="680" y1="0" x2="680" y2="800" stroke="#1C2B3A" strokeOpacity="0.07" strokeWidth="0.5" strokeDasharray="4 18" />
</g> </g>
{/* ━━━ MIDGROUND: The main arc composition ━━━ */} {/* ━━━ MIDGROUND: The main arc composition ━━━ */}
@@ -42,7 +42,7 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
cx={cx} cy={cy} r={R} cx={cx} cy={cy} r={R}
fill="none" fill="none"
stroke="#5BA4D9" stroke="#5BA4D9"
strokeOpacity="0.09" strokeOpacity="0.2"
strokeWidth="1" strokeWidth="1"
/> />
@@ -51,7 +51,7 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
cx={cx} cy={cy} r={R * 0.65} cx={cx} cy={cy} r={R * 0.65}
fill="none" fill="none"
stroke="#5BA4D9" stroke="#5BA4D9"
strokeOpacity="0.05" strokeOpacity="0.12"
strokeWidth="0.75" strokeWidth="0.75"
strokeDasharray="4 12" strokeDasharray="4 12"
/> />
@@ -61,7 +61,7 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
cx={cx} cy={cy} r={R * 1.35} cx={cx} cy={cy} r={R * 1.35}
fill="none" fill="none"
stroke="#1C2B3A" stroke="#1C2B3A"
strokeOpacity="0.035" strokeOpacity="0.08"
strokeWidth="0.5" strokeWidth="0.5"
strokeDasharray="3 16" strokeDasharray="3 16"
/> />
@@ -70,44 +70,44 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
{/* Vertical radius */} {/* Vertical radius */}
<line <line
x1={cx} y1={cy} x2={cx} y2={cy - R} x1={cx} y1={cy} x2={cx} y2={cy - R}
stroke="#5BA4D9" strokeOpacity="0.08" strokeWidth="0.75" stroke="#5BA4D9" strokeOpacity="0.18" strokeWidth="0.75"
/> />
{/* Top tick mark */} {/* Top tick mark */}
<line <line
x1={cx - 8} y1={cy - R} x2={cx + 8} y2={cy - R} x1={cx - 8} y1={cy - R} x2={cx + 8} y2={cy - R}
stroke="#5BA4D9" strokeOpacity="0.12" strokeWidth="0.75" stroke="#5BA4D9" strokeOpacity="0.25" strokeWidth="0.75"
/> />
{/* Diagonal radius — 45deg upper-right */} {/* Diagonal radius — 45deg upper-right */}
<line <line
x1={cx} y1={cy} x1={cx} y1={cy}
x2={cx + R * 0.707} y2={cy - R * 0.707} x2={cx + R * 0.707} y2={cy - R * 0.707}
stroke="#1C2B3A" strokeOpacity="0.06" strokeWidth="0.5" stroke="#1C2B3A" strokeOpacity="0.13" strokeWidth="0.5"
strokeDasharray="4 8" strokeDasharray="4 8"
/> />
{/* Horizontal radius — right */} {/* Horizontal radius — right */}
<line <line
x1={cx} y1={cy} x2={cx + R} y2={cy} x1={cx} y1={cy} x2={cx + R} y2={cy}
stroke="#5BA4D9" strokeOpacity="0.06" strokeWidth="0.5" stroke="#5BA4D9" strokeOpacity="0.14" strokeWidth="0.5"
/> />
{/* Right tick */} {/* Right tick */}
<line <line
x1={cx + R} y1={cy - 8} x2={cx + R} y2={cy + 8} x1={cx + R} y1={cy - 8} x2={cx + R} y2={cy + 8}
stroke="#5BA4D9" strokeOpacity="0.1" strokeWidth="0.75" stroke="#5BA4D9" strokeOpacity="0.22" strokeWidth="0.75"
/> />
{/* ── Center crosshair ── */} {/* ── Center crosshair ── */}
<line x1={cx - 12} y1={cy} x2={cx + 12} y2={cy} stroke="#5BA4D9" strokeOpacity="0.15" strokeWidth="0.75" /> <line x1={cx - 12} y1={cy} x2={cx + 12} y2={cy} stroke="#5BA4D9" strokeOpacity="0.3" strokeWidth="0.75" />
<line x1={cx} y1={cy - 12} x2={cx} y2={cy + 12} stroke="#5BA4D9" strokeOpacity="0.15" strokeWidth="0.75" /> <line x1={cx} y1={cy - 12} x2={cx} y2={cy + 12} stroke="#5BA4D9" strokeOpacity="0.3" strokeWidth="0.75" />
<circle cx={cx} cy={cy} r="2.5" fill="#5BA4D9" fillOpacity="0.12" /> <circle cx={cx} cy={cy} r="2.5" fill="#5BA4D9" fillOpacity="0.25" />
{/* ── Angle arc at center — 90deg sweep ── */} {/* ── Angle arc at center — 90deg sweep ── */}
<path <path
d={`M ${cx} ${cy - 30} A 30 30 0 0 1 ${cx + 30} ${cy}`} d={`M ${cx} ${cy - 30} A 30 30 0 0 1 ${cx + 30} ${cy}`}
fill="none" fill="none"
stroke="#5BA4D9" stroke="#5BA4D9"
strokeOpacity="0.1" strokeOpacity="0.2"
strokeWidth="0.75" strokeWidth="0.75"
/> />
@@ -115,38 +115,38 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
<line <line
x1={cx - R} y1={cy - R - 30} x1={cx - R} y1={cy - R - 30}
x2={cx + R} y2={cy - R - 30} x2={cx + R} y2={cy - R - 30}
stroke="#1C2B3A" strokeOpacity="0.07" strokeWidth="0.5" stroke="#1C2B3A" strokeOpacity="0.15" strokeWidth="0.5"
/> />
{/* End ticks */} {/* End ticks */}
<line x1={cx - R} y1={cy - R - 38} x2={cx - R} y2={cy - R - 22} stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.75" /> <line x1={cx - R} y1={cy - R - 38} x2={cx - R} y2={cy - R - 22} stroke="#1C2B3A" strokeOpacity="0.18" strokeWidth="0.75" />
<line x1={cx + R} y1={cy - R - 38} x2={cx + R} y2={cy - R - 22} stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.75" /> <line x1={cx + R} y1={cy - R - 38} x2={cx + R} y2={cy - R - 22} stroke="#1C2B3A" strokeOpacity="0.18" strokeWidth="0.75" />
{/* Label stub */} {/* Label stub */}
<rect x={cx - 18} y={cy - R - 37} width="36" height="7" rx="1" fill="#5BA4D9" fillOpacity="0.03" /> <rect x={cx - 18} y={cy - R - 37} width="36" height="7" rx="1" fill="#5BA4D9" fillOpacity="0.07" />
{/* ── Vertical dimension — right side ── */} {/* ── Vertical dimension — right side ── */}
<line <line
x1={cx + R + 30} y1={cy - R} x1={cx + R + 30} y1={cy - R}
x2={cx + R + 30} y2={cy + R} x2={cx + R + 30} y2={cy + R}
stroke="#1C2B3A" strokeOpacity="0.06" strokeWidth="0.5" stroke="#1C2B3A" strokeOpacity="0.13" strokeWidth="0.5"
strokeDasharray="2 8" strokeDasharray="2 8"
/> />
<line x1={cx + R + 22} y1={cy - R} x2={cx + R + 38} y2={cy - R} stroke="#1C2B3A" strokeOpacity="0.08" strokeWidth="0.75" /> <line x1={cx + R + 22} y1={cy - R} x2={cx + R + 38} y2={cy - R} stroke="#1C2B3A" strokeOpacity="0.16" strokeWidth="0.75" />
<line x1={cx + R + 22} y1={cy + R} x2={cx + R + 38} y2={cy + R} stroke="#1C2B3A" strokeOpacity="0.08" strokeWidth="0.75" /> <line x1={cx + R + 22} y1={cy + R} x2={cx + R + 38} y2={cy + R} stroke="#1C2B3A" strokeOpacity="0.16" strokeWidth="0.75" />
{/* Subtle fill — atmospheric glow behind main circle */} {/* Subtle fill — atmospheric glow behind main circle */}
<circle cx={cx} cy={cy} r={R * 0.8} fill="#5BA4D9" fillOpacity="0.015" /> <circle cx={cx} cy={cy} r={R * 0.8} fill="#5BA4D9" fillOpacity="0.035" />
</g> </g>
{/* ━━━ FOREGROUND: Crisp detail elements ━━━ */} {/* ━━━ FOREGROUND: Crisp detail elements ━━━ */}
<g data-layer="foreground"> <g data-layer="foreground">
{/* ── Corner brackets — architectural framing ── */} {/* ── Corner brackets — architectural framing ── */}
{/* Top-right */} {/* Top-right */}
<path d="M 940 40 L 970 40 L 970 70" fill="none" stroke="#1C2B3A" strokeOpacity="0.12" strokeWidth="1" /> <path d="M 940 40 L 970 40 L 970 70" fill="none" stroke="#1C2B3A" strokeOpacity="0.25" strokeWidth="1" />
{/* Bottom-right */} {/* Bottom-right */}
<path d="M 940 760 L 970 760 L 970 730" fill="none" stroke="#1C2B3A" strokeOpacity="0.08" strokeWidth="0.75" /> <path d="M 940 760 L 970 760 L 970 730" fill="none" stroke="#1C2B3A" strokeOpacity="0.18" strokeWidth="0.75" />
{/* Top inner */} {/* Top inner */}
<path d="M 560 80 L 590 80" fill="none" stroke="#1C2B3A" strokeOpacity="0.06" strokeWidth="0.75" /> <path d="M 560 80 L 590 80" fill="none" stroke="#1C2B3A" strokeOpacity="0.14" strokeWidth="0.75" />
<path d="M 560 80 L 560 110" fill="none" stroke="#1C2B3A" strokeOpacity="0.06" strokeWidth="0.75" /> <path d="M 560 80 L 560 110" fill="none" stroke="#1C2B3A" strokeOpacity="0.14" strokeWidth="0.75" />
{/* ── Tick marks around the main circle — spaced at 30deg intervals ── */} {/* ── Tick marks around the main circle — spaced at 30deg intervals ── */}
{[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map((deg) => { {[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map((deg) => {
@@ -161,7 +161,7 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
x1={x - nx * 6} y1={y - ny * 6} x1={x - nx * 6} y1={y - ny * 6}
x2={x + nx * 6} y2={y + ny * 6} x2={x + nx * 6} y2={y + ny * 6}
stroke="#5BA4D9" stroke="#5BA4D9"
strokeOpacity="0.1" strokeOpacity="0.2"
strokeWidth="0.75" strokeWidth="0.75"
/> />
) )
@@ -172,7 +172,7 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
d={`M ${cx + 60} ${cy - R + 40} A 50 50 0 0 1 ${cx + 110} ${cy - R + 40}`} d={`M ${cx + 60} ${cy - R + 40} A 50 50 0 0 1 ${cx + 110} ${cy - R + 40}`}
fill="none" fill="none"
stroke="#5BA4D9" stroke="#5BA4D9"
strokeOpacity="0.12" strokeOpacity="0.25"
strokeWidth="0.75" strokeWidth="0.75"
/> />
@@ -185,20 +185,20 @@ export default function HeroGeometric({ className }: HeroGeometricProps) {
cy={560 + row * 28} cy={560 + row * 28}
r="1" r="1"
fill="#1C2B3A" fill="#1C2B3A"
fillOpacity="0.06" fillOpacity="0.13"
/> />
)) ))
)} )}
{/* ── Scattered accent dots ── */} {/* ── Scattered accent dots ── */}
<circle cx={cx + 140} cy={cy - 80} r="2" fill="#5BA4D9" fillOpacity="0.1" /> <circle cx={cx + 140} cy={cy - 80} r="2" fill="#5BA4D9" fillOpacity="0.2" />
<circle cx={cx - 120} cy={cy + 100} r="1.5" fill="#5BA4D9" fillOpacity="0.07" /> <circle cx={cx - 120} cy={cy + 100} r="1.5" fill="#5BA4D9" fillOpacity="0.15" />
<circle cx={cx + 200} cy={cy + 150} r="1.5" fill="#1C2B3A" fillOpacity="0.06" /> <circle cx={cx + 200} cy={cy + 150} r="1.5" fill="#1C2B3A" fillOpacity="0.13" />
{/* ── Sparse left-side balance elements ── */} {/* ── Sparse left-side balance elements ── */}
<line x1="60" y1="350" x2="180" y2="350" stroke="#1C2B3A" strokeOpacity="0.03" strokeWidth="0.5" strokeDasharray="4 16" /> <line x1="60" y1="350" x2="180" y2="350" stroke="#1C2B3A" strokeOpacity="0.07" strokeWidth="0.5" strokeDasharray="4 16" />
<line x1="100" y1="500" x2="100" y2="530" stroke="#1C2B3A" strokeOpacity="0.04" strokeWidth="0.5" /> <line x1="100" y1="500" x2="100" y2="530" stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.5" />
<line x1="88" y1="515" x2="112" y2="515" stroke="#1C2B3A" strokeOpacity="0.04" strokeWidth="0.5" /> <line x1="88" y1="515" x2="112" y2="515" stroke="#1C2B3A" strokeOpacity="0.09" strokeWidth="0.5" />
</g> </g>
</svg> </svg>
) )

View File

@@ -115,11 +115,20 @@ export default function Nav() {
} }
}, [pathname]) }, [pathname])
const otherLocale = locales.find((l) => l !== currentLocale) ?? 'fr' const [localeMenuOpen, setLocaleMenuOpen] = useState(false)
const LOCALE_DISPLAY: Record<string, { flag: string; label: string; short: string }> = {
en: { flag: '🇬🇧', label: 'English', short: 'EN' },
fr: { flag: '🇫🇷', label: 'Français', short: 'FR' },
it: { flag: '🇮🇹', label: 'Italiano', short: 'IT' },
es: { flag: '🇪🇸', label: 'Español', short: 'ES' },
}
const isHomePage = pathname === '/' const isHomePage = pathname === '/'
function handleLocaleSwitch() { function handleLocaleSwitch(targetLocale: string) {
router.replace(pathname as any, { locale: otherLocale as any }) router.replace(pathname as any, { locale: targetLocale as any })
setLocaleMenuOpen(false)
} }
// Prevent body scroll when mobile menu is open // Prevent body scroll when mobile menu is open
@@ -183,14 +192,58 @@ export default function Nav() {
{/* ── Desktop right controls ── */} {/* ── Desktop right controls ── */}
<div className="hidden lg:flex items-center gap-4 shrink-0"> <div className="hidden lg:flex items-center gap-4 shrink-0">
{/* Language toggle */} {/* Language dropdown */}
<button <div className="relative">
onClick={handleLocaleSwitch} <button
className="label-md text-on-surface/60 hover:text-on-surface transition-colors duration-200 px-2 py-1 rounded focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2" onClick={() => setLocaleMenuOpen((prev) => !prev)}
aria-label={`Switch to ${otherLocale === 'fr' ? 'French' : 'English'}`} className="label-md text-on-surface/60 hover:text-on-surface transition-colors duration-200 px-2 py-1 rounded focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2"
> aria-label="Switch language"
{otherLocale.toUpperCase()} aria-expanded={localeMenuOpen}
</button> aria-haspopup="listbox"
>
{LOCALE_DISPLAY[currentLocale]?.short ?? currentLocale.toUpperCase()}
</button>
{/* Transparent overlay to close on outside click */}
{localeMenuOpen && (
<div
className="fixed inset-0 z-[40]"
aria-hidden="true"
onClick={() => setLocaleMenuOpen(false)}
/>
)}
<AnimatePresence>
{localeMenuOpen && (
<motion.ul
role="listbox"
aria-label="Select language"
className="absolute right-0 top-full mt-2 z-[41] bg-surface-high rounded-xl shadow-lg border border-outline-variant/20 overflow-hidden min-w-[140px]"
initial={{ opacity: 0, y: -6, scale: 0.97 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -6, scale: 0.97 }}
transition={{ duration: 0.18, ease: [0.25, 0.46, 0.45, 0.94] }}
>
{locales
.filter((l) => l !== currentLocale)
.map((l) => {
const display = LOCALE_DISPLAY[l]
return (
<li key={l} role="option" aria-selected={false}>
<button
onClick={() => handleLocaleSwitch(l)}
className="w-full flex items-center gap-2.5 px-4 py-2.5 label-md text-on-surface/70 hover:text-on-surface hover:bg-surface-low transition-colors duration-150 text-left"
>
<span aria-hidden="true">{display?.flag}</span>
<span>{display?.label}</span>
</button>
</li>
)
})}
</motion.ul>
)}
</AnimatePresence>
</div>
{/* Start a Project CTA */} {/* Start a Project CTA */}
<a <a
@@ -207,7 +260,7 @@ export default function Nav() {
{/* ── Mobile hamburger ── */} {/* ── Mobile hamburger ── */}
<button <button
className="lg:hidden p-2 -mr-2 text-on-surface focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 rounded" className="lg:hidden p-2 -mr-2 text-on-surface focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 rounded"
onClick={() => setMobileOpen(true)} onClick={() => { setMobileOpen(true); setLocaleMenuOpen(false) }}
aria-label="Open navigation menu" aria-label="Open navigation menu"
aria-expanded={mobileOpen} aria-expanded={mobileOpen}
aria-controls="mobile-menu" aria-controls="mobile-menu"
@@ -300,16 +353,27 @@ export default function Nav() {
{/* Bottom controls */} {/* Bottom controls */}
<div className="px-6 pb-8 pt-4 flex flex-col gap-3"> <div className="px-6 pb-8 pt-4 flex flex-col gap-3">
{/* Language toggle */} {/* Language options */}
<button <div className="flex flex-col gap-1">
onClick={() => { {locales
handleLocaleSwitch() .filter((l) => l !== currentLocale)
setMobileOpen(false) .map((l) => {
}} const display = LOCALE_DISPLAY[l]
className="w-full py-3 label-md text-on-surface/60 hover:text-on-surface transition-colors duration-200 text-left focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 rounded" return (
> <button
{otherLocale === 'fr' ? '🇫🇷 Français' : '🇬🇧 English'} key={l}
</button> onClick={() => {
handleLocaleSwitch(l)
setMobileOpen(false)
}}
className="w-full py-2.5 label-md text-on-surface/60 hover:text-on-surface transition-colors duration-200 text-left focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 rounded flex items-center gap-2.5"
>
<span aria-hidden="true">{display?.flag}</span>
<span>{display?.label}</span>
</button>
)
})}
</div>
{/* CTA */} {/* CTA */}
<a <a

View File

@@ -36,7 +36,16 @@ export default function Configurator() {
]; ];
return ( return (
<section id="configure" className="relative bg-surface py-24 overflow-hidden"> <section
id="configure"
className="relative bg-surface py-24 overflow-hidden"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
>
{/* Subtle diagonal accent line */} {/* Subtle diagonal accent line */}
<div <div
className="absolute top-0 left-0 right-0 h-px pointer-events-none" className="absolute top-0 left-0 right-0 h-px pointer-events-none"

View File

@@ -5,6 +5,7 @@ import { useLocale, useTranslations } from 'next-intl';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { MessageCircle } from 'lucide-react'; import { MessageCircle } from 'lucide-react';
import { revealVariants, staggerContainer, viewportOnce } from '@/lib/animations'; import { revealVariants, staggerContainer, viewportOnce } from '@/lib/animations';
import { trackEvent } from '@/lib/analytics';
import VoiceAgentProvider from '@/components/configurator/VoiceAgentProvider'; import VoiceAgentProvider from '@/components/configurator/VoiceAgentProvider';
import VoiceAgent from '@/components/configurator/VoiceAgent'; import VoiceAgent from '@/components/configurator/VoiceAgent';
import StepComplete from '@/components/configurator/StepComplete'; import StepComplete from '@/components/configurator/StepComplete';
@@ -36,6 +37,7 @@ export default function Discovery() {
const handleOpen = () => { const handleOpen = () => {
setIsOpen(true); setIsOpen(true);
trackEvent('voice_agent_started');
// Scroll to panel after it renders // Scroll to panel after it renders
requestAnimationFrame(() => { requestAnimationFrame(() => {
panelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }); panelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
@@ -44,6 +46,7 @@ export default function Discovery() {
const handleComplete = (brief: string, formData: WizardFormData) => { const handleComplete = (brief: string, formData: WizardFormData) => {
setCompleted({ brief, formData }); setCompleted({ brief, formData });
trackEvent('voice_agent_brief_generated');
}; };
const handleReset = () => { const handleReset = () => {
@@ -54,7 +57,16 @@ export default function Discovery() {
if (!voiceSupported) return null; if (!voiceSupported) return null;
return ( return (
<section id="discover" className="relative bg-surface-high py-24 overflow-hidden"> <section
id="discover"
className="relative bg-surface-high py-24 overflow-hidden"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
>
{/* Top accent line */} {/* Top accent line */}
<div <div
className="absolute top-0 left-0 right-0 h-px pointer-events-none" className="absolute top-0 left-0 right-0 h-px pointer-events-none"
@@ -111,7 +123,7 @@ export default function Discovery() {
</motion.p> </motion.p>
{!isOpen && ( {!isOpen && (
<motion.div variants={revealVariants} className="mt-8"> <motion.div variants={revealVariants} className="mt-8 flex flex-col items-center">
<button <button
type="button" type="button"
onClick={handleOpen} onClick={handleOpen}

View File

@@ -1,5 +1,6 @@
'use client'; 'use client';
import Image from 'next/image';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
@@ -124,198 +125,30 @@ function PhilosophyPillar({
); );
} }
// ─── Abstract Geometric Decoration ───────────────────────────────────────────
function AbstractGeometry() {
return (
<div
className="absolute inset-0 overflow-hidden rounded-xl"
aria-hidden="true"
>
{/* Primary large circle — filled radial glow */}
<div
className="absolute rounded-full"
style={{
width: '65%',
height: '65%',
top: '-8%',
right: '-12%',
background:
'radial-gradient(circle, rgba(91,164,217,0.12) 0%, rgba(0,100,148,0.06) 60%, transparent 100%)',
}}
/>
{/* Large circle ring — border only, ~40% opacity */}
<div
className="absolute rounded-full"
style={{
width: '72%',
height: '72%',
top: '-18%',
right: '-20%',
border: '1px solid rgba(91,164,217,0.20)',
opacity: 0.4,
}}
/>
{/* Secondary circle, bottom-left */}
<div
className="absolute rounded-full"
style={{
width: '50%',
height: '50%',
bottom: '-10%',
left: '-6%',
background:
'radial-gradient(circle, rgba(0,100,148,0.08) 0%, transparent 70%)',
}}
/>
{/* Second smaller ring — bottom-left */}
<div
className="absolute rounded-full"
style={{
width: '38%',
height: '38%',
bottom: '-4%',
left: '4%',
border: '1px solid rgba(0,100,148,0.18)',
opacity: 0.45,
}}
/>
{/* Diagonal grid */}
<div
className="absolute inset-0 opacity-[0.03]"
style={{
backgroundImage:
'repeating-linear-gradient(-45deg, var(--color-primary-dark) 0, var(--color-primary-dark) 1px, transparent 0, transparent 50%)',
backgroundSize: '32px 32px',
}}
/>
{/* Diagonal line crossing the composition */}
<div
className="absolute"
style={{
width: '130%',
height: '1px',
top: '42%',
left: '-15%',
background:
'linear-gradient(90deg, transparent 0%, rgba(91,164,217,0.18) 30%, rgba(0,100,148,0.22) 60%, transparent 100%)',
transform: 'rotate(-12deg)',
transformOrigin: 'left center',
}}
/>
{/* Accent rectangle top-left, rotated */}
<div
className="absolute rounded-md"
style={{
width: '22%',
height: '30%',
top: '10%',
left: '8%',
border: '1.5px solid rgba(91,164,217,0.15)',
transform: 'rotate(-8deg)',
}}
/>
{/* Second rotated rectangle outline — center */}
<div
className="absolute rounded-sm"
style={{
width: '16%',
height: '22%',
top: '38%',
left: '28%',
border: '1px solid rgba(91,164,217,0.12)',
transform: 'rotate(14deg)',
}}
/>
{/* Floating dot cluster center-right */}
<div
className="absolute"
style={{
width: '22%',
height: '22%',
top: '35%',
right: '10%',
backgroundImage:
'radial-gradient(circle, rgba(91,164,217,0.28) 1.5px, transparent 1.5px)',
backgroundSize: '10px 10px',
}}
/>
{/* Small dot cluster upper-left */}
<div
className="absolute"
style={{
width: '14%',
height: '16%',
top: '12%',
right: '32%',
backgroundImage:
'radial-gradient(circle, rgba(0,100,148,0.20) 1.5px, transparent 1.5px)',
backgroundSize: '8px 8px',
}}
/>
{/* Thin dashed arc */}
<svg
className="absolute"
style={{ top: '20%', left: '30%', opacity: 0.09 }}
width="140"
height="140"
viewBox="0 0 140 140"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="70"
cy="70"
r="60"
stroke="var(--color-primary-dark)"
strokeWidth="1"
strokeDasharray="8 6"
/>
</svg>
{/* Small solid accent square */}
<div
className="absolute rounded-sm"
style={{
width: '6%',
height: '6%',
bottom: '28%',
right: '28%',
background: 'rgba(91,164,217,0.22)',
transform: 'rotate(12deg)',
}}
/>
{/* Navy bottom overlay that fades upward — gives depth to pull-quote */}
<div
className="absolute inset-x-0 bottom-0 rounded-b-xl"
style={{
height: '45%',
background:
'linear-gradient(to top, rgba(28,43,58,0.55) 0%, rgba(28,43,58,0.18) 55%, transparent 100%)',
}}
/>
</div>
);
}
// ─── Main Component ─────────────────────────────────────────────────────────── // ─── Main Component ───────────────────────────────────────────────────────────
export default function Philosophy() { export default function Philosophy() {
const t = useTranslations(); const t = useTranslations();
return ( return (
<section id="about" className="bg-surface py-20"> <section
id="about"
className="relative bg-surface py-20 overflow-hidden"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
>
{/* Ambient radial glow */}
<div
className="absolute inset-0 pointer-events-none"
style={{
background: 'radial-gradient(ellipse 80% 60% at 20% 50%, rgba(91,164,217,0.04) 0%, transparent 70%)',
}}
aria-hidden="true"
/>
<div className="container mx-auto px-6"> <div className="container mx-auto px-6">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start"> <div className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-start">
@@ -374,7 +207,13 @@ export default function Philosophy() {
'overflow-visible', 'overflow-visible',
)} )}
> >
<AbstractGeometry /> <Image
src="/images/philosophy_image.png"
alt="Craftsmanship and precision"
fill
className="object-cover rounded-xl"
sizes="(max-width: 1024px) 100vw, 58vw"
/>
{/* Subtle inner shadow rim */} {/* Subtle inner shadow rim */}
<div <div

View File

@@ -2,8 +2,6 @@
import { motion, type Variants } from 'framer-motion'; import { motion, type Variants } from 'framer-motion';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import type { LucideIcon } from 'lucide-react';
import { Search, LayoutDashboard, PenTool, Rocket } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { import {
staggerContainerWide, staggerContainerWide,
@@ -17,16 +15,15 @@ import SectionHeader from '@/components/ui/SectionHeader';
interface Step { interface Step {
numeral: string; numeral: string;
key: 'discovery' | 'strategy' | 'build' | 'launch'; key: 'discovery' | 'strategy' | 'build' | 'launch';
Icon: LucideIcon;
} }
// ─── Data ───────────────────────────────────────────────────────────────────── // ─── Data ─────────────────────────────────────────────────────────────────────
const STEPS: Step[] = [ const STEPS: Step[] = [
{ numeral: '01', key: 'discovery', Icon: Search }, { numeral: '01', key: 'discovery' },
{ numeral: '02', key: 'strategy', Icon: LayoutDashboard }, { numeral: '02', key: 'strategy' },
{ numeral: '03', key: 'build', Icon: PenTool }, { numeral: '03', key: 'build' },
{ numeral: '04', key: 'launch', Icon: Rocket }, { numeral: '04', key: 'launch' },
]; ];
// ─── Variants ───────────────────────────────────────────────────────────────── // ─── Variants ─────────────────────────────────────────────────────────────────
@@ -44,9 +41,134 @@ const numeralScaleVariants: Variants = {
}, },
}; };
// ─── Animated blueprint network (desktop only) ───────────────────────────────
function FlowNetwork() {
// Radial constellation — center hub with curved spokes to outer nodes
const cx = 130, cy = 100; // center
const nodes = [
{ x: 50, y: 30 }, // top-left
{ x: 210, y: 25 }, // top-right
{ x: 240, y: 110 }, // right
{ x: 195, y: 180 }, // bottom-right
{ x: 55, y: 170 }, // bottom-left
{ x: 20, y: 95 }, // left
];
return (
<div className="hidden lg:block relative mt-8 w-full h-52" aria-hidden="true">
<style>{`
@keyframes flow-dash { to { stroke-dashoffset: -40; } }
@keyframes flow-dash-slow { to { stroke-dashoffset: -40; } }
@keyframes node-pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
@keyframes orbit-a {
from { transform: rotate(0deg) translateX(28px) rotate(0deg); }
to { transform: rotate(360deg) translateX(28px) rotate(-360deg); }
}
@keyframes orbit-b {
from { transform: rotate(120deg) translateX(22px) rotate(-120deg); }
to { transform: rotate(480deg) translateX(22px) rotate(-480deg); }
}
@keyframes orbit-c {
from { transform: rotate(240deg) translateX(35px) rotate(-240deg); }
to { transform: rotate(-120deg) translateX(35px) rotate(120deg); }
}
@keyframes ring-breathe {
0%, 100% { opacity: 0.06; }
50% { opacity: 0.14; }
}
.process-flow { animation: flow-dash 2.2s linear infinite; }
.process-flow-slow { animation: flow-dash-slow 3.5s linear infinite; }
.process-pulse { animation: node-pulse 2.8s ease-in-out infinite; }
.process-orbit-a { animation: orbit-a 8s linear infinite; }
.process-orbit-b { animation: orbit-b 11s linear infinite; }
.process-orbit-c { animation: orbit-c 14s linear infinite; }
.process-ring { animation: ring-breathe 4s ease-in-out infinite; }
.process-ring-lg { animation: ring-breathe 5.5s ease-in-out infinite; }
`}</style>
<svg className="w-full h-full" viewBox="0 0 260 200" fill="none" xmlns="http://www.w3.org/2000/svg">
{/* Breathing rings */}
<circle cx={cx} cy={cy} r="24" stroke="rgba(91,164,217,0.1)" strokeWidth="1" fill="none" className="process-ring" />
<circle cx={cx} cy={cy} r="42" stroke="rgba(91,164,217,0.07)" strokeWidth="1" fill="none" className="process-ring-lg" />
<circle cx={cx} cy={cy} r="65" stroke="rgba(91,164,217,0.04)" strokeWidth="0.8" fill="none" strokeDasharray="3 6" />
{/* Curved spokes from center to each outer node */}
{nodes.map((n, i) => {
const mx = cx + (n.x - cx) * 0.5 + (i % 2 === 0 ? 15 : -15);
const my = cy + (n.y - cy) * 0.5 + (i % 2 === 0 ? -12 : 12);
return (
<path
key={i}
d={`M ${cx} ${cy} Q ${mx} ${my} ${n.x} ${n.y}`}
stroke="rgba(91,164,217,0.18)"
strokeWidth="1.2"
strokeDasharray="5 4"
strokeLinecap="round"
className={i % 2 === 0 ? 'process-flow' : 'process-flow-slow'}
style={{ animationDelay: `${i * 0.3}s` }}
/>
);
})}
{/* Faint arcs connecting adjacent outer nodes */}
{nodes.map((n, i) => {
const next = nodes[(i + 1) % nodes.length];
const mx = cx + (n.x + next.x - 2 * cx) * 0.15;
const my = cy + (n.y + next.y - 2 * cy) * 0.15;
return (
<path
key={`arc-${i}`}
d={`M ${n.x} ${n.y} Q ${mx} ${my} ${next.x} ${next.y}`}
stroke="rgba(91,164,217,0.08)"
strokeWidth="0.8"
strokeDasharray="3 5"
strokeLinecap="round"
/>
);
})}
{/* Outer nodes — pulsing */}
{nodes.map((n, i) => (
<circle
key={`node-${i}`}
cx={n.x}
cy={n.y}
r="3"
fill="#5BA4D9"
className="process-pulse"
style={{ animationDelay: `${i * 0.45}s` }}
/>
))}
{/* Center hub */}
<circle cx={cx} cy={cy} r="5" fill="#5BA4D9" opacity="0.85" />
<circle cx={cx} cy={cy} r="2" fill="#fff" opacity="0.9" />
{/* Orbiting particles */}
<g style={{ transformOrigin: `${cx}px ${cy}px` }}>
<circle cx={cx} cy={cy} r="2" fill="#5BA4D9" opacity="0.7" className="process-orbit-a" />
</g>
<g style={{ transformOrigin: `${cx}px ${cy}px` }}>
<circle cx={cx} cy={cy} r="1.5" fill="rgba(91,164,217,0.5)" className="process-orbit-b" />
</g>
<g style={{ transformOrigin: `${cx}px ${cy}px` }}>
<circle cx={cx} cy={cy} r="1.5" fill="rgba(91,164,217,0.35)" className="process-orbit-c" />
</g>
{/* Corner brackets — architectural detail */}
<path d="M 14 25 L 14 20 L 19 20" stroke="rgba(28,43,58,0.12)" strokeWidth="0.8" fill="none" />
<path d="M 246 175 L 246 180 L 241 180" stroke="rgba(28,43,58,0.12)" strokeWidth="0.8" fill="none" />
</svg>
</div>
);
}
// ─── Sub-components ─────────────────────────────────────────────────────────── // ─── Sub-components ───────────────────────────────────────────────────────────
function StepCard({ numeral, stepKey, Icon }: { numeral: string; stepKey: string; Icon: LucideIcon }) { function StepCard({ numeral, stepKey }: { numeral: string; stepKey: string }) {
const t = useTranslations(); const t = useTranslations();
const title = t(`process.steps.${stepKey}.title`); const title = t(`process.steps.${stepKey}.title`);
const description = t(`process.steps.${stepKey}.description`); const description = t(`process.steps.${stepKey}.description`);
@@ -94,7 +216,16 @@ export default function Process() {
const t = useTranslations(); const t = useTranslations();
return ( return (
<section id="process" className="bg-surface-low py-20"> <section
id="process"
className="relative bg-surface py-20"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
>
<div className="container mx-auto px-6"> <div className="container mx-auto px-6">
{/* {/*
@@ -121,59 +252,22 @@ export default function Process() {
align="left" align="left"
/> />
</div> </div>
<FlowNetwork />
</div> </div>
{/* ── Steps column ── */} {/* ── Steps column ── */}
<div className="lg:col-span-3"> <div className="lg:col-span-3">
<div className="relative"> <motion.div
{/* Dashed connector line — visible on sm+ grid layouts only */} variants={staggerContainerWide}
<div initial="hidden"
className="hidden sm:block absolute inset-0 pointer-events-none" whileInView="visible"
aria-hidden="true" viewport={viewportOnce}
> className="grid grid-cols-1 sm:grid-cols-2 gap-5"
<svg >
className="w-full h-full" {STEPS.map((step) => (
preserveAspectRatio="none" <StepCard key={step.key} numeral={step.numeral} stepKey={step.key} />
xmlns="http://www.w3.org/2000/svg" ))}
> </motion.div>
{/* Horizontal dashes across the middle gap */}
<line
x1="50%" y1="50%"
x2="50%" y2="50%"
stroke="rgba(91,164,217,0.18)"
strokeWidth="1.5"
strokeDasharray="4 6"
/>
{/* Vertical dashes down the centre gap */}
<line
x1="0%" y1="50%"
x2="100%" y2="50%"
stroke="rgba(91,164,217,0.18)"
strokeWidth="1.5"
strokeDasharray="4 6"
/>
<line
x1="50%" y1="0%"
x2="50%" y2="100%"
stroke="rgba(91,164,217,0.18)"
strokeWidth="1.5"
strokeDasharray="4 6"
/>
</svg>
</div>
<motion.div
variants={staggerContainerWide}
initial="hidden"
whileInView="visible"
viewport={viewportOnce}
className="grid grid-cols-1 sm:grid-cols-2 gap-5"
>
{STEPS.map((step) => (
<StepCard key={step.key} numeral={step.numeral} stepKey={step.key} Icon={step.Icon} />
))}
</motion.div>
</div>
</div> </div>
</div> </div>

View File

@@ -9,6 +9,7 @@ import {
fadeVariants, fadeVariants,
viewportOnce, viewportOnce,
} from '@/lib/animations'; } from '@/lib/animations';
import Image from 'next/image';
import { Link } from '@/i18n/navigation'; import { Link } from '@/i18n/navigation';
import { Lock, Clock, ArrowRight } from 'lucide-react'; import { Lock, Clock, ArrowRight } from 'lucide-react';
@@ -21,6 +22,7 @@ interface Project {
/** number of tags to resolve from the translation array */ /** number of tags to resolve from the translation array */
tagCount: number; tagCount: number;
featured?: boolean; featured?: boolean;
image: string;
} }
interface ComingSoonItem { interface ComingSoonItem {
@@ -37,16 +39,19 @@ const PROJECTS: Project[] = [
slug: 'monaco-ocean', slug: 'monaco-ocean',
tagCount: 2, tagCount: 2,
featured: true, featured: true,
image: '/images/monaco_high_res.jpg',
}, },
{ {
i18nKey: 'portNimara', i18nKey: 'portNimara',
slug: 'port-nimara', slug: 'port-nimara',
tagCount: 2, tagCount: 2,
image: '/images/anguilla.png',
}, },
{ {
i18nKey: 'portAmador', i18nKey: 'portAmador',
slug: 'port-amador', slug: 'port-amador',
tagCount: 2, tagCount: 2,
image: '/images/panama.png',
}, },
]; ];
@@ -86,274 +91,6 @@ const comingSoonVariants = {
}, },
}; };
// ─── Geometric Placeholder ────────────────────────────────────────────────────
function GeometricPlaceholder({
variant = 'featured',
cardVariant = 'default',
className,
}: {
variant?: 'featured' | 'small';
cardVariant?: 'default' | 'nimara' | 'amador';
className?: string;
}) {
const isFeatured = variant === 'featured';
// Different gradient bases per card so secondary cards look distinct
const gradientMap = {
default: 'from-primary-dark/90 to-primary/70',
nimara: 'from-navy/95 to-primary-dark/75',
amador: 'from-[#1a3a4a]/95 to-primary/60',
};
return (
<div
className={cn(
'relative overflow-hidden bg-gradient-to-br',
gradientMap[cardVariant],
className,
)}
aria-hidden="true"
>
<div className="absolute inset-0">
{isFeatured ? (
/* ── Featured (Monaco): blueprint feel ── */
<>
{/* Large filled circle top-right */}
<div
className="absolute rounded-full bg-white/[0.06]"
style={{ width: '55%', height: '55%', top: '-15%', right: '-10%' }}
/>
{/* Large circle ring — blueprint layer */}
<div
className="absolute rounded-full"
style={{
width: '45%',
height: '45%',
top: '10%',
left: '5%',
border: '1px solid rgba(255,255,255,0.12)',
opacity: 0.4,
}}
/>
{/* Medium circle bottom-left */}
<div
className="absolute rounded-full bg-white/[0.08]"
style={{ width: '40%', height: '40%', bottom: '-20%', left: '-5%' }}
/>
{/* Subtle grid overlay (blueprint feel) */}
<div
className="absolute inset-0 opacity-[0.035]"
style={{
backgroundImage:
'linear-gradient(rgba(255,255,255,1) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,1) 1px, transparent 1px)',
backgroundSize: '32px 32px',
}}
/>
{/* Diagonal stripes very subtle */}
<div
className="absolute inset-0 opacity-[0.025]"
style={{
backgroundImage:
'repeating-linear-gradient(-45deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
backgroundSize: '28px 28px',
}}
/>
{/* Small dot cluster */}
<div
className="absolute opacity-[0.12]"
style={{
width: '20%',
height: '20%',
top: '55%',
right: '18%',
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
backgroundSize: '8px 8px',
}}
/>
{/* Blueprint horizontal line — wide, white/20 */}
<div
className="absolute bg-white/[0.22] rounded-full"
style={{ width: '60%', height: '1px', top: '50%', left: '5%' }}
/>
{/* Second thinner line below */}
<div
className="absolute bg-white/[0.10] rounded-full"
style={{ width: '40%', height: '1px', top: 'calc(50% + 10px)', left: '5%' }}
/>
{/* Accent rotated rectangle */}
<div
className="absolute bg-white/[0.10] rounded-sm"
style={{
width: '18%',
height: '28%',
bottom: '18%',
right: '15%',
transform: 'rotate(-6deg)',
}}
/>
{/* Small diagonal accent line */}
<div
className="absolute bg-white/[0.15]"
style={{
width: '25%',
height: '1px',
top: '28%',
right: '8%',
transform: 'rotate(-30deg)',
transformOrigin: 'left center',
}}
/>
</>
) : cardVariant === 'nimara' ? (
/* ── Port Nimara: horizontal bands + arc ── */
<>
{/* Large arc ring top-left */}
<div
className="absolute rounded-full"
style={{
width: '80%',
height: '80%',
top: '-30%',
left: '-20%',
border: '1px solid rgba(255,255,255,0.10)',
opacity: 0.5,
}}
/>
{/* Smaller ring center */}
<div
className="absolute rounded-full"
style={{
width: '45%',
height: '70%',
bottom: '-15%',
right: '-10%',
border: '1px solid rgba(91,164,217,0.25)',
}}
/>
{/* Horizontal rule band */}
<div
className="absolute bg-white/[0.06]"
style={{ height: '28%', bottom: 0, left: 0, right: 0 }}
/>
{/* Fine horizontal lines */}
<div
className="absolute bg-white/20 rounded-full"
style={{ width: '50%', height: '1px', top: '35%', right: '8%' }}
/>
<div
className="absolute bg-white/10 rounded-full"
style={{ width: '30%', height: '1px', top: '45%', right: '8%' }}
/>
{/* Dot cluster top-right */}
<div
className="absolute opacity-[0.14]"
style={{
width: '25%',
height: '30%',
top: '5%',
right: '5%',
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
backgroundSize: '8px 8px',
}}
/>
{/* Diagonal line */}
<div
className="absolute bg-white/[0.12]"
style={{
width: '40%',
height: '1px',
top: '60%',
left: '5%',
transform: 'rotate(-20deg)',
transformOrigin: 'left center',
}}
/>
</>
) : (
/* ── Port Amador: triangular/radial composition ── */
<>
{/* Central radial glow */}
<div
className="absolute"
style={{
width: '70%',
height: '70%',
top: '-10%',
right: '-15%',
background:
'radial-gradient(circle, rgba(91,164,217,0.18) 0%, transparent 70%)',
}}
/>
{/* Diamond/rotated square accent */}
<div
className="absolute"
style={{
width: '30%',
height: '50%',
bottom: '-10%',
left: '10%',
border: '1px solid rgba(255,255,255,0.12)',
transform: 'rotate(45deg)',
}}
/>
{/* Diagonal stripes (different angle) */}
<div
className="absolute inset-0 opacity-[0.03]"
style={{
backgroundImage:
'repeating-linear-gradient(30deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
backgroundSize: '20px 20px',
}}
/>
{/* Top horizontal line */}
<div
className="absolute bg-white/20 rounded-full"
style={{ width: '40%', height: '1px', top: '22%', left: '8%' }}
/>
{/* Small filled rectangle */}
<div
className="absolute bg-white/[0.12] rounded-sm"
style={{
width: '20%',
height: '32%',
top: '15%',
right: '12%',
transform: 'rotate(8deg)',
}}
/>
{/* Dot accent bottom-right */}
<div
className="absolute opacity-[0.16]"
style={{
width: '22%',
height: '22%',
bottom: '8%',
right: '8%',
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
backgroundSize: '7px 7px',
}}
/>
</>
)}
</div>
{/* Bottom gradient fade — card bg color bleed for text readability */}
<div
className="absolute inset-x-0 bottom-0 h-2/5"
style={{
background: isFeatured
? 'linear-gradient(to top, rgba(0,100,148,0.55) 0%, transparent 100%)'
: cardVariant === 'nimara'
? 'linear-gradient(to top, rgba(28,43,58,0.60) 0%, transparent 100%)'
: 'linear-gradient(to top, rgba(26,58,74,0.55) 0%, transparent 100%)',
}}
/>
</div>
);
}
// ─── Tag Chip ───────────────────────────────────────────────────────────────── // ─── Tag Chip ─────────────────────────────────────────────────────────────────
function TagChip({ label, showDot = false }: { label: string; showDot?: boolean }) { function TagChip({ label, showDot = false }: { label: string; showDot?: boolean }) {
@@ -383,12 +120,15 @@ function FeaturedCard({ project, readLabel, t }: { project: Project; readLabel:
'transition-shadow duration-300 hover:shadow-[0_24px_48px_rgba(25,28,29,0.10)]', 'transition-shadow duration-300 hover:shadow-[0_24px_48px_rgba(25,28,29,0.10)]',
)} )}
> >
{/* Geometric image placeholder */} <div className="relative w-full aspect-[16/9] md:aspect-[2/1] overflow-hidden">
<GeometricPlaceholder <Image
variant="featured" src={project.image}
cardVariant="default" alt={t(`work.projects.${project.i18nKey}.title`)}
className="w-full aspect-[16/9] md:aspect-[2/1]" fill
/> className="object-cover transition-transform duration-500 group-hover:scale-[1.03]"
sizes="(max-width: 768px) 100vw, 66vw"
/>
</div>
{/* Content */} {/* Content */}
<div className="flex flex-col flex-1 p-7 gap-4"> <div className="flex flex-col flex-1 p-7 gap-4">
@@ -432,13 +172,7 @@ function FeaturedCard({ project, readLabel, t }: { project: Project; readLabel:
// ─── Small Card ─────────────────────────────────────────────────────────────── // ─── Small Card ───────────────────────────────────────────────────────────────
const SLUG_TO_VARIANT: Record<string, 'nimara' | 'amador'> = {
'port-nimara': 'nimara',
'port-amador': 'amador',
};
function SmallCard({ project, readLabel, t }: { project: Project; readLabel: string; t: (key: string) => string }) { function SmallCard({ project, readLabel, t }: { project: Project; readLabel: string; t: (key: string) => string }) {
const cardVariant = SLUG_TO_VARIANT[project.slug] ?? 'nimara';
const tags = Array.from({ length: project.tagCount }, (_, i) => const tags = Array.from({ length: project.tagCount }, (_, i) =>
t(`work.projects.${project.i18nKey}.tags.${i}`), t(`work.projects.${project.i18nKey}.tags.${i}`),
); );
@@ -453,19 +187,14 @@ function SmallCard({ project, readLabel, t }: { project: Project; readLabel: str
'hover:shadow-subtle', 'hover:shadow-subtle',
)} )}
> >
{/* Geometric placeholder — grayscale to color on hover */}
<div className="relative overflow-hidden"> <div className="relative overflow-hidden">
<div <div className="relative w-full aspect-[16/7]">
className={cn( <Image
'transition-all duration-500', src={project.image}
'grayscale group-hover:grayscale-0', alt={t(`work.projects.${project.i18nKey}.title`)}
'opacity-80 group-hover:opacity-100', fill
)} className="object-cover transition-transform duration-500 group-hover:scale-[1.03]"
> sizes="(max-width: 768px) 100vw, 33vw"
<GeometricPlaceholder
variant="small"
cardVariant={cardVariant}
className="w-full aspect-[16/7]"
/> />
</div> </div>
</div> </div>
@@ -557,7 +286,16 @@ export default function SelectedWorks() {
const secondaryProjects = PROJECTS.filter((p) => !p.featured); const secondaryProjects = PROJECTS.filter((p) => !p.featured);
return ( return (
<section id="work" className="bg-surface-low py-20"> <section
id="work"
className="bg-surface-low py-20"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
>
<style>{` <style>{`
@keyframes dashed-drift { @keyframes dashed-drift {
0% { background-position: 0 0, 100% 0, 100% 100%, 0 100%; } 0% { background-position: 0 0, 100% 0, 100% 100%, 0 100%; }

View File

@@ -112,6 +112,12 @@ export default function TrustBar() {
<section <section
aria-label="Trust indicators" aria-label="Trust indicators"
className="relative bg-surface-low py-12" className="relative bg-surface-low py-12"
style={{
backgroundImage: [
'repeating-linear-gradient(0deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
'repeating-linear-gradient(90deg, rgba(25,28,29,0.02) 0px, rgba(25,28,29,0.02) 1px, transparent 1px, transparent 48px)',
].join(', '),
}}
> >
{/* Gradient bridge — blends hero into this section */} {/* Gradient bridge — blends hero into this section */}
<div <div

View File

@@ -1,6 +1,7 @@
'use client'; 'use client';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { Users, MessageCircle, BarChart3 } from 'lucide-react'; import { Users, MessageCircle, BarChart3 } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { import {
@@ -115,6 +116,7 @@ function AICapabilityCard({ capability }: { capability: AiCapability }) {
// ─── Component ───────────────────────────────────────────────────────────────── // ─── Component ─────────────────────────────────────────────────────────────────
export default function AILayer({ capabilities }: AILayerProps) { export default function AILayer({ capabilities }: AILayerProps) {
const t = useTranslations('servicesPage.ai')
return ( return (
<section <section
id="ai-automation" id="ai-automation"
@@ -137,7 +139,7 @@ export default function AILayer({ capabilities }: AILayerProps) {
variants={revealVariants} variants={revealVariants}
className="label-md text-primary mb-4" className="label-md text-primary mb-4"
> >
Intelligent Layer {t('eyebrow')}
</motion.span> </motion.span>
{/* Heading */} {/* Heading */}
@@ -146,7 +148,7 @@ export default function AILayer({ capabilities }: AILayerProps) {
variants={revealVariants} variants={revealVariants}
className="font-serif font-semibold tracking-headline text-white text-4xl md:text-5xl max-w-2xl leading-[1.1]" className="font-serif font-semibold tracking-headline text-white text-4xl md:text-5xl max-w-2xl leading-[1.1]"
> >
The AI Layer {t('title')}
</motion.h2> </motion.h2>
{/* Vertical line */} {/* Vertical line */}
@@ -163,7 +165,7 @@ export default function AILayer({ capabilities }: AILayerProps) {
className="font-serif italic text-xl leading-relaxed max-w-xl" className="font-serif italic text-xl leading-relaxed max-w-xl"
style={{ color: 'rgba(255,255,255,0.75)' }} style={{ color: 'rgba(255,255,255,0.75)' }}
> >
We build your ecosystem then make it intelligent. {t('subtitle')}
</motion.p> </motion.p>
{/* Context paragraph */} {/* Context paragraph */}
@@ -172,11 +174,7 @@ export default function AILayer({ capabilities }: AILayerProps) {
className="mt-5 text-[0.9375rem] leading-relaxed max-w-2xl" className="mt-5 text-[0.9375rem] leading-relaxed max-w-2xl"
style={{ color: 'rgba(255,255,255,0.5)' }} style={{ color: 'rgba(255,255,255,0.5)' }}
> >
AI is not a product we bolt on it is the connective tissue of {t('description')}
every system we build. Once your digital infrastructure is live, we
layer language models, automation pipelines, and predictive analytics
directly into your workflows, so your team operates with capabilities
that were previously reserved for organisations ten times your size.
</motion.p> </motion.p>
</motion.div> </motion.div>
@@ -202,7 +200,7 @@ export default function AILayer({ capabilities }: AILayerProps) {
className="mt-10 text-center text-xs uppercase tracking-widest" className="mt-10 text-center text-xs uppercase tracking-widest"
style={{ color: 'rgba(255,255,255,0.25)' }} style={{ color: 'rgba(255,255,255,0.25)' }}
> >
Compatible with your existing stack no data ever leaves your infrastructure {t('bottomNote')}
</motion.p> </motion.p>
</div> </div>

View File

@@ -1,6 +1,7 @@
'use client'; 'use client';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { ArrowRight } from 'lucide-react'; import { ArrowRight } from 'lucide-react';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { import {
@@ -27,6 +28,7 @@ const decorLineVariants = {
// ─── Component ───────────────────────────────────────────────────────────────── // ─── Component ─────────────────────────────────────────────────────────────────
export default function ServicesCTA() { export default function ServicesCTA() {
const t = useTranslations('servicesPage.cta')
return ( return (
<section <section
className="bg-surface-low py-24" className="bg-surface-low py-24"
@@ -90,23 +92,21 @@ export default function ServicesCTA() {
{/* Eyebrow */} {/* Eyebrow */}
<ScrollReveal variant="fadeUp"> <ScrollReveal variant="fadeUp">
<span className="label-md text-primary"> <span className="label-md text-primary">
Let&apos;s Talk {t('eyebrow')}
</span> </span>
</ScrollReveal> </ScrollReveal>
{/* Heading */} {/* Heading */}
<ScrollReveal variant="fadeUp" delay={0.08}> <ScrollReveal variant="fadeUp" delay={0.08}>
<h2 className="font-serif font-semibold tracking-headline text-on-surface text-4xl md:text-5xl max-w-2xl leading-[1.1]"> <h2 className="font-serif font-semibold tracking-headline text-on-surface text-4xl md:text-5xl max-w-2xl leading-[1.1]">
Ready to scope your project? {t('title')}
</h2> </h2>
</ScrollReveal> </ScrollReveal>
{/* Subtitle */} {/* Subtitle */}
<ScrollReveal variant="fadeUp" delay={0.16}> <ScrollReveal variant="fadeUp" delay={0.16}>
<p className="text-lg text-outline leading-relaxed max-w-xl"> <p className="text-lg text-outline leading-relaxed max-w-xl">
Use our interactive configurator to define your requirements, select {t('subtitle')}
your services, and generate a personalised project brief no
commitment required, just clarity.
</p> </p>
</ScrollReveal> </ScrollReveal>
@@ -119,14 +119,14 @@ export default function ServicesCTA() {
size="lg" size="lg"
arrow arrow
> >
Configure Your Project {t('primary')}
</Button> </Button>
<Button <Button
href="mailto:hello@letsbe.biz" href="mailto:hello@letsbe.biz"
variant="secondary" variant="secondary"
size="lg" size="lg"
> >
hello@letsbe.biz {t('email')}
</Button> </Button>
</div> </div>
</ScrollReveal> </ScrollReveal>
@@ -134,7 +134,7 @@ export default function ServicesCTA() {
{/* Reassurance */} {/* Reassurance */}
<ScrollReveal variant="fadeIn" delay={0.3}> <ScrollReveal variant="fadeIn" delay={0.3}>
<p className="text-sm text-outline/60 mt-1"> <p className="text-sm text-outline/60 mt-1">
No commitment required just a conversation about what&apos;s possible. {t('reassurance')}
</p> </p>
</ScrollReveal> </ScrollReveal>

View File

@@ -1,6 +1,7 @@
'use client'; 'use client';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { staggerContainer, revealVariants, viewportOnce } from '@/lib/animations'; import { staggerContainer, revealVariants, viewportOnce } from '@/lib/animations';
// ─── Animation variants ──────────────────────────────────────────────────────── // ─── Animation variants ────────────────────────────────────────────────────────
@@ -45,6 +46,7 @@ const ruleVariants = {
// ─── Component ───────────────────────────────────────────────────────────────── // ─── Component ─────────────────────────────────────────────────────────────────
export default function ServicesHero() { export default function ServicesHero() {
const t = useTranslations('servicesPage.hero')
return ( return (
<section <section
className="bg-surface pt-32 pb-20" className="bg-surface pt-32 pb-20"
@@ -62,7 +64,7 @@ export default function ServicesHero() {
variants={eyebrowVariants} variants={eyebrowVariants}
className="label-md text-primary mb-5" className="label-md text-primary mb-5"
> >
Our Capabilities {t('eyebrow')}
</motion.span> </motion.span>
{/* Headline */} {/* Headline */}
@@ -70,8 +72,8 @@ export default function ServicesHero() {
variants={headlineVariants} variants={headlineVariants}
className="font-serif font-semibold tracking-headline text-on-surface text-5xl md:text-6xl lg:text-7xl max-w-4xl leading-[1.05]" className="font-serif font-semibold tracking-headline text-on-surface text-5xl md:text-6xl lg:text-7xl max-w-4xl leading-[1.05]"
> >
Three Pillars of{' '} {t('title')}{' '}
<span className="text-gradient">Digital Excellence</span> <span className="text-gradient">{t('titleAccent')}</span>
</motion.h1> </motion.h1>
{/* Subtitle */} {/* Subtitle */}
@@ -79,9 +81,7 @@ export default function ServicesHero() {
variants={subtitleVariants} variants={subtitleVariants}
className="mt-6 text-lg text-outline leading-relaxed max-w-2xl" className="mt-6 text-lg text-outline leading-relaxed max-w-2xl"
> >
We design, build, and operate complete digital ecosystems from the {t('subtitle')}
first pixel to the server rack. Every discipline under one roof,
every deliverable built to a standard most agencies never attempt.
</motion.p> </motion.p>
{/* Decorative rule */} {/* Decorative rule */}

View File

@@ -1,4 +1,4 @@
export const locales = ['en', 'fr'] as const export const locales = ['en', 'fr', 'it', 'es'] as const
export const defaultLocale = 'en' as const export const defaultLocale = 'en' as const
export type Locale = (typeof locales)[number] export type Locale = (typeof locales)[number]

View File

@@ -1,4 +1,33 @@
{ {
"meta": {
"siteName": "LetsBe.",
"home": {
"title": "LetsBe. | Custom Web Design, Software & Digital Infrastructure",
"description": "Bespoke websites, purpose-built software, AI integration, and private infrastructure — designed, built, and managed by one dedicated team."
},
"about": {
"title": "About LetsBe. | Our Story & Approach",
"description": "An American-founded digital studio building custom websites, software, and platforms for businesses that care about quality."
},
"services": {
"title": "Services | LetsBe. — Web Design, Software & Infrastructure",
"description": "Custom web design, purpose-built software, AI automation, and private infrastructure — three pillars of digital excellence under one roof."
},
"work": {
"monaco-ocean": {
"title": "Monaco Ocean Protection Challenge | LetsBe.",
"description": "AI-powered judging and analytics platform for one of the Mediterranean's leading conservation events."
},
"port-nimara": {
"title": "Port Nimara — Maritime Digital Hub | LetsBe.",
"description": "Custom website and full CRM for lead management, berth assignment, and marina operations."
},
"port-amador": {
"title": "Port Amador — Premium Nautical Experience | LetsBe.",
"description": "Website and private digital infrastructure for a premium marina — cloud storage, email, and file management."
}
}
},
"nav": { "nav": {
"services": "Services", "services": "Services",
"configure": "Get Started", "configure": "Get Started",
@@ -9,47 +38,47 @@
"bookCall": "Book a Call" "bookCall": "Book a Call"
}, },
"hero": { "hero": {
"title": "Websites, software, and infrastructure - designed and built {accentWord} around you.", "title": "Your website. Your software. Your {accentWord} digital world.",
"accentWord": "entirely", "accentWord": "entire",
"subtitle": "We design custom websites, build purpose-built software, and run private infrastructure that you own and control. One team, from first pixel to final deployment.", "subtitle": "Custom websites, purpose-built software, and the infrastructure to run it all - designed, built, and managed by one dedicated team.",
"cta": "Start Your Project", "cta": "Start Your Project",
"ctaSecondary": "See Our Work", "ctaSecondary": "See Our Work",
"trust": "Trusted by businesses worldwide" "trust": "Trusted by businesses worldwide"
}, },
"trustBar": { "trustBar": {
"customBuilt": { "customBuilt": {
"title": "Built From Scratch", "title": "Designed From Scratch",
"description": "Every project designed and coded to your exact requirements. No templates, no shortcuts." "description": "No templates, no page builders. Every site is custom-designed and hand-built for your brand."
}, },
"privateInfra": { "privateInfra": {
"title": "You Own Everything", "title": "You Own Everything",
"description": "Private servers, your data, your tools - fully controlled and owned by you." "description": "Your code, your data, your servers. We build it, you own it - no lock-in, no surprises."
}, },
"aiPowered": { "aiPowered": {
"title": "One Team, End to End", "title": "One Team, Start to Finish",
"description": "Design, development, hosting, and support from a single dedicated team." "description": "No freelancer juggling. One team handles design, code, hosting, and support."
}, },
"rivieraBased": { "rivieraBased": {
"title": "AI Where It Matters", "title": "AI Built In",
"description": "Intelligent features and automation built directly into your systems." "description": "Intelligent features and automation woven directly into your website and software."
} }
}, },
"services": { "services": {
"eyebrow": "What We Do", "eyebrow": "What We Do",
"title": "Design. Build. Run.", "title": "Design. Build. Grow.",
"web": { "web": {
"title": "Websites & Web Apps", "title": "Web Design & Development",
"features": ["Custom Web Design", "Responsive Development", "SEO & Digital Marketing", "Content Management"] "features": ["Custom Website Design", "Responsive Development", "SEO & Performance", "Content Management"]
}, },
"systems": { "systems": {
"title": "Custom Software", "title": "Software & Platforms",
"features": ["Management Platforms", "CRMs & Business Tools", "Booking & Scheduling", "API Integrations"] "features": ["Business Management Tools", "CRMs & Dashboards", "Booking & Scheduling Systems", "API Integrations"]
}, },
"infrastructure": { "infrastructure": {
"title": "Private Infrastructure", "title": "Hosting & Infrastructure",
"features": ["Dedicated Servers", "Email & Cloud Storage", "Security & Encryption", "Monitoring & Support"] "features": ["Dedicated Servers", "Email & Cloud Storage", "Security & Monitoring", "Ongoing Support"]
}, },
"aiNarrative": "And when you're ready, we layer AI into everything - from intelligent features in your software to automation that connects all your tools." "aiNarrative": "And we layer AI into everything - from intelligent features in your website to automation that connects all your tools."
}, },
"configurator": { "configurator": {
"eyebrow": "Get Started", "eyebrow": "Get Started",
@@ -82,19 +111,19 @@
"services": { "services": {
"web": { "web": {
"title": "Web Design & Development", "title": "Web Design & Development",
"description": "Custom websites and web applications - designed from scratch, built for performance, and optimized for search engines." "description": "Custom websites and web applications - designed from scratch, built to perform, and optimized to get found."
}, },
"systems": { "systems": {
"title": "Custom Software", "title": "Custom Software",
"description": "Management platforms, CRMs, and business tools built to match exactly how your team works." "description": "CRMs, management platforms, and business tools built around the way your team actually works."
}, },
"infrastructure": { "infrastructure": {
"title": "Private Infrastructure", "title": "Private Infrastructure",
"description": "Dedicated servers with email, cloud storage, and business tools - fully owned and controlled by you." "description": "Dedicated hosting, email, cloud storage, and the infrastructure your business runs on - fully owned by you."
} }
}, },
"aiToggle": "Add AI Integration", "aiToggle": "Add AI Integration",
"aiDescription": "Intelligent features and automation built directly into your systems.", "aiDescription": "Practical AI features and automation built directly into your website and software.",
"aiTypes": { "aiTypes": {
"teammate": { "teammate": {
"title": "AI Teammate", "title": "AI Teammate",
@@ -173,7 +202,8 @@
"contactConfirmButton": "That's correct", "contactConfirmButton": "That's correct",
"reconnect": "Reconnect", "reconnect": "Reconnect",
"connectionLost": "Connection lost. Your conversation is saved.", "connectionLost": "Connection lost. Your conversation is saved.",
"briefComplete": "Brief complete" "briefComplete": "Brief complete",
"startConversation": "Start Conversation"
}, },
"privacy": "Your information is private and will never be shared.", "privacy": "Your information is private and will never be shared.",
"generateBrief": "Generate My Brief", "generateBrief": "Generate My Brief",
@@ -238,56 +268,204 @@
}, },
"comingSoonProjects": { "comingSoonProjects": {
"riviera": { "riviera": {
"title": "Confidential Riviera Project", "title": "Real Estate Management Platform",
"subtitle": "Coming Soon" "subtitle": "Coming Soon"
}, },
"sophia": { "sophia": {
"title": "Sophia Antipolis AI Startup", "title": "Enterprise SaaS — Austin, TX",
"subtitle": "Launching Q4" "subtitle": "Launching Q4"
} }
} }
}, },
"philosophy": { "philosophy": {
"eyebrow": "Why It Matters", "eyebrow": "Why Us",
"title": "Your tools should belong to you.", "title": "We do things differently.",
"subtitle": "Most businesses rent their digital life from a dozen different platforms. We think there's a better way - one where you own your data, control your infrastructure, and aren't locked into anyone's pricing page.", "subtitle": "Most agencies hand you a template and call it custom. We think your business deserves better - real design, real engineering, and a team that sticks around after launch.",
"ownership": { "ownership": {
"title": "Own Your Stack", "title": "Built to Be Yours",
"description": "We move you off scattered SaaS subscriptions and onto private infrastructure - servers, email, cloud storage, and tools that you control." "description": "Everything we build, you own. Your code, your data, your infrastructure - no lock-in, no platform dependencies, no surprises."
}, },
"craftsmanship": { "craftsmanship": {
"title": "No Shortcuts", "title": "Craft Over Convenience",
"description": "We write clean, hand-crafted code optimized for speed and search engines. No page builders, no bloated themes, no technical debt." "description": "We write clean, hand-built code optimized for speed and search engines. No page builders, no bloated themes, no shortcuts."
}, },
"oneTeam": { "oneTeam": {
"title": "One Relationship", "title": "One Relationship",
"description": "From the initial design through development to ongoing support - one team that knows your business inside and out." "description": "From first design to ongoing support - one team that knows your business inside and out. No handoffs, no telephone-game briefs."
}, },
"quote": "We build technology that works for your business - not the other way around.", "quote": "We build technology that works for your business - not the other way around.",
"foundedLocation": "Matt Ciaccio, Founder" "foundedLocation": "Matt Ciaccio, Founder"
}, },
"cta": { "cta": {
"eyebrow": "Let's Talk", "eyebrow": "Let's Talk",
"title": "Ready to build something?", "title": "Ready to build something great?",
"subtitle": "Tell us what you need. No pitch decks, no pressure - just a conversation about what's possible.", "subtitle": "Tell us what you're working on. No pitch decks, no pressure - just an honest conversation about what's possible.",
"cta": "Start Your Project", "cta": "Start Your Project",
"configure": "Start Your Project", "configure": "Start Your Project",
"email": "hello@letsbe.biz", "email": "hello@letsbe.biz",
"reassurance": "No commitment required." "reassurance": "No commitment required."
}, },
"footer": { "footer": {
"tagline": "Custom websites, software, and infrastructure for businesses that want to own their digital future.", "tagline": "Custom websites, software, and digital platforms - designed and built for businesses that refuse to settle.",
"location": "American-founded. Serving clients worldwide.", "location": "American-founded. Serving clients worldwide.",
"services": "Services", "services": "Services",
"studio": "Studio", "studio": "Studio",
"connect": "Connect", "connect": "Connect",
"serviceLinks": { "serviceLinks": {
"designDev": "Websites & Web Apps", "designDev": "Web Design & Development",
"customSystems": "Custom Software", "customSystems": "Custom Software",
"infrastructure": "Private Infrastructure", "infrastructure": "Private Infrastructure",
"aiAutomation": "AI Integration" "aiAutomation": "AI Integration"
}, },
"privacy": "Privacy Policy", "privacy": "Privacy Policy",
"terms": "Terms of Service" "terms": "Terms of Service"
},
"aboutPage": {
"hero": {
"eyebrow": "About LetsBe.",
"title": "Great businesses deserve great digital partners.",
"subtitle": "We design and build custom websites, software, and digital platforms for businesses that care about quality — and want a team that does too."
},
"story": {
"eyebrow": "Our Story",
"title": "Built for businesses like yours.",
"p1": "LetsBe. started with a simple belief: that ambitious businesses deserve digital tools as carefully considered as the work they do. Not templates. Not off-the-shelf platforms. Real design and engineering, built from scratch.",
"p2": "Our early clients were founders and operators who needed more than a website — they needed a technical partner who could design, build, host, and maintain everything under one roof. Those projects shaped how we work today.",
"p3": "We build platforms meant to be owned, not rented. We document everything, we hand over codebases that outlast the engagement, and we never lock clients into systems they can't leave. That's not a feature — it's how we think business should work.",
"quote": "Build fewer things. Build them better. Build them to last.",
"quoteAttrib": "LetsBe. founding principle"
},
"pillars": {
"eyebrow": "Our Beliefs",
"title": "What We Believe",
"subtitle": "Three principles behind every project we take on.",
"craftsmanship": {
"title": "Craftsmanship First",
"description": "The gap between a website that works and one that lasts is craft. We sweat the typography, the transitions, the performance, the edge cases. Every interface we ship is something we'd be proud to sign."
},
"oneTeam": {
"title": "One Team, Everything",
"description": "Design, development, hosting, infrastructure — one team, one point of contact, one standard of quality. No handoffs between agencies. No juggling freelancers. Just people who care about the whole thing."
},
"ownership": {
"title": "Built to Be Yours",
"description": "Everything we build, you own — the code, the data, the infrastructure. No vendor lock-in, no platform dependencies. We hand over work that outlasts the engagement."
}
},
"quote": {
"text": "We don't just build websites — we build the foundation your business runs on.",
"attrib": "LetsBe. founding philosophy"
},
"cta": {
"eyebrow": "Work With Us",
"title": "Let's build something together.",
"subtitle": "Whether you have a clear brief or just an early idea, we'd love to talk through what's possible.",
"primary": "Start your project",
"secondary": "Book a call"
}
},
"servicesPage": {
"hero": {
"eyebrow": "Our Services",
"title": "Everything your business",
"titleAccent": "needs online.",
"subtitle": "We design custom websites, build purpose-built software, and manage the infrastructure behind it all — one team, one standard of quality, nothing outsourced."
},
"pillars": [
{
"id": "design-development",
"numeral": "01",
"title": "Web Design & Development",
"description": "Your website shouldn't look like everyone else's — and it shouldn't be built like everyone else's either. We design and build custom websites and web applications from a blank canvas, crafting every layout, every interaction, and every page with intention. The result is fast, search-engine-friendly, and built to grow with your business. Whether you need a marketing site that converts, a web application your team relies on, or an e-commerce platform that scales — we build it from scratch, and we build it to last.",
"features": [
{ "icon": "Palette", "title": "Custom Design", "description": "Every layout, component, and interaction is designed for your brand. No themes, no templates, no shortcuts." },
{ "icon": "Globe", "title": "Web Applications", "description": "Modern, responsive applications built with the latest technologies — fast, reliable, and ready to scale." },
{ "icon": "ShoppingCart", "title": "E-Commerce", "description": "Custom storefronts, checkout flows, and multi-currency platforms built for serious online retail." },
{ "icon": "Zap", "title": "Performance & SEO", "description": "Fast load times, clean code, and search engine optimization built into the foundation — not bolted on after." }
]
},
{
"id": "custom-systems",
"numeral": "02",
"title": "Software & Platforms",
"description": "Off-the-shelf software makes assumptions about how your business works. We don't. When spreadsheets and generic tools stop cutting it, we build the exact system your team needs — designed around your workflow, not someone else's. From CRMs tailored to your sales process, to management platforms that replace three different subscriptions, to integrations that connect your existing tools — everything we build is yours, fully documented, and built to last.",
"features": [
{ "icon": "Database", "title": "CRM & Management Tools", "description": "Relationship and pipeline management built around how your team actually works — not how a generic platform thinks you should." },
{ "icon": "Code2", "title": "Custom Software", "description": "From booking platforms to internal tools to full SaaS products — purpose-built for your business." },
{ "icon": "GitBranch", "title": "Integrations & APIs", "description": "We connect your existing tools and build the bridges between systems so everything works together." },
{ "icon": "Wrench", "title": "Dashboards & Automation", "description": "Admin panels, reporting tools, and workflow automation that give your team an unfair advantage." }
]
},
{
"id": "infrastructure",
"numeral": "03",
"title": "Hosting & Infrastructure",
"description": "Your website and software need a home — and we think you should own it. We set up and manage dedicated servers, email, cloud storage, and all the infrastructure your business runs on. No shared hosting, no mysterious third-party dependencies. You know where your data lives, who has access, and that someone is watching the dashboard around the clock.",
"features": [
{ "icon": "Server", "title": "Dedicated Hosting", "description": "Private servers managed for your business — no shared hosting, no noisy neighbors, no surprises." },
{ "icon": "Shield", "title": "Your Data, Your Control", "description": "You own your data and know exactly where it lives. Full access, full transparency, no lock-in." },
{ "icon": "Lock", "title": "Security & Protection", "description": "Serious security, proactive monitoring, and protection built into your infrastructure from day one." },
{ "icon": "Settings", "title": "Monitoring & Support", "description": "Proactive monitoring, regular updates, and ongoing support so you never have to worry about uptime." }
]
}
],
"ai": {
"eyebrow": "Intelligent Layer",
"title": "AI Built Into Everything",
"subtitle": "Your platform, made smarter.",
"description": "We integrate AI directly into the websites and software we build for you. Not as a buzzword or an add-on — as practical features that save your team time and give your customers a better experience.",
"bottomNote": "Every AI feature is tailored to your business — your data stays on your servers",
"capabilities": [
{ "id": "ai-teammate", "title": "AI Teammate", "description": "An AI assistant built into your workflow — automates repetitive tasks, surfaces the info your team needs, and connects your tools." },
{ "id": "customer-facing-ai", "title": "Customer-Facing AI", "description": "Smart features for your customers — intelligent search, personalized recommendations, and conversational interfaces that work around the clock." },
{ "id": "data-intelligence", "title": "Data Intelligence", "description": "AI that helps you understand your data — automated reports, trend spotting, and insights you can actually act on." }
]
},
"cta": {
"eyebrow": "Let's Talk",
"title": "Ready to get started?",
"subtitle": "Walk through a few questions and we'll put together a project brief tailored to you — no commitment required, just clarity.",
"primary": "Start Your Project",
"email": "hello@letsbe.biz",
"reassurance": "No commitment required — just a conversation about what's possible."
}
},
"caseStudy": {
"labels": {
"challenge": "The Challenge",
"challengeHeading": "The problem we set out to solve",
"approach": "Our Approach",
"approachHeading": "How we thought about it",
"outcome": "The Outcome",
"outcomeHeading": "What we delivered",
"builtWith": "Built with",
"yourTurn": "Your Turn",
"ctaTitle": "Ready to build something like this?",
"ctaSubtitle": "Every project starts with a conversation. Tell us what you're working on and we'll figure out the best way to bring it to life.",
"ctaButton": "Start your project"
},
"projects": {
"monaco-ocean": {
"subtitle": "AI-Powered Judging & Analytics Platform",
"description": "A comprehensive judging and analytics system with advanced AI jury integration for one of the Mediterranean's most prestigious conservation events.",
"challenge": "The Monaco Ocean Protection Challenge needed a modern platform to manage submissions, coordinate judges across time zones, and provide AI-assisted evaluation of conservation proposals — all while maintaining the prestige and security expected of a Monaco institution.",
"approach": "We built a custom platform from the ground up using Next.js and a private PostgreSQL infrastructure. The AI jury module uses natural language processing to pre-screen submissions and generate summary reports, while human judges retain full control over final decisions.",
"outcome": "The platform processed over 200 submissions in its first season, reducing judge workload by 40% through AI-assisted pre-screening. The client praised the system's reliability and the elegance of its interface."
},
"port-nimara": {
"subtitle": "Maritime Digital Hub",
"description": "Scalable digital hub for maritime logistics.",
"challenge": "Port Nimara needed a modern digital presence that could serve as both a marketing website and an operational hub for berth inquiries, event management, and partner communications.",
"approach": "We designed and developed a performant Nuxt.js application with a headless CMS for content management, integrated with their existing maritime scheduling systems via custom API middleware.",
"outcome": "The new platform increased online berth inquiries by 3x and provided the port authority with real-time content management capabilities they previously lacked."
},
"port-amador": {
"subtitle": "Premium Nautical Experience",
"description": "Premium digital experience for elite nautical services.",
"challenge": "Port Amador required a luxury-grade digital experience that matched the exclusivity of their nautical services, with multi-language support and seamless booking integration.",
"approach": "We crafted a bespoke website with cinematic imagery, smooth animations, and an integrated booking flow. The site was built on modern web technologies with a focus on performance and SEO for the competitive luxury maritime market.",
"outcome": "The redesigned platform elevated Port Amador's digital presence to match their premium positioning, with a 60% improvement in page load times and significantly increased organic traffic."
}
}
} }
} }

471
src/i18n/messages/es.json Normal file
View File

@@ -0,0 +1,471 @@
{
"meta": {
"siteName": "LetsBe.",
"home": {
"title": "LetsBe. | Diseño Web a Medida, Software e Infraestructura Digital",
"description": "Sitios web a medida, software diseñado para ti, integración de IA e infraestructura privada — diseñados, desarrollados y gestionados por un único equipo dedicado."
},
"about": {
"title": "Sobre LetsBe. | Nuestra Historia y Enfoque",
"description": "Un estudio digital fundado en Estados Unidos que crea sitios web, software y plataformas a medida para empresas que apuestan por la calidad."
},
"services": {
"title": "Servicios | LetsBe. — Diseño Web, Software e Infraestructura",
"description": "Diseño web a medida, software dedicado, automatización con IA e infraestructura privada — tres pilares de excelencia digital bajo un mismo techo."
},
"work": {
"monaco-ocean": {
"title": "Monaco Ocean Protection Challenge | LetsBe.",
"description": "Plataforma de evaluación y análisis impulsada por IA para uno de los principales eventos de conservación del Mediterráneo."
},
"port-nimara": {
"title": "Port Nimara — Hub Digital Marítimo | LetsBe.",
"description": "Sitio web a medida y CRM completo para la gestión de clientes potenciales, asignación de amarres y operaciones de la marina."
},
"port-amador": {
"title": "Port Amador — Experiencia Náutica Premium | LetsBe.",
"description": "Sitio web e infraestructura digital privada para una marina premium — almacenamiento en la nube, correo electrónico y gestión de archivos."
}
}
},
"nav": {
"services": "Servicios",
"configure": "Empezar",
"process": "Proceso",
"work": "Proyectos",
"about": "Nosotros",
"startProject": "Iniciar un Proyecto",
"bookCall": "Reservar una Llamada"
},
"hero": {
"title": "Tu sitio web. Tu software. Tu mundo digital {accentWord}.",
"accentWord": "completo",
"subtitle": "Sitios web a medida, software diseñado para ti y la infraestructura para gestionarlo todo - diseñados, desarrollados y mantenidos por un único equipo dedicado.",
"cta": "Inicia tu Proyecto",
"ctaSecondary": "Ver Nuestros Proyectos",
"trust": "La confianza de empresas en todo el mundo"
},
"trustBar": {
"customBuilt": {
"title": "Diseñado Desde Cero",
"description": "Sin plantillas, sin constructores de páginas. Cada sitio se diseña a medida y se desarrolla a mano para tu marca."
},
"privateInfra": {
"title": "Todo es Tuyo",
"description": "Tu código, tus datos, tus servidores. Nosotros lo construimos, tú lo posees - sin ataduras, sin sorpresas."
},
"aiPowered": {
"title": "Un Equipo, De Principio a Fin",
"description": "Sin malabares con freelancers. Un solo equipo gestiona diseño, código, alojamiento y soporte."
},
"rivieraBased": {
"title": "IA Integrada",
"description": "Funcionalidades inteligentes y automatización integradas directamente en tu sitio web y software."
}
},
"services": {
"eyebrow": "Lo Que Hacemos",
"title": "Diseñar. Desarrollar. Crecer.",
"web": {
"title": "Diseño y Desarrollo Web",
"features": ["Diseño Web a Medida", "Desarrollo Responsive", "SEO y Rendimiento", "Gestión de Contenidos"]
},
"systems": {
"title": "Software y Plataformas",
"features": ["Herramientas de Gestión Empresarial", "CRM y Paneles de Control", "Sistemas de Reservas", "Integraciones API"]
},
"infrastructure": {
"title": "Alojamiento e Infraestructura",
"features": ["Servidores Dedicados", "Email y Almacenamiento en la Nube", "Seguridad y Monitorización", "Soporte Continuo"]
},
"aiNarrative": "Y aplicamos IA en todo lo que hacemos - desde funcionalidades inteligentes en tu sitio web hasta la automatización que conecta todas tus herramientas."
},
"configurator": {
"eyebrow": "Empezar",
"title": "Cuéntanos qué necesitas.",
"description": "Responde a unas pocas preguntas y prepararemos un briefing de proyecto personalizado para ti.",
"step1": {
"title": "¿Qué necesitas?",
"subtitle": "Selecciona los servicios que se adaptan a tu proyecto."
},
"step2": {
"title": "Cuéntanos sobre tu proyecto",
"subtitle": "Algunos detalles nos ayudan a preparar el enfoque adecuado."
},
"step3": {
"title": "Casi listo",
"subtitle": "Revisa tus selecciones e indícanos cómo contactarte."
},
"complete": {
"title": "Tu briefing de proyecto está listo",
"subtitle": "Revisa tu bandeja de entrada - hemos enviado un briefing detallado a {email}",
"nextStep": "Siguiente paso: hablemos de tu briefing",
"bookSubtitle": "Reserva una llamada gratuita de 30 minutos para hablar de tu proyecto y los próximos pasos.",
"bookCall": "Reservar una Llamada",
"briefPreview": "Tu briefing de proyecto",
"reachDirectly": "O contáctanos directamente en"
},
"howItWorks": "Cómo funciona",
"noCommitment": "Sin compromiso",
"selectService": "Selecciona al menos un servicio para continuar",
"services": {
"web": {
"title": "Diseño y Desarrollo Web",
"description": "Sitios web y aplicaciones a medida - diseñados desde cero, construidos para rendir y optimizados para que te encuentren."
},
"systems": {
"title": "Software a Medida",
"description": "CRM, plataformas de gestión y herramientas empresariales creadas en torno a cómo trabaja realmente tu equipo."
},
"infrastructure": {
"title": "Infraestructura Privada",
"description": "Alojamiento dedicado, email, almacenamiento en la nube y la infraestructura sobre la que funciona tu negocio - totalmente tuya."
}
},
"aiToggle": "Añadir Integración de IA",
"aiDescription": "Funcionalidades de IA prácticas y automatización integradas directamente en tu sitio web y software.",
"aiTypes": {
"teammate": {
"title": "IA como Compañero de Equipo",
"description": "Un asistente de IA interno que ayuda a tu equipo a trabajar más rápido - automatiza tareas, responde preguntas, conecta tus herramientas."
},
"customer-facing": {
"title": "IA de Cara al Cliente",
"description": "Funcionalidades de IA con las que interactúan tus clientes - búsqueda inteligente, recomendaciones personalizadas, interfaces conversacionales."
},
"data-intelligence": {
"title": "Inteligencia de Datos",
"description": "IA que analiza los datos de tu negocio para extraer insights, tendencias y recomendaciones accionables."
},
"notsure": {
"title": "Aún No Estoy Seguro",
"description": "Sin problema - exploraremos juntos el mejor enfoque de IA durante la fase de descubrimiento."
}
},
"industries": {
"maritime": "Náutica / Yachting",
"hospitality": "Hostelería",
"technology": "Tecnología",
"realestate": "Inmobiliaria",
"finance": "Finanzas",
"ngo": "ONG / Sin Ánimo de Lucro",
"other": "Otro"
},
"timelines": {
"asap": "Lo antes posible",
"1-3months": "13 meses",
"3-6months": "36 meses",
"exploring": "Solo explorando"
},
"fields": {
"industry": "Tu sector",
"scope": "¿Qué quieres conseguir?",
"scopeOptional": "(opcional)",
"scopePlaceholder": "p. ej. Necesitamos reemplazar nuestro sistema de reservas actual y mejorar la experiencia del cliente…",
"timeline": "Plazo",
"name": "Tu nombre",
"company": "Empresa",
"email": "Correo electrónico",
"phone": "Teléfono",
"phoneOptional": "(opcional)",
"contactPreference": "Método de contacto preferido",
"contactEmail": "Email",
"contactPhone": "Teléfono",
"contactWhatsapp": "WhatsApp",
"currentSiteUrl": "Sitio web actual",
"currentSiteUrlOptional": "(opcional)",
"currentSiteUrlPlaceholder": "https://tusitio.com",
"currentSiteThoughts": "Opinión sobre tu sitio actual",
"currentSiteThoughtsPlaceholder": "Qué funciona, qué no, qué te gustaría cambiar..."
},
"summary": {
"heading": "Tus selecciones",
"aiEnhancement": "Mejora con IA"
},
"generating": "Generando",
"generatingSteps": {
"preparingBrief": "Preparando tu briefing",
"analyzingSite": "Analizando tu sitio web actual",
"runningAudit": "Ejecutando auditoría de rendimiento",
"generatingBrief": "Generando tu briefing personalizado"
},
"voice": {
"agentName": "Asistente de proyectos de LetsBe",
"endConversation": "Finalizar Conversación",
"analyzingSite": "Analizando tu sitio...",
"connecting": "Conectando...",
"mute": "Silenciar",
"unmute": "Activar micrófono",
"generatingBrief": "Generando tu briefing...",
"contactConfirm": "¿Es esto correcto?",
"contactEdit": "Editar",
"contactConfirmButton": "Sí, es correcto",
"reconnect": "Reconectar",
"connectionLost": "Conexión perdida. Tu conversación está guardada.",
"briefComplete": "Briefing completado",
"startConversation": "Iniciar conversación"
},
"privacy": "Tu información es privada y nunca será compartida.",
"generateBrief": "Generar Mi Briefing",
"nextStep": "Siguiente Paso",
"back": "Volver",
"startOver": "Empezar de Nuevo",
"errors": {
"general": "Algo salió mal. Por favor, inténtalo de nuevo.",
"network": "Error de red. Comprueba tu conexión e inténtalo de nuevo."
}
},
"discovery": {
"eyebrow": "Vamos a Descubrirlo",
"title": "¿No sabes por dónde empezar?",
"description": "Cuéntanos en qué estás pensando y lo resolveremos juntos. Recibirás un briefing personalizado al final.",
"cta": "Hablemos",
"privacy": "Las conversaciones de voz no se graban ni se almacenan."
},
"process": {
"eyebrow": "Cómo Trabajamos",
"title": "De la Idea al Lanzamiento",
"steps": {
"discovery": {
"title": "Descubrimiento",
"description": "Conocemos tu negocio, tus usuarios y lo que realmente necesitas construir."
},
"strategy": {
"title": "Estrategia y Planificación",
"description": "Definimos la arquitectura, elegimos las herramientas adecuadas y trazamos el plan de desarrollo."
},
"build": {
"title": "Diseño y Desarrollo",
"description": "Tu proyecto toma forma - píxel a píxel, función a función."
},
"launch": {
"title": "Lanzamiento y Soporte",
"description": "Desplegamos, monitorizamos y mantenemos todo funcionando sin problemas."
}
}
},
"work": {
"eyebrow": "Nuestros Proyectos",
"title": "Proyectos Que Hemos Construido",
"readCaseStudy": "Ver Proyecto",
"comingSoon": "Próximamente",
"projects": {
"monaco": {
"title": "Monaco Ocean Protection Challenge",
"description": "Plataforma de evaluación y análisis con filtrado por IA, asignación automática de jueces y revisión inteligente de proyectos para uno de los principales eventos de conservación del Mediterráneo.",
"tags": ["Software a Medida", "Integración de IA"]
},
"portNimara": {
"title": "Port Nimara",
"description": "Sitio web a medida y CRM completo para la gestión de clientes potenciales, asignación de amarres y operaciones de la marina.",
"tags": ["Sitio Web", "Software a Medida"]
},
"portAmador": {
"title": "Port Amador",
"description": "Sitio web e infraestructura digital privada - almacenamiento en la nube, email y gestión de archivos para una marina premium.",
"tags": ["Sitio Web", "Infraestructura"]
}
},
"comingSoonProjects": {
"riviera": {
"title": "Plataforma de Gestión Inmobiliaria",
"subtitle": "Próximamente"
},
"sophia": {
"title": "SaaS Empresarial — Austin, TX",
"subtitle": "Lanzamiento en Q4"
}
}
},
"philosophy": {
"eyebrow": "Por Qué Nosotros",
"title": "Hacemos las cosas de otra manera.",
"subtitle": "La mayoría de las agencias te dan una plantilla y lo llaman personalizado. Creemos que tu negocio merece algo mejor - diseño real, ingeniería real y un equipo que sigue ahí después del lanzamiento.",
"ownership": {
"title": "Construido para que sea Tuyo",
"description": "Todo lo que construimos es tuyo. Tu código, tus datos, tu infraestructura - sin ataduras, sin dependencias de plataformas, sin sorpresas."
},
"craftsmanship": {
"title": "Artesanía por Encima de la Comodidad",
"description": "Escribimos código limpio, hecho a mano y optimizado para velocidad y motores de búsqueda. Sin constructores de páginas, sin temas sobrecargados, sin atajos."
},
"oneTeam": {
"title": "Una Sola Relación",
"description": "Desde el primer diseño hasta el soporte continuo - un equipo que conoce tu negocio de arriba abajo. Sin traspasos, sin briefs perdidos por el camino."
},
"quote": "Construimos tecnología que trabaja para tu negocio - no al revés.",
"foundedLocation": "Matt Ciaccio, Fundador"
},
"cta": {
"eyebrow": "Hablemos",
"title": "¿Listo para construir algo grande?",
"subtitle": "Cuéntanos en qué estás trabajando. Sin presentaciones, sin presión - solo una conversación honesta sobre lo que es posible.",
"cta": "Inicia tu Proyecto",
"configure": "Inicia tu Proyecto",
"email": "hello@letsbe.biz",
"reassurance": "Sin compromiso."
},
"footer": {
"tagline": "Sitios web, software y plataformas digitales a medida - diseñados y desarrollados para empresas que se niegan a conformarse con menos.",
"location": "Fundado en Estados Unidos. Al servicio de clientes en todo el mundo.",
"services": "Servicios",
"studio": "Studio",
"connect": "Contacto",
"serviceLinks": {
"designDev": "Diseño y Desarrollo Web",
"customSystems": "Software a Medida",
"infrastructure": "Infraestructura Privada",
"aiAutomation": "Integración de IA"
},
"privacy": "Política de Privacidad",
"terms": "Términos de Servicio"
},
"aboutPage": {
"hero": {
"eyebrow": "Sobre LetsBe.",
"title": "Las grandes empresas merecen grandes socios digitales.",
"subtitle": "Diseñamos y desarrollamos sitios web, software y plataformas digitales a medida para empresas que apuestan por la calidad — y que buscan un equipo que haga lo mismo."
},
"story": {
"eyebrow": "Nuestra Historia",
"title": "Construido para empresas como la tuya.",
"p1": "LetsBe. nació de una convicción sencilla: las empresas ambiciosas merecen herramientas digitales tan cuidadas como el trabajo que realizan. No plantillas. No plataformas genéricas. Diseño e ingeniería reales, construidos desde cero.",
"p2": "Nuestros primeros clientes eran fundadores y operadores que necesitaban algo más que un sitio web — un socio técnico capaz de diseñar, desarrollar, alojar y mantener todo bajo un mismo techo. Esos proyectos dieron forma a cómo trabajamos hoy.",
"p3": "Construimos plataformas pensadas para ser poseídas, no alquiladas. Documentamos todo, entregamos bases de código que perduran más allá del proyecto y nunca atamos a los clientes a sistemas que no pueden abandonar. Eso no es una característica — es cómo creemos que debería funcionar el negocio.",
"quote": "Construir menos cosas. Construirlas mejor. Construirlas para que duren.",
"quoteAttrib": "Principio fundacional de LetsBe."
},
"pillars": {
"eyebrow": "Nuestras Convicciones",
"title": "En Qué Creemos",
"subtitle": "Tres principios detrás de cada proyecto que emprendemos.",
"craftsmanship": {
"title": "La Artesanía Primero",
"description": "La diferencia entre un sitio web que funciona y uno que perdura es la artesanía. Nos preocupamos por la tipografía, las transiciones, el rendimiento, los casos límite. Cada interfaz que entregamos es algo de lo que nos enorgullecemos firmar."
},
"oneTeam": {
"title": "Un Equipo, Todo",
"description": "Diseño, desarrollo, alojamiento, infraestructura — un solo equipo, un solo punto de contacto, un solo estándar de calidad. Sin traspasos entre agencias. Sin malabarismos con freelancers. Solo personas que se preocupan por el conjunto."
},
"ownership": {
"title": "Construido para que sea Tuyo",
"description": "Todo lo que construimos es tuyo — el código, los datos, la infraestructura. Sin vendor lock-in, sin dependencias de plataformas. Entregamos trabajo que perdura más allá del proyecto."
}
},
"quote": {
"text": "No solo construimos sitios web — construimos los cimientos sobre los que funciona tu negocio.",
"attrib": "Filosofía fundacional de LetsBe."
},
"cta": {
"eyebrow": "Trabaja Con Nosotros",
"title": "Construyamos algo juntos.",
"subtitle": "Tanto si tienes un briefing claro como si solo tienes una idea inicial, nos encantaría hablar sobre lo que es posible.",
"primary": "Inicia tu proyecto",
"secondary": "Reservar una llamada"
}
},
"servicesPage": {
"hero": {
"eyebrow": "Nuestros Servicios",
"title": "Todo lo que tu negocio",
"titleAccent": "necesita en línea.",
"subtitle": "Diseñamos sitios web a medida, desarrollamos software dedicado y gestionamos la infraestructura que lo sustenta todo — un solo equipo, un solo estándar de calidad, nada externalizado."
},
"pillars": [
{
"id": "design-development",
"numeral": "01",
"title": "Diseño y Desarrollo Web",
"description": "Tu sitio web no debería parecerse al de todos los demás — ni estar construido como el de todos los demás. Diseñamos y desarrollamos sitios web y aplicaciones web desde un lienzo en blanco, creando cada layout, cada interacción y cada página con intención. El resultado es rápido, amigable para los motores de búsqueda y construido para crecer con tu negocio. Tanto si necesitas un sitio de marketing que convierte, una aplicación web en la que tu equipo confía, o una plataforma de e-commerce que escala — lo construimos desde cero, y lo construimos para que dure.",
"features": [
{ "icon": "Palette", "title": "Diseño a Medida", "description": "Cada layout, componente e interacción se diseña para tu marca. Sin temas, sin plantillas, sin atajos." },
{ "icon": "Globe", "title": "Aplicaciones Web", "description": "Aplicaciones modernas y responsive desarrolladas con las últimas tecnologías — rápidas, fiables y listas para escalar." },
{ "icon": "ShoppingCart", "title": "E-Commerce", "description": "Tiendas personalizadas, flujos de pago y plataformas multi-divisa construidas para el comercio online serio." },
{ "icon": "Zap", "title": "Rendimiento y SEO", "description": "Tiempos de carga rápidos, código limpio y optimización para motores de búsqueda integrados en los cimientos — no añadidos después." }
]
},
{
"id": "custom-systems",
"numeral": "02",
"title": "Software y Plataformas",
"description": "El software genérico hace suposiciones sobre cómo funciona tu negocio. Nosotros no. Cuando las hojas de cálculo y las herramientas genéricas dejan de ser suficientes, construimos exactamente el sistema que tu equipo necesita — diseñado en torno a tu flujo de trabajo, no al de otra persona. Desde CRM adaptados a tu proceso de ventas, hasta plataformas de gestión que reemplazan tres suscripciones distintas, pasando por integraciones que conectan tus herramientas existentes — todo lo que construimos es tuyo, completamente documentado y construido para durar.",
"features": [
{ "icon": "Database", "title": "CRM y Herramientas de Gestión", "description": "Gestión de relaciones y pipeline construida en torno a cómo trabaja realmente tu equipo — no a cómo cree una plataforma genérica que deberías trabajar." },
{ "icon": "Code2", "title": "Software a Medida", "description": "Desde plataformas de reservas hasta herramientas internas o productos SaaS completos — diseñados específicamente para tu negocio." },
{ "icon": "GitBranch", "title": "Integraciones y APIs", "description": "Conectamos tus herramientas existentes y construimos los puentes entre sistemas para que todo funcione conjuntamente." },
{ "icon": "Wrench", "title": "Paneles y Automatización", "description": "Paneles de administración, herramientas de informes y automatización de flujos de trabajo que le dan a tu equipo una ventaja competitiva." }
]
},
{
"id": "infrastructure",
"numeral": "03",
"title": "Alojamiento e Infraestructura",
"description": "Tu sitio web y tu software necesitan un hogar — y creemos que deberías ser tú quien lo posea. Configuramos y gestionamos servidores dedicados, correo electrónico, almacenamiento en la nube y toda la infraestructura sobre la que funciona tu negocio. Sin alojamiento compartido, sin misteriosas dependencias de terceros. Sabes dónde viven tus datos, quién tiene acceso y que alguien está vigilando el panel de control las 24 horas del día.",
"features": [
{ "icon": "Server", "title": "Alojamiento Dedicado", "description": "Servidores privados gestionados para tu negocio — sin alojamiento compartido, sin vecinos molestos, sin sorpresas." },
{ "icon": "Shield", "title": "Tus Datos, Tu Control", "description": "Posees tus datos y sabes exactamente dónde están. Acceso completo, total transparencia, sin lock-in." },
{ "icon": "Lock", "title": "Seguridad y Protección", "description": "Seguridad seria, monitorización proactiva y protección integrada en tu infraestructura desde el primer día." },
{ "icon": "Settings", "title": "Monitorización y Soporte", "description": "Monitorización proactiva, actualizaciones regulares y soporte continuo para que nunca tengas que preocuparte por el tiempo de actividad." }
]
}
],
"ai": {
"eyebrow": "Capa Inteligente",
"title": "IA Integrada en Todo",
"subtitle": "Tu plataforma, más inteligente.",
"description": "Integramos IA directamente en los sitios web y el software que construimos para ti. No como palabra de moda ni como complemento — como funcionalidades prácticas que ahorran tiempo a tu equipo y ofrecen a tus clientes una mejor experiencia.",
"bottomNote": "Cada funcionalidad de IA se adapta a tu negocio — tus datos permanecen en tus servidores",
"capabilities": [
{ "id": "ai-teammate", "title": "IA como Compañero de Equipo", "description": "Un asistente de IA integrado en tu flujo de trabajo — automatiza tareas repetitivas, saca a la superficie la información que tu equipo necesita y conecta tus herramientas." },
{ "id": "customer-facing-ai", "title": "IA de Cara al Cliente", "description": "Funcionalidades inteligentes para tus clientes — búsqueda inteligente, recomendaciones personalizadas e interfaces conversacionales disponibles las 24 horas." },
{ "id": "data-intelligence", "title": "Inteligencia de Datos", "description": "IA que te ayuda a entender tus datos — informes automatizados, detección de tendencias e insights sobre los que puedes actuar de verdad." }
]
},
"cta": {
"eyebrow": "Hablemos",
"title": "¿Listo para empezar?",
"subtitle": "Responde a unas pocas preguntas y prepararemos un briefing de proyecto personalizado para ti — sin compromiso, solo claridad.",
"primary": "Inicia tu Proyecto",
"email": "hello@letsbe.biz",
"reassurance": "Sin compromiso — solo una conversación sobre lo que es posible."
}
},
"caseStudy": {
"labels": {
"challenge": "El Reto",
"challengeHeading": "El problema que nos propusimos resolver",
"approach": "Nuestro Enfoque",
"approachHeading": "Cómo lo pensamos",
"outcome": "El Resultado",
"outcomeHeading": "Lo que entregamos",
"builtWith": "Desarrollado con",
"yourTurn": "Tu Turno",
"ctaTitle": "¿Listo para construir algo así?",
"ctaSubtitle": "Cada proyecto empieza con una conversación. Cuéntanos en qué estás trabajando y encontraremos la mejor manera de hacerlo realidad.",
"ctaButton": "Inicia tu proyecto"
},
"projects": {
"monaco-ocean": {
"subtitle": "Plataforma de Evaluación y Análisis con IA",
"description": "Un sistema completo de evaluación y análisis con integración avanzada de jurado de IA para uno de los eventos de conservación más prestigiosos del Mediterráneo.",
"challenge": "El Monaco Ocean Protection Challenge necesitaba una plataforma moderna para gestionar las candidaturas, coordinar jueces en distintas zonas horarias y proporcionar una evaluación asistida por IA de las propuestas de conservación — todo ello manteniendo el prestigio y la seguridad que se esperan de una institución monegasca.",
"approach": "Construimos una plataforma personalizada desde cero usando Next.js y una infraestructura PostgreSQL privada. El módulo de jurado de IA utiliza procesamiento del lenguaje natural para pre-seleccionar candidaturas y generar informes de resumen, mientras que los jueces humanos conservan el control total sobre las decisiones finales.",
"outcome": "La plataforma procesó más de 200 candidaturas en su primera temporada, reduciendo la carga de trabajo de los jueces en un 40% gracias a la pre-selección asistida por IA. El cliente elogió la fiabilidad del sistema y la elegancia de su interfaz."
},
"port-nimara": {
"subtitle": "Hub Digital Marítimo",
"description": "Hub digital escalable para logística marítima.",
"challenge": "Port Nimara necesitaba una presencia digital moderna que pudiera funcionar tanto como sitio de marketing como hub operativo para consultas de amarres, gestión de eventos y comunicaciones con socios.",
"approach": "Diseñamos y desarrollamos una aplicación Nuxt.js de alto rendimiento con un CMS headless para la gestión de contenidos, integrada con sus sistemas de planificación marítima existentes a través de middleware API personalizado.",
"outcome": "La nueva plataforma triplicó las consultas de amarres en línea y proporcionó a la autoridad portuaria capacidades de gestión de contenidos en tiempo real de las que antes carecía."
},
"port-amador": {
"subtitle": "Experiencia Náutica Premium",
"description": "Experiencia digital premium para servicios náuticos de élite.",
"challenge": "Port Amador requería una experiencia digital de categoría lujo que estuviera a la altura de la exclusividad de sus servicios náuticos, con soporte multiidioma e integración de reservas sin fricciones.",
"approach": "Creamos un sitio web a medida con imágenes cinematográficas, animaciones fluidas y un flujo de reservas integrado. El sitio se construyó sobre tecnologías web modernas con un enfoque en el rendimiento y el SEO para el competitivo mercado marítimo de lujo.",
"outcome": "La plataforma rediseñada elevó la presencia digital de Port Amador a su posicionamiento premium, con una mejora del 60% en los tiempos de carga de las páginas y un aumento significativo del tráfico orgánico."
}
}
}
}

View File

@@ -1,4 +1,33 @@
{ {
"meta": {
"siteName": "LetsBe.",
"home": {
"title": "LetsBe. | Design Web Sur Mesure, Logiciels & Infrastructure Digitale",
"description": "Sites web sur mesure, logiciels dédiés, intégration IA et infrastructure privée — conçus, développés et gérés par une seule équipe."
},
"about": {
"title": "À Propos de LetsBe. | Notre Histoire & Approche",
"description": "Un studio digital fondé aux États-Unis, créant des sites web, logiciels et plateformes sur mesure pour les entreprises exigeantes."
},
"services": {
"title": "Services | LetsBe. — Design Web, Logiciels & Infrastructure",
"description": "Design web sur mesure, logiciels dédiés, automatisation IA et infrastructure privée — trois piliers d'excellence digitale sous un même toit."
},
"work": {
"monaco-ocean": {
"title": "Monaco Ocean Protection Challenge | LetsBe.",
"description": "Plateforme de jugement et d'analyse propulsée par l'IA pour l'un des événements de conservation majeurs de la Méditerranée."
},
"port-nimara": {
"title": "Port Nimara — Hub Digital Maritime | LetsBe.",
"description": "Site web sur mesure et CRM complet pour la gestion des prospects, l'attribution des places et les opérations de la marina."
},
"port-amador": {
"title": "Port Amador — Expérience Nautique Premium | LetsBe.",
"description": "Site web et infrastructure digitale privée pour une marina premium — stockage cloud, email et gestion de fichiers."
}
}
},
"nav": { "nav": {
"services": "Services", "services": "Services",
"configure": "Démarrer", "configure": "Démarrer",
@@ -9,47 +38,47 @@
"bookCall": "Réserver un Appel" "bookCall": "Réserver un Appel"
}, },
"hero": { "hero": {
"title": "Sites web, logiciels et infrastructure - conçus et développés {accentWord} autour de vous.", "title": "Votre site web. Vos logiciels. {accentWord} votre univers digital.",
"accentWord": "entièrement", "accentWord": "Tout",
"subtitle": "Nous concevons des sites web sur mesure, développons des logiciels dédiés et gérons une infrastructure privée qui vous appartient. Une seule équipe, du premier pixel au déploiement final.", "subtitle": "Sites web sur mesure, logiciels dédiés et l'infrastructure pour tout faire tourner - conçus, développés et gérés par une seule équipe.",
"cta": "Démarrer Votre Projet", "cta": "Démarrer Votre Projet",
"ctaSecondary": "Voir Nos Réalisations", "ctaSecondary": "Voir Nos Réalisations",
"trust": "La confiance d'entreprises dans le monde entier" "trust": "La confiance d'entreprises dans le monde entier"
}, },
"trustBar": { "trustBar": {
"customBuilt": { "customBuilt": {
"title": "Conçu Sur Mesure", "title": "Conçu De Zéro",
"description": "Chaque projet est designé et codé selon vos besoins exacts. Pas de templates, pas de raccourcis." "description": "Pas de templates, pas de constructeurs de pages. Chaque site est conçu sur mesure et développé à la main pour votre marque."
}, },
"privateInfra": { "privateInfra": {
"title": "Tout Vous Appartient", "title": "Tout Vous Appartient",
"description": "Serveurs privés, vos données, vos outils - entièrement contrôlés et détenus par vous." "description": "Votre code, vos données, vos serveurs. On construit, vous possédez - pas de verrouillage, pas de surprises."
}, },
"aiPowered": { "aiPowered": {
"title": "Une Seule Équipe", "title": "Une Équipe, De A à Z",
"description": "Design, développement, hébergement et support par une seule équipe dédiée." "description": "Fini le jonglage entre freelances. Une seule équipe gère design, code, hébergement et support."
}, },
"rivieraBased": { "rivieraBased": {
"title": "L'IA Là Où Ça Compte", "title": "IA Intégrée",
"description": "Fonctionnalités intelligentes et automatisation intégrées directement dans vos systèmes." "description": "Fonctionnalités intelligentes et automatisation intégrées directement dans votre site web et vos logiciels."
} }
}, },
"services": { "services": {
"eyebrow": "Ce Que Nous Faisons", "eyebrow": "Ce Que Nous Faisons",
"title": "Concevoir. Développer. Héberger.", "title": "Concevoir. Développer. Grandir.",
"web": { "web": {
"title": "Sites Web & Applications", "title": "Design & Développement Web",
"features": ["Design Web Sur Mesure", "Développement Responsive", "SEO & Marketing Digital", "Gestion de Contenu"] "features": ["Design de Site Sur Mesure", "Développement Responsive", "SEO & Performance", "Gestion de Contenu"]
}, },
"systems": { "systems": {
"title": "Logiciels Sur Mesure", "title": "Logiciels & Plateformes",
"features": ["Plateformes de Gestion", "CRM & Outils Métier", "Réservation & Planning", "Intégrations API"] "features": ["Outils de Gestion", "CRM & Tableaux de Bord", "Systèmes de Réservation", "Intégrations API"]
}, },
"infrastructure": { "infrastructure": {
"title": "Infrastructure Privée", "title": "Hébergement & Infrastructure",
"features": ["Serveurs Dédiés", "Email & Stockage Cloud", "Sécurité & Chiffrement", "Monitoring & Support"] "features": ["Serveurs Dédiés", "Email & Stockage Cloud", "Sécurité & Monitoring", "Support Continu"]
}, },
"aiNarrative": "Et quand vous êtes prêt, nous intégrons l'IA dans l'ensemble - des fonctionnalités intelligentes dans vos logiciels à l'automatisation qui connecte tous vos outils." "aiNarrative": "Et nous intégrons l'IA dans tout ce que nous faisons - des fonctionnalités intelligentes dans votre site web à l'automatisation qui connecte tous vos outils."
}, },
"configurator": { "configurator": {
"eyebrow": "Démarrer", "eyebrow": "Démarrer",
@@ -82,19 +111,19 @@
"services": { "services": {
"web": { "web": {
"title": "Design & Développement Web", "title": "Design & Développement Web",
"description": "Sites web et applications sur mesure - conçus de zéro, optimisés pour la performance et le référencement." "description": "Sites web et applications sur mesure - conçus de zéro, performants et optimisés pour être trouvés."
}, },
"systems": { "systems": {
"title": "Logiciels Sur Mesure", "title": "Logiciels Sur Mesure",
"description": "Plateformes de gestion, CRM et outils métier conçus pour correspondre exactement à votre façon de travailler." "description": "CRM, plateformes de gestion et outils métier conçus autour de la façon dont votre équipe travaille vraiment."
}, },
"infrastructure": { "infrastructure": {
"title": "Infrastructure Privée", "title": "Infrastructure Privée",
"description": "Serveurs dédiés avec email, stockage cloud et outils métier - entièrement détenus et contrôlés par vous." "description": "Hébergement dédié, email, stockage cloud et l'infrastructure sur laquelle votre entreprise fonctionne - entièrement à vous."
} }
}, },
"aiToggle": "Ajouter l'Intégration IA", "aiToggle": "Ajouter l'Intégration IA",
"aiDescription": "Fonctionnalités intelligentes et automatisation intégrées directement dans vos systèmes.", "aiDescription": "Fonctionnalités IA pratiques et automatisation intégrées directement dans votre site web et vos logiciels.",
"aiTypes": { "aiTypes": {
"teammate": { "teammate": {
"title": "IA Coéquipier", "title": "IA Coéquipier",
@@ -173,7 +202,8 @@
"contactConfirmButton": "C'est correct", "contactConfirmButton": "C'est correct",
"reconnect": "Reconnecter", "reconnect": "Reconnecter",
"connectionLost": "Connexion perdue. Votre conversation est sauvegardée.", "connectionLost": "Connexion perdue. Votre conversation est sauvegardée.",
"briefComplete": "Brief terminé" "briefComplete": "Brief terminé",
"startConversation": "Démarrer la conversation"
}, },
"privacy": "Vos informations sont privées et ne seront jamais partagées.", "privacy": "Vos informations sont privées et ne seront jamais partagées.",
"generateBrief": "Générer Mon Brief", "generateBrief": "Générer Mon Brief",
@@ -238,56 +268,204 @@
}, },
"comingSoonProjects": { "comingSoonProjects": {
"riviera": { "riviera": {
"title": "Projet Confidentiel Riviera", "title": "Plateforme de Gestion Immobilière",
"subtitle": "Bientôt Disponible" "subtitle": "Bientôt Disponible"
}, },
"sophia": { "sophia": {
"title": "Startup IA Sophia Antipolis", "title": "SaaS Entreprise — Austin, TX",
"subtitle": "Lancement T4" "subtitle": "Lancement T4"
} }
} }
}, },
"philosophy": { "philosophy": {
"eyebrow": "Pourquoi C'est Important", "eyebrow": "Pourquoi Nous",
"title": "Vos outils devraient vous appartenir.", "title": "On fait les choses différemment.",
"subtitle": "La plupart des entreprises louent leur vie digitale à une dizaine de plateformes différentes. Nous pensons qu'il y a mieux - un monde où vous possédez vos données, contrôlez votre infrastructure et n'êtes enfermé dans la grille tarifaire de personne.", "subtitle": "La plupart des agences vous donnent un template et appellent ça du sur-mesure. Nous pensons que votre entreprise mérite mieux - un vrai design, une vraie ingénierie, et une équipe qui reste après le lancement.",
"ownership": { "ownership": {
"title": "Maîtrisez Votre Stack", "title": "Construit Pour Vous",
"description": "Nous vous libérons des abonnements SaaS dispersés pour vous installer sur une infrastructure privée - serveurs, email, stockage cloud et outils que vous contrôlez." "description": "Tout ce que nous construisons vous appartient. Votre code, vos données, votre infrastructure - pas de verrouillage, pas de dépendances, pas de surprises."
}, },
"craftsmanship": { "craftsmanship": {
"title": "Pas de Raccourcis", "title": "L'Artisanat Avant Tout",
"description": "Nous écrivons du code propre, artisanal, optimisé pour la vitesse et le référencement. Pas de constructeurs de pages, pas de thèmes surchargés, pas de dette technique." "description": "Nous écrivons du code propre, construit à la main, optimisé pour la vitesse et le référencement. Pas de constructeurs de pages, pas de thèmes surchargés, pas de raccourcis."
}, },
"oneTeam": { "oneTeam": {
"title": "Une Seule Relation", "title": "Une Seule Relation",
"description": "Du design initial au développement jusqu'au support continu - une seule équipe qui connaît votre activité de A à Z." "description": "Du premier design au support continu - une seule équipe qui connaît votre activité de A à Z. Pas de sous-traitance, pas de briefs perdus en route."
}, },
"quote": "Nous construisons la technologie qui travaille pour votre entreprise - pas l'inverse.", "quote": "Nous construisons la technologie qui travaille pour votre entreprise - pas l'inverse.",
"foundedLocation": "Matt Ciaccio, Fondateur" "foundedLocation": "Matt Ciaccio, Fondateur"
}, },
"cta": { "cta": {
"eyebrow": "Parlons-en", "eyebrow": "Parlons-en",
"title": "Prêt à construire quelque chose ?", "title": "Prêt à construire quelque chose de grand ?",
"subtitle": "Dites-nous ce dont vous avez besoin. Pas de slides, pas de pression - juste une conversation sur ce qui est possible.", "subtitle": "Dites-nous sur quoi vous travaillez. Pas de slides, pas de pression - juste une conversation honnête sur ce qui est possible.",
"cta": "Démarrer Votre Projet", "cta": "Démarrer Votre Projet",
"configure": "Démarrer Votre Projet", "configure": "Démarrer Votre Projet",
"email": "hello@letsbe.biz", "email": "hello@letsbe.biz",
"reassurance": "Sans engagement." "reassurance": "Sans engagement."
}, },
"footer": { "footer": {
"tagline": "Sites web, logiciels et infrastructure sur mesure pour les entreprises qui veulent maîtriser leur avenir digital.", "tagline": "Sites web, logiciels et plateformes digitales sur mesure - conçus et développés pour les entreprises qui refusent de se contenter de moins.",
"location": "Fondé aux États-Unis. Au service de clients dans le monde entier.", "location": "Fondé aux États-Unis. Au service de clients dans le monde entier.",
"services": "Services", "services": "Services",
"studio": "Studio", "studio": "Studio",
"connect": "Contact", "connect": "Contact",
"serviceLinks": { "serviceLinks": {
"designDev": "Sites Web & Applications", "designDev": "Design & Développement Web",
"customSystems": "Logiciels Sur Mesure", "customSystems": "Logiciels Sur Mesure",
"infrastructure": "Infrastructure Privée", "infrastructure": "Infrastructure Privée",
"aiAutomation": "Intégration IA" "aiAutomation": "Intégration IA"
}, },
"privacy": "Politique de Confidentialité", "privacy": "Politique de Confidentialité",
"terms": "Conditions d'Utilisation" "terms": "Conditions d'Utilisation"
},
"aboutPage": {
"hero": {
"eyebrow": "À propos de LetsBe.",
"title": "Les grandes entreprises méritent de grands partenaires digitaux.",
"subtitle": "Nous concevons et développons des sites web, des logiciels et des plateformes digitales sur mesure pour les entreprises qui exigent la qualité — et qui veulent une équipe qui la partage."
},
"story": {
"eyebrow": "Notre Histoire",
"title": "Conçu pour des entreprises comme la vôtre.",
"p1": "LetsBe. est née d'une conviction simple : les entreprises ambitieuses méritent des outils digitaux aussi soigneusement pensés que le travail qu'elles accomplissent. Pas de templates. Pas de plateformes standardisées. Un vrai design et une vraie ingénierie, construits de zéro.",
"p2": "Nos premiers clients étaient des fondateurs et des dirigeants qui avaient besoin de plus qu'un site web — ils avaient besoin d'un partenaire technique capable de concevoir, développer, héberger et maintenir l'ensemble sous un même toit. Ces projets ont façonné notre façon de travailler aujourd'hui.",
"p3": "Nous construisons des plateformes faites pour être possédées, pas louées. Nous documentons tout, nous remettons des bases de code qui perdurent au-delà de la mission, et nous ne verrouillons jamais nos clients dans des systèmes qu'ils ne peuvent pas quitter. Ce n'est pas une fonctionnalité — c'est notre vision des affaires.",
"quote": "Construire moins de choses. Les construire mieux. Les construire pour durer.",
"quoteAttrib": "Principe fondateur de LetsBe."
},
"pillars": {
"eyebrow": "Nos Convictions",
"title": "Ce en quoi nous croyons",
"subtitle": "Trois principes qui guident chaque projet que nous prenons en charge.",
"craftsmanship": {
"title": "L'Artisanat Avant Tout",
"description": "La différence entre un site qui fonctionne et un site qui dure, c'est le soin apporté à sa réalisation. Nous soignons la typographie, les transitions, la performance, les cas limites. Chaque interface que nous livrons est quelque chose dont nous sommes fiers de signer."
},
"oneTeam": {
"title": "Une Équipe, Tout Inclus",
"description": "Design, développement, hébergement, infrastructure — une seule équipe, un seul interlocuteur, un seul niveau d'exigence. Pas de sous-traitance entre agences. Pas de jonglage avec des freelances. Juste des gens qui se soucient de l'ensemble."
},
"ownership": {
"title": "Construit Pour Vous Appartenir",
"description": "Tout ce que nous construisons vous appartient — le code, les données, l'infrastructure. Pas de dépendance fournisseur, pas de contraintes de plateforme. Nous remettons un travail qui perdurera au-delà de notre collaboration."
}
},
"quote": {
"text": "Nous ne construisons pas seulement des sites web — nous construisons les fondations sur lesquelles votre entreprise s'appuie.",
"attrib": "Philosophie fondatrice de LetsBe."
},
"cta": {
"eyebrow": "Travaillez Avec Nous",
"title": "Construisons quelque chose ensemble.",
"subtitle": "Que vous ayez un brief précis ou simplement une idée naissante, nous serions ravis d'explorer ce qui est possible.",
"primary": "Démarrer votre projet",
"secondary": "Réserver un appel"
}
},
"servicesPage": {
"hero": {
"eyebrow": "Nos Services",
"title": "Tout ce dont votre entreprise",
"titleAccent": "a besoin en ligne.",
"subtitle": "Nous concevons des sites web sur mesure, développons des logiciels dédiés et gérons l'infrastructure derrière tout cela — une seule équipe, un seul niveau d'exigence, rien d'externalisé."
},
"pillars": [
{
"id": "design-development",
"numeral": "01",
"title": "Design & Développement Web",
"description": "Votre site web ne devrait pas ressembler à celui de tout le monde — et ne devrait pas être construit comme celui de tout le monde non plus. Nous concevons et développons des sites web et des applications web sur mesure à partir d'une page blanche, en façonnant chaque mise en page, chaque interaction et chaque page avec intention. Le résultat est rapide, optimisé pour les moteurs de recherche, et conçu pour évoluer avec votre entreprise. Que vous ayez besoin d'un site marketing qui convertit, d'une application web sur laquelle votre équipe s'appuie, ou d'une plateforme e-commerce qui passe à l'échelle — nous la construisons de zéro, et nous la construisons pour durer.",
"features": [
{ "icon": "Palette", "title": "Design Sur Mesure", "description": "Chaque mise en page, composant et interaction est conçu pour votre marque. Pas de thèmes, pas de templates, pas de raccourcis." },
{ "icon": "Globe", "title": "Applications Web", "description": "Des applications modernes et responsives développées avec les dernières technologies — rapides, fiables et prêtes à évoluer." },
{ "icon": "ShoppingCart", "title": "E-Commerce", "description": "Boutiques sur mesure, tunnels de commande et plateformes multi-devises conçus pour le commerce en ligne sérieux." },
{ "icon": "Zap", "title": "Performance & SEO", "description": "Des temps de chargement rapides, un code propre et une optimisation pour les moteurs de recherche intégrés dès la conception — pas ajoutés après coup." }
]
},
{
"id": "custom-systems",
"numeral": "02",
"title": "Logiciels & Plateformes",
"description": "Les logiciels standard font des suppositions sur le fonctionnement de votre entreprise. Pas nous. Quand les tableurs et les outils génériques ne suffisent plus, nous développons le système exact dont votre équipe a besoin — conçu autour de votre processus, pas de celui d'un autre. Des CRM adaptés à votre cycle de vente, aux plateformes de gestion qui remplacent trois abonnements différents, en passant par les intégrations qui connectent vos outils existants — tout ce que nous construisons vous appartient, est entièrement documenté et conçu pour durer.",
"features": [
{ "icon": "Database", "title": "CRM & Outils de Gestion", "description": "La gestion des relations et des pipelines construite autour de la façon dont votre équipe travaille réellement — pas selon les schémas d'une plateforme générique." },
{ "icon": "Code2", "title": "Logiciels Sur Mesure", "description": "Des plateformes de réservation aux outils internes en passant par les produits SaaS complets — conçus sur mesure pour votre entreprise." },
{ "icon": "GitBranch", "title": "Intégrations & API", "description": "Nous connectons vos outils existants et construisons les passerelles entre systèmes pour que tout fonctionne ensemble." },
{ "icon": "Wrench", "title": "Tableaux de Bord & Automatisation", "description": "Panneaux d'administration, outils de reporting et automatisation des processus qui donnent à votre équipe un avantage décisif." }
]
},
{
"id": "infrastructure",
"numeral": "03",
"title": "Hébergement & Infrastructure",
"description": "Votre site web et vos logiciels ont besoin d'un chez-soi — et nous pensons que vous devriez en être propriétaire. Nous mettons en place et gérons des serveurs dédiés, l'email, le stockage cloud et toute l'infrastructure sur laquelle votre entreprise fonctionne. Pas d'hébergement mutualisé, pas de dépendances tierces obscures. Vous savez où vivent vos données, qui y a accès, et que quelqu'un surveille le tableau de bord en permanence.",
"features": [
{ "icon": "Server", "title": "Hébergement Dédié", "description": "Des serveurs privés gérés pour votre entreprise — pas d'hébergement mutualisé, pas de voisins encombrants, pas de surprises." },
{ "icon": "Shield", "title": "Vos Données, Votre Contrôle", "description": "Vous possédez vos données et savez exactement où elles se trouvent. Accès complet, transparence totale, sans verrouillage." },
{ "icon": "Lock", "title": "Sécurité & Protection", "description": "Une sécurité sérieuse, une surveillance proactive et une protection intégrée dans votre infrastructure dès le premier jour." },
{ "icon": "Settings", "title": "Surveillance & Support", "description": "Surveillance proactive, mises à jour régulières et support continu pour que vous n'ayez jamais à vous soucier de la disponibilité." }
]
}
],
"ai": {
"eyebrow": "Couche Intelligente",
"title": "L'IA Intégrée Partout",
"subtitle": "Votre plateforme, rendue plus intelligente.",
"description": "Nous intégrons l'IA directement dans les sites web et les logiciels que nous développons pour vous. Non pas comme un mot à la mode ou un module complémentaire — mais comme des fonctionnalités concrètes qui font gagner du temps à votre équipe et offrent une meilleure expérience à vos clients.",
"bottomNote": "Chaque fonctionnalité IA est adaptée à votre entreprise — vos données restent sur vos serveurs",
"capabilities": [
{ "id": "ai-teammate", "title": "IA Coéquipier", "description": "Un assistant IA intégré à votre flux de travail — automatise les tâches répétitives, fait remonter les informations dont votre équipe a besoin et connecte vos outils." },
{ "id": "customer-facing-ai", "title": "IA Orientée Client", "description": "Des fonctionnalités intelligentes pour vos clients — recherche avancée, recommandations personnalisées et interfaces conversationnelles disponibles en permanence." },
{ "id": "data-intelligence", "title": "Intelligence des Données", "description": "L'IA qui vous aide à comprendre vos données — rapports automatisés, détection de tendances et insights sur lesquels vous pouvez réellement agir." }
]
},
"cta": {
"eyebrow": "Parlons-en",
"title": "Prêt à vous lancer ?",
"subtitle": "Répondez à quelques questions et nous préparerons un brief projet sur mesure pour vous — sans engagement, juste de la clarté.",
"primary": "Démarrer Votre Projet",
"email": "hello@letsbe.biz",
"reassurance": "Sans engagement — juste une conversation sur ce qui est possible."
}
},
"caseStudy": {
"labels": {
"challenge": "Le Défi",
"challengeHeading": "Le problème que nous cherchions à résoudre",
"approach": "Notre Approche",
"approachHeading": "Comment nous avons réfléchi",
"outcome": "Le Résultat",
"outcomeHeading": "Ce que nous avons livré",
"builtWith": "Développé avec",
"yourTurn": "À Votre Tour",
"ctaTitle": "Prêt à construire quelque chose comme ça ?",
"ctaSubtitle": "Chaque projet commence par une conversation. Dites-nous sur quoi vous travaillez et nous trouverons la meilleure façon de le concrétiser.",
"ctaButton": "Démarrer votre projet"
},
"projects": {
"monaco-ocean": {
"subtitle": "Plateforme de Jugement & d'Analyse Propulsée par l'IA",
"description": "Un système complet de jugement et d'analyse avec intégration avancée d'un jury IA pour l'un des événements de conservation les plus prestigieux de la Méditerranée.",
"challenge": "Le Monaco Ocean Protection Challenge avait besoin d'une plateforme moderne pour gérer les candidatures, coordonner les juges à travers différents fuseaux horaires et fournir une évaluation assistée par l'IA des projets de conservation — tout en maintenant le prestige et la sécurité attendus d'une institution monégasque.",
"approach": "Nous avons développé une plateforme sur mesure de A à Z en utilisant Next.js et une infrastructure PostgreSQL privée. Le module de jury IA utilise le traitement du langage naturel pour présélectionner les candidatures et générer des rapports de synthèse, tandis que les juges humains conservent le contrôle total des décisions finales.",
"outcome": "La plateforme a traité plus de 200 candidatures lors de sa première saison, réduisant la charge de travail des juges de 40 % grâce à la présélection assistée par l'IA. Le client a salué la fiabilité du système et l'élégance de son interface."
},
"port-nimara": {
"subtitle": "Hub Digital Maritime",
"description": "Hub digital évolutif pour la logistique maritime.",
"challenge": "Port Nimara avait besoin d'une présence digitale moderne pouvant servir à la fois de site vitrine et de hub opérationnel pour les demandes d'anneaux, la gestion d'événements et les communications avec les partenaires.",
"approach": "Nous avons conçu et développé une application Nuxt.js performante avec un CMS headless pour la gestion de contenu, intégrée à leurs systèmes de planification maritime existants via un middleware API sur mesure.",
"outcome": "La nouvelle plateforme a multiplié par 3 les demandes d'anneaux en ligne et a fourni aux autorités portuaires des capacités de gestion de contenu en temps réel dont elles manquaient jusqu'alors."
},
"port-amador": {
"subtitle": "Expérience Nautique Premium",
"description": "Expérience digitale premium pour des services nautiques d'élite.",
"challenge": "Port Amador avait besoin d'une expérience digitale de standing luxe à la hauteur de l'exclusivité de ses services nautiques, avec une prise en charge multilingue et une intégration de réservation transparente.",
"approach": "Nous avons créé un site web sur mesure avec des visuels cinématographiques, des animations fluides et un tunnel de réservation intégré. Le site a été développé avec des technologies web modernes en mettant l'accent sur la performance et le SEO pour le marché maritime de luxe très concurrentiel.",
"outcome": "La plateforme repensée a élevé la présence digitale de Port Amador pour correspondre à son positionnement premium, avec une amélioration de 60 % des temps de chargement des pages et une augmentation significative du trafic organique."
}
}
} }
} }

471
src/i18n/messages/it.json Normal file
View File

@@ -0,0 +1,471 @@
{
"meta": {
"siteName": "LetsBe.",
"home": {
"title": "LetsBe. | Web Design Su Misura, Software & Infrastruttura Digitale",
"description": "Siti web su misura, software dedicato, integrazione IA e infrastruttura privata — progettati, sviluppati e gestiti da un unico team."
},
"about": {
"title": "Chi Siamo | LetsBe. — La Nostra Storia & Approccio",
"description": "Uno studio digitale fondato negli Stati Uniti che crea siti web, software e piattaforme su misura per aziende che puntano alla qualità."
},
"services": {
"title": "Servizi | LetsBe. — Web Design, Software & Infrastruttura",
"description": "Web design su misura, software dedicato, automazione IA e infrastruttura privata — tre pilastri dell'eccellenza digitale sotto un unico tetto."
},
"work": {
"monaco-ocean": {
"title": "Monaco Ocean Protection Challenge | LetsBe.",
"description": "Piattaforma di giuria e analisi basata sull'IA per uno dei principali eventi di conservazione del Mediterraneo."
},
"port-nimara": {
"title": "Port Nimara — Hub Digitale Marittimo | LetsBe.",
"description": "Sito web su misura e CRM completo per la gestione dei lead, l'assegnazione dei posti barca e le operazioni del porto."
},
"port-amador": {
"title": "Port Amador — Esperienza Nautica Premium | LetsBe.",
"description": "Sito web e infrastruttura digitale privata per un marina di lusso — cloud storage, email e gestione dei file."
}
}
},
"nav": {
"services": "Servizi",
"configure": "Inizia",
"process": "Metodo",
"work": "Lavori",
"about": "Chi Siamo",
"startProject": "Avvia un Progetto",
"bookCall": "Prenota una Chiamata"
},
"hero": {
"title": "Il tuo sito. Il tuo software. Il tuo mondo digitale {accentWord}.",
"accentWord": "completo",
"subtitle": "Siti web su misura, software dedicato e l'infrastruttura per far girare tutto — progettati, sviluppati e gestiti da un unico team.",
"cta": "Avvia il Tuo Progetto",
"ctaSecondary": "Scopri i Nostri Lavori",
"trust": "La fiducia di aziende in tutto il mondo"
},
"trustBar": {
"customBuilt": {
"title": "Progettato da Zero",
"description": "Nessun template, nessun page builder. Ogni sito è progettato su misura e costruito a mano per il tuo brand."
},
"privateInfra": {
"title": "Tutto è Tuo",
"description": "Il tuo codice, i tuoi dati, i tuoi server. Lo costruiamo noi, lo possiedi tu — nessun lock-in, nessuna sorpresa."
},
"aiPowered": {
"title": "Un Team, dall'Inizio alla Fine",
"description": "Niente freelance da coordinare. Un solo team gestisce design, codice, hosting e supporto."
},
"rivieraBased": {
"title": "IA Integrata",
"description": "Funzionalità intelligenti e automazione integrate direttamente nel tuo sito web e nei tuoi software."
}
},
"services": {
"eyebrow": "Cosa Facciamo",
"title": "Progettare. Sviluppare. Crescere.",
"web": {
"title": "Web Design & Sviluppo",
"features": ["Design di Siti Su Misura", "Sviluppo Responsive", "SEO & Performance", "Gestione dei Contenuti"]
},
"systems": {
"title": "Software & Piattaforme",
"features": ["Strumenti di Gestione Aziendale", "CRM & Dashboard", "Sistemi di Prenotazione", "Integrazioni API"]
},
"infrastructure": {
"title": "Hosting & Infrastruttura",
"features": ["Server Dedicati", "Email & Cloud Storage", "Sicurezza & Monitoraggio", "Supporto Continuativo"]
},
"aiNarrative": "E integriamo l'IA in tutto — dalle funzionalità intelligenti nel tuo sito web all'automazione che connette tutti i tuoi strumenti."
},
"configurator": {
"eyebrow": "Inizia",
"title": "Dicci di cosa hai bisogno.",
"description": "Rispondi a qualche domanda e prepareremo un brief di progetto su misura per te.",
"step1": {
"title": "Di cosa hai bisogno?",
"subtitle": "Seleziona i servizi che si adattano al tuo progetto."
},
"step2": {
"title": "Parlaci del tuo progetto",
"subtitle": "Qualche dettaglio ci aiuta a preparare l'approccio giusto."
},
"step3": {
"title": "Quasi fatto",
"subtitle": "Controlla le tue selezioni e dicci come contattarti."
},
"complete": {
"title": "Il tuo brief di progetto è pronto",
"subtitle": "Controlla la tua casella — abbiamo inviato un brief dettagliato a {email}",
"nextStep": "Prossimo passo: parliamo del tuo brief",
"bookSubtitle": "Prenota una chiamata gratuita di 30 minuti per discutere del tuo progetto e dei prossimi passi.",
"bookCall": "Prenota una Chiamata",
"briefPreview": "Il tuo brief di progetto",
"reachDirectly": "O contattaci direttamente a"
},
"howItWorks": "Come funziona",
"noCommitment": "Nessun impegno richiesto",
"selectService": "Seleziona almeno un servizio per continuare",
"services": {
"web": {
"title": "Web Design & Sviluppo",
"description": "Siti web e applicazioni su misura — progettati da zero, costruiti per performare e ottimizzati per essere trovati."
},
"systems": {
"title": "Software Su Misura",
"description": "CRM, piattaforme di gestione e strumenti aziendali costruiti attorno al modo in cui il tuo team lavora davvero."
},
"infrastructure": {
"title": "Infrastruttura Privata",
"description": "Hosting dedicato, email, cloud storage e l'infrastruttura su cui gira la tua azienda — interamente di tua proprietà."
}
},
"aiToggle": "Aggiungi Integrazione IA",
"aiDescription": "Funzionalità IA pratiche e automazione integrate direttamente nel tuo sito web e nei tuoi software.",
"aiTypes": {
"teammate": {
"title": "IA come Collaboratore",
"description": "Un assistente IA interno che aiuta il tuo team a lavorare più velocemente — automatizza le attività, risponde alle domande, connette i tuoi strumenti."
},
"customer-facing": {
"title": "IA per i Clienti",
"description": "Funzionalità IA con cui interagiscono i tuoi clienti — ricerca intelligente, raccomandazioni personalizzate, interfacce conversazionali."
},
"data-intelligence": {
"title": "Intelligenza dei Dati",
"description": "L'IA analizza i dati della tua azienda per far emergere insight, trend e raccomandazioni concrete."
},
"notsure": {
"title": "Non Ancora Sicuro",
"description": "Nessun problema — esploreremo insieme il miglior approccio IA durante la fase di discovery."
}
},
"industries": {
"maritime": "Marittimo / Yachting",
"hospitality": "Ospitalità",
"technology": "Tecnologia",
"realestate": "Immobiliare",
"finance": "Finanza",
"ngo": "ONG / Non Profit",
"other": "Altro"
},
"timelines": {
"asap": "Prima possibile",
"1-3months": "13 mesi",
"3-6months": "36 mesi",
"exploring": "Sto solo esplorando"
},
"fields": {
"industry": "Il tuo settore",
"scope": "Cosa vuoi ottenere?",
"scopeOptional": "(opzionale)",
"scopePlaceholder": "es. Dobbiamo sostituire il nostro sistema di prenotazione attuale e migliorare l'esperienza cliente…",
"timeline": "Tempistiche",
"name": "Il tuo nome",
"company": "Azienda",
"email": "Indirizzo email",
"phone": "Telefono",
"phoneOptional": "(opzionale)",
"contactPreference": "Metodo di contatto preferito",
"contactEmail": "Email",
"contactPhone": "Telefono",
"contactWhatsapp": "WhatsApp",
"currentSiteUrl": "Sito web attuale",
"currentSiteUrlOptional": "(opzionale)",
"currentSiteUrlPlaceholder": "https://iltuosito.com",
"currentSiteThoughts": "Opinioni sul tuo sito attuale",
"currentSiteThoughtsPlaceholder": "Cosa funziona, cosa non funziona, cosa vorresti cambiare..."
},
"summary": {
"heading": "Le tue selezioni",
"aiEnhancement": "Potenziamento IA"
},
"generating": "Generazione",
"generatingSteps": {
"preparingBrief": "Preparazione del tuo brief",
"analyzingSite": "Analisi del tuo sito attuale",
"runningAudit": "Audit delle performance in corso",
"generatingBrief": "Generazione del tuo brief personalizzato"
},
"voice": {
"agentName": "Assistente di progetto LetsBe",
"endConversation": "Termina la Conversazione",
"analyzingSite": "Analisi del tuo sito...",
"connecting": "Connessione in corso...",
"mute": "Silenzia",
"unmute": "Riattiva audio",
"generatingBrief": "Generazione del tuo brief...",
"contactConfirm": "È tutto corretto?",
"contactEdit": "Modifica",
"contactConfirmButton": "È corretto",
"reconnect": "Riconnetti",
"connectionLost": "Connessione persa. La tua conversazione è salvata.",
"briefComplete": "Brief completato",
"startConversation": "Avvia conversazione"
},
"privacy": "Le tue informazioni sono private e non saranno mai condivise.",
"generateBrief": "Genera il Mio Brief",
"nextStep": "Prossimo Passo",
"back": "Indietro",
"startOver": "Ricomincia",
"errors": {
"general": "Qualcosa è andato storto. Riprova.",
"network": "Errore di rete. Controlla la connessione e riprova."
}
},
"discovery": {
"eyebrow": "Troviamolo Insieme",
"title": "Non sai da dove iniziare?",
"description": "Dicci cosa hai in mente e lo capiremo insieme. Riceverai un brief personalizzato alla fine.",
"cta": "Parliamone",
"privacy": "Le conversazioni vocali non vengono registrate né memorizzate."
},
"process": {
"eyebrow": "Come Lavoriamo",
"title": "Dall'Idea al Lancio",
"steps": {
"discovery": {
"title": "Discovery",
"description": "Studiamo la tua azienda, i tuoi utenti e ciò che hai davvero bisogno di costruire."
},
"strategy": {
"title": "Strategia & Pianificazione",
"description": "Definiamo l'architettura, scegliamo gli strumenti giusti e pianifichiamo lo sviluppo."
},
"build": {
"title": "Design & Sviluppo",
"description": "Il tuo progetto prende forma — pixel dopo pixel, funzionalità dopo funzionalità."
},
"launch": {
"title": "Lancio & Supporto",
"description": "Facciamo il deploy, monitoriamo e manteniamo tutto funzionante senza intoppi."
}
}
},
"work": {
"eyebrow": "I Nostri Lavori",
"title": "Progetti Che Abbiamo Realizzato",
"readCaseStudy": "Vedi Progetto",
"comingSoon": "Prossimamente",
"projects": {
"monaco": {
"title": "Monaco Ocean Protection Challenge",
"description": "Piattaforma di giuria e analisi con filtraggio basato su IA, assegnazione automatica dei giudici e valutazione intelligente dei progetti per uno dei principali eventi di conservazione del Mediterraneo.",
"tags": ["Software Su Misura", "Integrazione IA"]
},
"portNimara": {
"title": "Port Nimara",
"description": "Sito web su misura e CRM completo per la gestione dei lead, l'assegnazione dei posti barca e le operazioni del porto.",
"tags": ["Sito Web", "Software Su Misura"]
},
"portAmador": {
"title": "Port Amador",
"description": "Sito web e infrastruttura digitale privata — cloud storage, email e gestione dei file per un marina di lusso.",
"tags": ["Sito Web", "Infrastruttura"]
}
},
"comingSoonProjects": {
"riviera": {
"title": "Piattaforma di Gestione Immobiliare",
"subtitle": "Prossimamente"
},
"sophia": {
"title": "SaaS Enterprise — Austin, TX",
"subtitle": "Lancio Q4"
}
}
},
"philosophy": {
"eyebrow": "Perché Noi",
"title": "Facciamo le cose diversamente.",
"subtitle": "La maggior parte delle agenzie ti dà un template e lo chiama su misura. Noi pensiamo che la tua azienda meriti di meglio — design vero, ingegneria vera e un team che resta anche dopo il lancio.",
"ownership": {
"title": "Costruito per Essere Tuo",
"description": "Tutto quello che costruiamo è tuo. Il tuo codice, i tuoi dati, la tua infrastruttura — nessun lock-in, nessuna dipendenza da piattaforme, nessuna sorpresa."
},
"craftsmanship": {
"title": "Qualità Prima della Comodità",
"description": "Scriviamo codice pulito, costruito a mano, ottimizzato per velocità e motori di ricerca. Nessun page builder, nessun tema gonfio, nessuna scorciatoia."
},
"oneTeam": {
"title": "Un'Unica Relazione",
"description": "Dal primo design al supporto continuativo — un solo team che conosce la tua azienda a fondo. Nessun passaggio di mano, nessun brief perso per strada."
},
"quote": "Costruiamo tecnologia che lavora per la tua azienda — non il contrario.",
"foundedLocation": "Matt Ciaccio, Fondatore"
},
"cta": {
"eyebrow": "Parliamone",
"title": "Pronto a costruire qualcosa di grande?",
"subtitle": "Dicci su cosa stai lavorando. Niente presentazioni, niente pressioni — solo una conversazione onesta su ciò che è possibile.",
"cta": "Avvia il Tuo Progetto",
"configure": "Avvia il Tuo Progetto",
"email": "hello@letsbe.biz",
"reassurance": "Nessun impegno richiesto."
},
"footer": {
"tagline": "Siti web, software e piattaforme digitali su misura — progettati e sviluppati per aziende che rifiutano di accontentarsi.",
"location": "Fondato negli Stati Uniti. Al servizio di clienti in tutto il mondo.",
"services": "Servizi",
"studio": "Studio",
"connect": "Contatti",
"serviceLinks": {
"designDev": "Web Design & Sviluppo",
"customSystems": "Software Su Misura",
"infrastructure": "Infrastruttura Privata",
"aiAutomation": "Integrazione IA"
},
"privacy": "Privacy Policy",
"terms": "Termini di Servizio"
},
"aboutPage": {
"hero": {
"eyebrow": "Chi Siamo",
"title": "Le grandi aziende meritano grandi partner digitali.",
"subtitle": "Progettiamo e sviluppiamo siti web, software e piattaforme digitali su misura per aziende che puntano alla qualità — e che cercano un team che faccia lo stesso."
},
"story": {
"eyebrow": "La Nostra Storia",
"title": "Costruito per aziende come la tua.",
"p1": "LetsBe. è nata da una convinzione semplice: le aziende ambiziose meritano strumenti digitali curati quanto il lavoro che svolgono. Non template. Non piattaforme preconfezionate. Design e ingegneria reali, costruiti da zero.",
"p2": "I nostri primi clienti erano founder e imprenditori che avevano bisogno di qualcosa di più di un sito web — un partner tecnico capace di progettare, sviluppare, ospitare e mantenere tutto sotto un unico tetto. Quei progetti hanno plasmato il nostro modo di lavorare oggi.",
"p3": "Costruiamo piattaforme pensate per essere possedute, non affittate. Documentiamo tutto, consegniamo codebase che sopravvivono al progetto e non leghiamo mai i clienti a sistemi che non possono lasciare. Non è una caratteristica — è come pensiamo che il business dovrebbe funzionare.",
"quote": "Costruire meno cose. Costruirle meglio. Costruirle per durare.",
"quoteAttrib": "Principio fondante di LetsBe."
},
"pillars": {
"eyebrow": "Le Nostre Convinzioni",
"title": "In Cosa Crediamo",
"subtitle": "Tre principi alla base di ogni progetto che realizziamo.",
"craftsmanship": {
"title": "Prima la Qualità",
"description": "La differenza tra un sito che funziona e uno che dura è la cura artigianale. Ci preoccupiamo della tipografia, delle transizioni, delle performance, dei casi limite. Ogni interfaccia che rilasciamo è qualcosa di cui siamo orgogliosi di firmare."
},
"oneTeam": {
"title": "Un Team, Tutto",
"description": "Design, sviluppo, hosting, infrastruttura — un unico team, un unico punto di contatto, un unico standard di qualità. Nessun passaggio tra agenzie. Nessun freelance da coordinare. Solo persone che si preoccupano dell'intero progetto."
},
"ownership": {
"title": "Costruito per Essere Tuo",
"description": "Tutto quello che costruiamo è tuo — il codice, i dati, l'infrastruttura. Nessun vendor lock-in, nessuna dipendenza da piattaforme. Consegniamo lavoro che sopravvive al progetto."
}
},
"quote": {
"text": "Non costruiamo solo siti web — costruiamo le fondamenta su cui gira la tua azienda.",
"attrib": "Filosofia fondante di LetsBe."
},
"cta": {
"eyebrow": "Lavora Con Noi",
"title": "Costruiamo qualcosa insieme.",
"subtitle": "Che tu abbia un brief chiaro o solo un'idea iniziale, ci farebbe piacere parlare di ciò che è possibile.",
"primary": "Avvia il tuo progetto",
"secondary": "Prenota una chiamata"
}
},
"servicesPage": {
"hero": {
"eyebrow": "I Nostri Servizi",
"title": "Tutto ciò di cui la tua azienda",
"titleAccent": "ha bisogno online.",
"subtitle": "Progettiamo siti web su misura, sviluppiamo software dedicato e gestiamo l'infrastruttura che li supporta — un unico team, un unico standard di qualità, niente esternalizzato."
},
"pillars": [
{
"id": "design-development",
"numeral": "01",
"title": "Web Design & Sviluppo",
"description": "Il tuo sito web non dovrebbe assomigliare a quello di tutti gli altri — e non dovrebbe essere costruito come quello di tutti gli altri. Progettiamo e sviluppiamo siti web e applicazioni web da una tela bianca, curando ogni layout, ogni interazione e ogni pagina con intenzione. Il risultato è veloce, ottimizzato per i motori di ricerca e costruito per crescere con la tua azienda. Che tu abbia bisogno di un sito marketing che converte, di un'applicazione web su cui il tuo team fa affidamento, o di una piattaforma e-commerce che scala — lo costruiamo da zero, e lo costruiamo per durare.",
"features": [
{ "icon": "Palette", "title": "Design Su Misura", "description": "Ogni layout, componente e interazione è progettato per il tuo brand. Nessun tema, nessun template, nessuna scorciatoia." },
{ "icon": "Globe", "title": "Applicazioni Web", "description": "Applicazioni moderne e responsive sviluppate con le tecnologie più recenti — veloci, affidabili e pronte a scalare." },
{ "icon": "ShoppingCart", "title": "E-Commerce", "description": "Storefront personalizzati, flussi di checkout e piattaforme multi-valuta costruite per il retail online serio." },
{ "icon": "Zap", "title": "Performance & SEO", "description": "Tempi di caricamento rapidi, codice pulito e ottimizzazione per i motori di ricerca integrati nelle fondamenta — non aggiunti in un secondo momento." }
]
},
{
"id": "custom-systems",
"numeral": "02",
"title": "Software & Piattaforme",
"description": "I software preconfezionati fanno ipotesi su come funziona la tua azienda. Noi no. Quando fogli di calcolo e strumenti generici non bastano più, costruiamo esattamente il sistema di cui il tuo team ha bisogno — progettato attorno al tuo flusso di lavoro, non a quello di qualcun altro. Dai CRM adatti al tuo processo di vendita, alle piattaforme di gestione che sostituiscono tre abbonamenti diversi, alle integrazioni che connettono i tuoi strumenti esistenti — tutto quello che costruiamo è tuo, completamente documentato e costruito per durare.",
"features": [
{ "icon": "Database", "title": "CRM & Strumenti di Gestione", "description": "Gestione delle relazioni e della pipeline costruita attorno a come lavora davvero il tuo team — non come pensa una piattaforma generica che dovresti lavorare." },
{ "icon": "Code2", "title": "Software Su Misura", "description": "Dalle piattaforme di prenotazione agli strumenti interni, fino ai prodotti SaaS completi — costruiti su misura per la tua azienda." },
{ "icon": "GitBranch", "title": "Integrazioni & API", "description": "Connettiamo i tuoi strumenti esistenti e costruiamo i ponti tra i sistemi affinché tutto funzioni insieme." },
{ "icon": "Wrench", "title": "Dashboard & Automazione", "description": "Pannelli di amministrazione, strumenti di reporting e automazione dei flussi di lavoro che danno al tuo team un vantaggio competitivo." }
]
},
{
"id": "infrastructure",
"numeral": "03",
"title": "Hosting & Infrastruttura",
"description": "Il tuo sito web e il tuo software hanno bisogno di una casa — e noi pensiamo che dovresti possederla. Configuriamo e gestiamo server dedicati, email, cloud storage e tutta l'infrastruttura su cui gira la tua azienda. Nessun hosting condiviso, nessuna misteriosa dipendenza da terze parti. Sai dove vivono i tuoi dati, chi vi ha accesso e che qualcuno tiene d'occhio la dashboard 24 ore su 24.",
"features": [
{ "icon": "Server", "title": "Hosting Dedicato", "description": "Server privati gestiti per la tua azienda — nessun hosting condiviso, nessun vicino rumoroso, nessuna sorpresa." },
{ "icon": "Shield", "title": "I Tuoi Dati, Il Tuo Controllo", "description": "Possiedi i tuoi dati e sai esattamente dove si trovano. Accesso completo, piena trasparenza, nessun lock-in." },
{ "icon": "Lock", "title": "Sicurezza & Protezione", "description": "Sicurezza seria, monitoraggio proattivo e protezione integrata nella tua infrastruttura fin dal primo giorno." },
{ "icon": "Settings", "title": "Monitoraggio & Supporto", "description": "Monitoraggio proattivo, aggiornamenti regolari e supporto continuativo così non dovrai mai preoccuparti dell'uptime." }
]
}
],
"ai": {
"eyebrow": "Livello Intelligente",
"title": "IA Integrata in Tutto",
"subtitle": "La tua piattaforma, resa più intelligente.",
"description": "Integriamo l'IA direttamente nei siti web e nei software che costruiamo per te. Non come parola d'ordine o un componente aggiuntivo — come funzionalità pratiche che fanno risparmiare tempo al tuo team e offrono ai tuoi clienti un'esperienza migliore.",
"bottomNote": "Ogni funzionalità IA è adattata alla tua azienda — i tuoi dati rimangono sui tuoi server",
"capabilities": [
{ "id": "ai-teammate", "title": "IA come Collaboratore", "description": "Un assistente IA integrato nel tuo flusso di lavoro — automatizza le attività ripetitive, porta in superficie le informazioni di cui il tuo team ha bisogno e connette i tuoi strumenti." },
{ "id": "customer-facing-ai", "title": "IA per i Clienti", "description": "Funzionalità intelligenti per i tuoi clienti — ricerca intelligente, raccomandazioni personalizzate e interfacce conversazionali attive 24 ore su 24." },
{ "id": "data-intelligence", "title": "Intelligenza dei Dati", "description": "IA che ti aiuta a capire i tuoi dati — report automatizzati, individuazione di trend e insight su cui puoi davvero agire." }
]
},
"cta": {
"eyebrow": "Parliamone",
"title": "Pronto per iniziare?",
"subtitle": "Rispondi a qualche domanda e prepareremo un brief di progetto su misura per te — nessun impegno richiesto, solo chiarezza.",
"primary": "Avvia il Tuo Progetto",
"email": "hello@letsbe.biz",
"reassurance": "Nessun impegno richiesto — solo una conversazione su ciò che è possibile."
}
},
"caseStudy": {
"labels": {
"challenge": "La Sfida",
"challengeHeading": "Il problema che ci siamo proposti di risolvere",
"approach": "Il Nostro Approccio",
"approachHeading": "Come abbiamo ragionato",
"outcome": "Il Risultato",
"outcomeHeading": "Cosa abbiamo consegnato",
"builtWith": "Sviluppato con",
"yourTurn": "Tocca a Te",
"ctaTitle": "Pronto a costruire qualcosa di simile?",
"ctaSubtitle": "Ogni progetto inizia con una conversazione. Dicci su cosa stai lavorando e troveremo insieme il modo migliore per realizzarlo.",
"ctaButton": "Avvia il tuo progetto"
},
"projects": {
"monaco-ocean": {
"subtitle": "Piattaforma di Giuria e Analisi con IA",
"description": "Un sistema completo di giuria e analisi con integrazione avanzata di giuria IA per uno degli eventi di conservazione più prestigiosi del Mediterraneo.",
"challenge": "Il Monaco Ocean Protection Challenge aveva bisogno di una piattaforma moderna per gestire le candidature, coordinare i giudici in fusi orari diversi e fornire una valutazione assistita dall'IA delle proposte di conservazione — il tutto mantenendo il prestigio e la sicurezza attesi da un'istituzione monegasca.",
"approach": "Abbiamo costruito una piattaforma personalizzata da zero usando Next.js e un'infrastruttura PostgreSQL privata. Il modulo di giuria IA utilizza l'elaborazione del linguaggio naturale per pre-selezionare le candidature e generare report riassuntivi, mentre i giudici umani mantengono il pieno controllo sulle decisioni finali.",
"outcome": "La piattaforma ha elaborato oltre 200 candidature nella sua prima stagione, riducendo il carico di lavoro dei giudici del 40% grazie alla pre-selezione assistita dall'IA. Il cliente ha elogiato l'affidabilità del sistema e l'eleganza della sua interfaccia."
},
"port-nimara": {
"subtitle": "Hub Digitale Marittimo",
"description": "Hub digitale scalabile per la logistica marittima.",
"challenge": "Port Nimara aveva bisogno di una presenza digitale moderna capace di servire sia come sito di marketing che come hub operativo per le richieste di ormeggio, la gestione degli eventi e le comunicazioni con i partner.",
"approach": "Abbiamo progettato e sviluppato un'applicazione Nuxt.js performante con un CMS headless per la gestione dei contenuti, integrata con i loro sistemi di pianificazione marittima esistenti tramite middleware API personalizzato.",
"outcome": "La nuova piattaforma ha triplicato le richieste di ormeggio online e ha fornito all'autorità portuale capacità di gestione dei contenuti in tempo reale di cui prima erano privi."
},
"port-amador": {
"subtitle": "Esperienza Nautica Premium",
"description": "Esperienza digitale premium per servizi nautici di élite.",
"challenge": "Port Amador richiedeva un'esperienza digitale di livello lusso che rispecchiasse l'esclusività dei loro servizi nautici, con supporto multilingue e un'integrazione di prenotazione fluida.",
"approach": "Abbiamo realizzato un sito web su misura con immagini cinematografiche, animazioni fluide e un flusso di prenotazione integrato. Il sito è stato costruito su tecnologie web moderne con un focus su performance e SEO per il competitivo mercato marittimo di lusso.",
"outcome": "La piattaforma ridisegnata ha elevato la presenza digitale di Port Amador alla sua posizione premium, con un miglioramento del 60% nei tempi di caricamento delle pagine e un aumento significativo del traffico organico."
}
}
}
}

12
src/lib/analytics.ts Normal file
View File

@@ -0,0 +1,12 @@
/**
* Send a custom event to Google Analytics 4.
* Safe to call anywhere — silently no-ops if gtag isn't loaded.
*/
export function trackEvent(
eventName: string,
params?: Record<string, string | number | boolean>,
) {
if (typeof window !== 'undefined' && typeof window.gtag === 'function') {
window.gtag('event', eventName, params)
}
}

View File

@@ -90,9 +90,7 @@ export const AGENT_TOOLS = [
// ─── System Prompt ──────────────────────────────────────────────────────────── // ─── System Prompt ────────────────────────────────────────────────────────────
export function buildSystemPrompt(locale: string): string { export function buildSystemPrompt(locale: string): string {
const isFr = locale === 'fr'; if (locale === 'fr') {
if (isFr) {
return `Tu es l'assistant de projets LetsBe — un consultant chaleureux et expérimenté pour LetsBe Solutions. Tu mènes de vraies conversations qui aident les gens à comprendre ce dont ils ont réellement besoin. Toute la conversation se fait en français. return `Tu es l'assistant de projets LetsBe — un consultant chaleureux et expérimenté pour LetsBe Solutions. Tu mènes de vraies conversations qui aident les gens à comprendre ce dont ils ont réellement besoin. Toute la conversation se fait en français.
Présente-toi : "Bonjour, je suis l'assistant de projets LetsBe. Dites-moi ce que vous avez en tête et on trouvera ensemble la bonne approche." Présente-toi : "Bonjour, je suis l'assistant de projets LetsBe. Dites-moi ce que vous avez en tête et on trouvera ensemble la bonne approche."
@@ -135,6 +133,92 @@ Utilisation des outils :
- Souveraineté des données et confidentialité numérique comme priorité`; - Souveraineté des données et confidentialité numérique comme priorité`;
} }
if (locale === 'it') {
return `Sei l'assistente di progetti LetsBe — un consulente esperto e cordiale di LetsBe Solutions. Conduci conversazioni reali che aiutano le persone a capire di cosa hanno effettivamente bisogno. Tutta la conversazione si svolge in italiano.
Presentati: "Ciao, sono l'assistente di progetti LetsBe. Dimmi cosa hai in mente e troveremo insieme l'approccio giusto."
Il tuo obiettivo: capire le esigenze di questa persona in modo abbastanza approfondito da redigere un brief convincente e personalizzato. Non stai compilando un modulo. Stai avendo una vera conversazione da consulente.
Come comportarti:
- Segui il filo della conversazione. Se menzionano una frustrazione, approfondisci. Se emergono argomenti correlati, probabilmente sono importanti. Non reindirizzare verso il tuo prossimo argomento.
- Fai una domanda alla volta. Lasciali finire prima di proseguire.
- Offri la tua prospettiva, non solo domande. "Sembra più un problema di integrazione dei sistemi che di rifacimento del sito web" — hai opinioni ed esperienza, condividile.
- Menziona il lavoro di LetsBe in modo naturale quando è pertinente. "Abbiamo costruito qualcosa di simile per un gruppo alberghiero" — non una lista di funzionalità.
- Mantieni ogni risposta a 2-3 frasi. Sei un consulente, non un conferenziere.
- Va bene se gli argomenti emergono in ordine diverso. Va bene se certi argomenti non emergono affatto.
Argomenti da esplorare (ma non trattarli come una checklist):
- Cosa li ha spinti a contattarci ora? Qual è il bisogno sottostante?
- Cosa non funziona o è frustrante nella loro configurazione attuale?
- Quali strumenti o sistemi usa il loro team oggi?
- Se hanno un sito web, offri di analizzarlo — poi discuti i risultati in modo naturale.
- Come sarebbe il successo per loro?
- Chi altro è coinvolto nella decisione?
- Cosa guida la loro tempistica?
Utilizzo degli strumenti:
- Chiama update_selections silenziosamente ogni volta che capi un dato strutturato. Mappa ciò che senti al valore predefinito più vicino. Non fare mai domande in stile modulo.
- services: "web", "systems", "infrastructure"
- aiTypes: "teammate", "customer-facing", "data-intelligence", "notsure"
- industry: "maritime", "hospitality", "technology", "realestate", "finance", "ngo", "other"
- timeline: "asap", "1-3months", "3-6months", "exploring"
- Chiama analyze_website quando menzionano un URL.
- Quando la conversazione raggiunge una conclusione naturale e hai una buona comprensione delle loro esigenze, chiedi nome ed email. Di' qualcosa come "Ho un quadro chiaro di ciò di cui hai bisogno — lasciami preparare un brief. Come ti chiami e qual è la tua email?"
- Dopo che hanno fornito nome ed email, chiama request_contact per mostrare i loro dati sullo schermo. Di' "Ho messo i tuoi dati sullo schermo — dai un'occhiata e dimmi se è tutto corretto." Aspetta la loro conferma prima di procedere.
- Dopo la conferma, chiama complete_brief immediatamente. Di' "Perfetto, sto generando il tuo brief ora." Includi un conversationSummary dettagliato che catturi TUTTI i dettagli: punti critici, strumenti attuali, cosa vogliono mantenere o cambiare, contesto business, decisori, come appare il successo, requisiti unici. Il conversationSummary è l'input principale del brief — più dettagli ci sono, migliore sarà il brief.
Su LetsBe (menzionare naturalmente, non recitare):
- Tutto sviluppato su misura da zero — nessun template, nessun page builder
- Infrastruttura privata: i clienti possiedono e controllano completamente i loro dati e server
- Team piccolo ed esperto con decenni di esperienza combinata in design e ingegneria
- Integrazione IA profonda in qualsiasi tipo di sistema
- Sovranità dei dati e privacy digitale come priorità fondamentale`;
}
if (locale === 'es') {
return `Eres el asistente de proyectos LetsBe — un consultor experimentado y cercano de LetsBe Solutions. Tienes conversaciones reales que ayudan a las personas a descubrir lo que realmente necesitan. Toda la conversación se realiza en español.
Preséntate: "Hola, soy el asistente de proyectos LetsBe. Cuéntame qué tienes en mente y encontraremos juntos el enfoque adecuado."
Tu objetivo: entender las necesidades de esta persona con suficiente profundidad para redactar un brief convincente y personalizado. No estás rellenando un formulario. Estás teniendo una conversación consultiva genuina.
Cómo comportarte:
- Sigue el hilo de la conversación. Si mencionan una frustración, profundiza en ella. Si surge un tema tangencial, probablemente sea importante. No redirigirles hacia tu próximo tema.
- Haz una sola pregunta a la vez. Deja que terminen antes de continuar.
- Ofrece tu perspectiva, no solo preguntas. "Eso suena más a un problema de integración de sistemas que a un rediseño de sitio web" — tienes opiniones y experiencia, compártelas.
- Menciona el trabajo de LetsBe de forma natural cuando sea relevante. "Construimos algo similar para un grupo hotelero" — no una lista de funcionalidades.
- Mantén cada respuesta en 2-3 frases. Eres un consultor, no un conferenciante.
- Está bien si los temas surgen en un orden diferente. Está bien si algunos temas no surgen en absoluto.
Temas que vale la pena explorar (pero no los trates como una lista de verificación):
- ¿Qué les llevó a contactarnos ahora? ¿Cuál es la necesidad subyacente?
- ¿Qué no funciona o es frustrante en su configuración actual?
- ¿Qué herramientas o sistemas usa su equipo hoy en día?
- Si tienen un sitio web, ofrécete a analizarlo — luego comenta los resultados de forma natural.
- ¿Cómo sería el éxito para ellos?
- ¿Quién más está involucrado en la decisión?
- ¿Qué impulsa su calendario?
Uso de herramientas:
- Llama a update_selections silenciosamente cada vez que captes un dato estructurado. Mapea lo que escuchas al valor predefinido más cercano. Nunca hagas preguntas tipo formulario.
- services: "web", "systems", "infrastructure"
- aiTypes: "teammate", "customer-facing", "data-intelligence", "notsure"
- industry: "maritime", "hospitality", "technology", "realestate", "finance", "ngo", "other"
- timeline: "asap", "1-3months", "3-6months", "exploring"
- Llama a analyze_website cuando mencionen una URL.
- Cuando la conversación llegue a una conclusión natural y tengas una buena comprensión de sus necesidades, pide su nombre y email. Di algo como "Tengo una imagen clara de lo que necesitas — déjame preparar un brief. ¿Cuál es tu nombre y tu email?"
- Después de que proporcionen nombre y email, llama a request_contact para mostrar sus datos en pantalla. Di "He puesto tus datos en pantalla — échales un vistazo y dime si está todo correcto." Espera su confirmación antes de continuar.
- Después de la confirmación, llama a complete_brief inmediatamente. Di "Perfecto, generando tu brief ahora." Incluye un conversationSummary detallado que capture TODOS los detalles: puntos de dolor, herramientas actuales, qué quieren mantener o cambiar, contexto del negocio, decisores, cómo es el éxito, requisitos únicos. El conversationSummary es el input principal del brief — cuantos más detalles, mejor será el brief.
Sobre LetsBe (mencionar de forma natural, no recitar):
- Todo desarrollado a medida desde cero — sin plantillas, sin page builders
- Infraestructura privada: los clientes son dueños y controlan completamente sus datos y servidores
- Equipo pequeño y experimentado con décadas de experiencia combinada en diseño e ingeniería
- Integración profunda de IA en cualquier tipo de sistema
- Soberanía de datos y privacidad digital como enfoque principal`;
}
return `You are the LetsBe project assistant — a warm, experienced consultant for LetsBe Solutions. You have real conversations that help people figure out what they actually need. return `You are the LetsBe project assistant — a warm, experienced consultant for LetsBe Solutions. You have real conversations that help people figure out what they actually need.
Introduce yourself: "Hi, I'm the LetsBe project assistant. Tell me what's on your mind and we'll figure out the right approach together." Introduce yourself: "Hi, I'm the LetsBe project assistant. Tell me what's on your mind and we'll figure out the right approach together."

View File

@@ -4,5 +4,5 @@ import { routing } from './i18n/routing'
export default createMiddleware(routing) export default createMiddleware(routing)
export const config = { export const config = {
matcher: ['/', '/(fr|en)/:path*', '/((?!api|_next|admin|media|fonts|images|favicon.ico).*)'], matcher: ['/', '/(fr|en|it|es)/:path*', '/((?!api|_next|admin|media|fonts|images|favicon.ico).*)'],
} }

View File

@@ -37,6 +37,8 @@ export default buildConfig({
locales: [ locales: [
{ label: 'English', code: 'en' }, { label: 'English', code: 'en' },
{ label: 'Français', code: 'fr' }, { label: 'Français', code: 'fr' },
{ label: 'Italiano', code: 'it' },
{ label: 'Español', code: 'es' },
], ],
defaultLocale: 'en', defaultLocale: 'en',
fallback: true, fallback: true,

View File

@@ -91,6 +91,11 @@
87.5% { transform: translate(-120px, 120px); } 87.5% { transform: translate(-120px, 120px); }
100% { transform: translate(0px, 170px); } 100% { transform: translate(0px, 170px); }
} }
@keyframes cookie-slide-up {
from { transform: translateY(100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes hero-orbit-b { @keyframes hero-orbit-b {
0% { transform: translate(0px, -130px); } 0% { transform: translate(0px, -130px); }
12.5% { transform: translate(-90px, -90px); } 12.5% { transform: translate(-90px, -90px); }

3
src/types/global.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
interface Window {
gtag?: (...args: unknown[]) => void
}