Commit Graph

133 Commits

Author SHA1 Message Date
499109f8a9 Merge pull request 'chore(site): cache-bust translations.js' (#20) from chore/cache-bust-translations into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-06-03 12:32:21 +03:00
Serge RAKOTO HARRY-NAIVO
43e576249c chore(site): cache-bust translations.js (?v=20260603)
translations.js a Cache-Control max-age=7j sans versioning -> les visiteurs
gardaient l'ancien menu en cache. Cache-buster pour rendre le renommage
Contact->Inscription visible immédiatement par tous.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:32:13 +02:00
5399fc1a40 Merge pull request 'feat(site): Contact -> Inscription (menu + page)' (#19) from fix/contact-to-inscription into main
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-06-03 12:21:47 +03:00
Serge RAKOTO HARRY-NAIVO
61a2a67b00 feat(site): renomme "Contact" en "Inscription" (menu + page contact)
- Menu : "Contact" -> "Inscription" (FR) / "Sign Up" (EN) / "Fisoratana anarana" (MG)
- Page : titre "Contactez-Nous" -> "Inscrivez-vous"
- Sous-titre : retire "Inscrivez-vous et" -> "Commencez à envoyer vos colis dès aujourd'hui"
- i18n (translations.js, 3 langues) + fallback HTML en dur sur toutes les pages
- footer "Contact" (coordonnées) laissé inchangé

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:21:15 +02:00
2a2ea2f5e4 Merge pull request 'fix: relayer token_hash vers le deep link reset password' (#18) from fix/reset-password-token-hash into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-05-30 06:04:51 +03:00
Serge RAKOTO HARRY-NAIVO
df8bf01759 fix: relayer token_hash vers le deep link reset password
Le nouveau flux reset (Edge Function mva-password-reset, deploye 2026-05-30)
envoie un lien ?token_hash=HASH&type=recovery au lieu de ?token=. La page-relais
lit desormais token_hash + type et construit le deep link
mvaglobalfret://reset-password?token_hash=...&type=... que l'app consomme via
verifyOtp({ token_hash, type }). Si token_hash est absent, on affiche un message
d'erreur (lien invalide) au lieu de tenter le redirect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 04:49:51 +02:00
ee17b2b48c Merge pull request 'feat(guide): add armes � feu + substances ill�gales aux articles interdits' (#16) from feat/add-firearms-illegal-substances into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-05-22 02:02:45 +03:00
Serge RAKOTO HARRY-NAIVO
84b4b7753e feat(guide): add armes à feu in Explosifs + substances illégales in Substances toxiques
Demande Serge — clarifier les articles interdits sur mva-globalfret.com/guide-envoi.html.

Changes :
- guide-envoi.html : append 'armes à feu' à cat1Desc + 'substances illégales' à cat6Desc (visible immédiat sans JS i18n).
- js/translations.js : sync les 3 langues FR/EN/MG sur cat1Desc + cat6Desc.

FR : armes à feu / substances illégales
EN : firearms / illegal substances
MG : basy / zavatra tsy ara-dalàna

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 01:02:14 +02:00
b6b492f224 Merge pull request 'chore: remove decommissioned cloudflare-worker' (#15) from chore/remove-decommissioned-cloudflare-worker into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-05-16 17:41:54 +03:00
Serge RAKOTO HARRY-NAIVO
32c7d65698 chore: remove decommissioned cloudflare-worker
Le worker hubspot-proxy.js a ete decommissione le 2026-05-10 :
migration HubSpot CRM -> mva-api Fastify + Postgres + Resend (= mention
explicite dans js/form-handler.js).

Le dossier cloudflare-worker/ (DEPLOIEMENT.md + hubspot-proxy.js + wrangler.toml)
n'est plus utilise par le frontend mais traine dans le repo. Cleanup.

Refs:
- js/form-handler.js commentaire 'Migration 2026-05-10 : remplace l ancien
  Cloudflare Worker mva-hubspot-proxy.sergemind4s.workers.dev (= decommissionne)
  par les routes mva-api Fastify. La DB Postgres remplace HubSpot Contacts.'
- Audit hygiene M4S 2026-05-16
2026-05-16 16:39:22 +02:00
24104ac9f4 Merge pull request 'fix(site): setup-password token length 64 -> 96' (#14) from fix/setup-token-length-96 into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-05-11 00:14:37 +03:00
Serge RAKOTO HARRY-NAIVO
a6d219453c fix(site): setup-password.html validation token 64 -> 96 chars
Bug compagnon de api PR #57 : crypto.randomBytes(48).toString hex = 96
caracteres, pas 64. La validation JS cote site rejetait tous les vrais
tokens avec 'Lien invalide ou incomplet'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:14:30 +02:00
2878e8e01a Merge pull request 'feat(site): page setup-password.html (bridge lead -> user)' (#13) from feat/setup-password-page into main
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-10 23:31:46 +03:00
Serge RAKOTO HARRY-NAIVO
af58c04776 feat(site): page setup-password.html pour bridge lead -> user
Compagnon de api PR #55 (bridge lead -> user).

Flow:
- Lead clique email setup compte
- Arrive sur /setup-password.html?token=XXX
- JS POST /auth/lookup-setup-token pre-remplit email + firstname + ref
- Form 2 password avec validation (min 8 majuscule chiffre)
- Submit POST /auth/setup-from-lead -> user cree + JWT
- Affiche success + lien vers application.html pour download app

Design: card centree, MVA gold/navy, mobile responsive, vanilla JS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:31:36 +02:00
61397720e8 Merge pull request 'feat(api): migrate Worker mva-hubspot-proxy → mva-api /leads/* routes' (#12) from feat/migrate-worker-to-mva-api into main
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-10 14:02:18 +03:00
Serge RAKOTO HARRY-NAIVO
7217f12bd2 feat(api): migrate Worker mva-hubspot-proxy → mva-api /leads/* routes
Le Cloudflare Worker hubspot-proxy était une solution temporaire car
le panel admin AdminJS n'était pas encore disponible. Maintenant qu'
AdminJS marche, on rapatrie tout le flow inscription côté MVA backend.

## Changements

- `js/form-handler.js`
  - WORKER_PROXY_URL → API_BASE_URL = https://api.mva.mind4solutions.com
  - checkExistingContact : POST /leads/check-email
    (response shape : {exists, firstname, reference_client})
  - setupContactForm : POST /leads/request-verification
  - sendWelcomeBackEmail : POST /leads/welcome-back

- `js/confirmation.js`
  - WORKER_PROXY_URL → API_BASE_URL
  - POST /leads/verify-token (= au lieu de Worker action verifyToken)
  - Detection token expiré/invalide via code INVALID_OR_EXPIRED

## Aucun changement HTML

Les forms HTML, IDs des éléments, validation côté client, gestion
Turnstile sont tous inchangés. Seules les URLs API changent.

## Côté backend (PR #44 mva-prestige-v2)

Les routes mva-api /leads/* sont déployées séparément avec :
- Validation Zod + Turnstile + rate limit
- DB Postgres (table leads + leads_pending) remplace HubSpot Contacts + KV
- Resend pour les emails (= unification écosystème M4S)
- AdminJS Resource leads pour Mélissa CRUD

## Cutover

Cette PR doit être merged + déployée APRÈS la migration backend
(PR #44) + après le run du script migrate-hubspot-to-postgres.js
(= les 4 contacts HubSpot existants en DB).
2026-05-10 11:34:07 +02:00
bc919b07e0 Merge pull request 'fix(reset-password): redirect to mvaglobalfret:// custom scheme' (#11) from fix/reset-password-deep-link-mva into main
Some checks failed
Deploy site to GitHub Pages / deploy (push) Has been cancelled
2026-05-07 22:31:54 +03:00
Serge RAKOTO HARRY-NAIVO
605fa63f70 fix(reset-password): redirect to mvaglobalfret:// custom scheme for mva-api tokens
Le bridge HTML redirige maintenant vers le custom scheme natif
mvaglobalfret://reset-password?token=... au lieu de
https://auth.mind4solutions.com/reset-password.

Le flow Supabase (auth.m4s.com / Phase 2.1) ne sait pas valider les
tokens UUID custom émis par mva-api (Fastify). Sans ce fix, les emails
reset password Cluster A B2 atterriraient sur une page d'erreur
"Lien invalide".

UI fallback HTML conservée + bouton CTA stylé pour les cas où le
deep-link automatique ne déclenche pas l'app (browser desktop, app
non installée).

Fixes Cluster A B2 blocker (= session 2026-05-07 MVA app).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 21:27:59 +02:00
2774c25a61 chore: post-review cleanup (3 Important + dead code purge -116 lines) (#10)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 18:37:10 +03:00
e14b0ff01a fix(worker): restore original Ravis de vous revoir email template (#9)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 17:07:36 +03:00
5c34e59a8d feat(worker): re-enable welcome-back email via Worker + Resend (footer 2026) (#8)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 16:43:58 +03:00
db43583a62 fix(js): animate-on-scroll threshold 0.1 ? 0 (mobile cgv + politique invisible bug) (#7)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 16:37:39 +03:00
5b84e5697e chore(post-cutover): fix 3 polish bugs (welcome-back, mobile lang switcher, animate-on-scroll) (#6)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 16:36:28 +03:00
5f88891a83 fix(worker): replace Forms API submission with CRM API direct (#5)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 16:10:11 +03:00
10960e8ae1 feat(cloudflare): point HTML/JS to new Mind4Solutions Worker + Turnstile sitekey (#4)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 15:28:23 +03:00
483195711e refactor(worker): Brevo+EmailJS ? Resend + remove cron + fix github.io URLs (#3)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 15:27:41 +03:00
2d3526da06 feat(seo): sitemap + robots.txt + mobile reset-password bridge (#2)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 01:04:05 +03:00
c973b67ec9 feat(images): self-host hero photos from Unsplash (#1)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
2026-05-07 01:01:54 +03:00
MVA Global Fret
713168ecbe Update hosting info: GitHub Pages → Hostinger VPS (Falkenstein)
Some checks are pending
Deploy site to GitHub Pages / deploy (push) Waiting to run
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-06 20:28:00 +02:00
MVA Global Fret
70f8f86c7a Add Mentions Légales & Politique de Confidentialité pages
Create two new legal pages (FR/EN/MG) with LAATEL Corporation
company details (STAT, RCS, NIF). Add footer links to all pages
and translation keys for the three languages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-06 20:05:39 +02:00
8f51ef794a
Merge pull request #3 from MVA-Global-Fret/migration-brevo
confirmation.html: center button text in action row
2026-05-06 16:57:18 +02:00
MVA Global Fret
77baadffba confirmation.html: center button text in action row
The .btn class uses display:inline-flex with align-items:center but
no justify-content, so text stuck to the left when the parent flex
stretched the buttons to fill the row. Add justify-content:center
scoped to the confirmation card actions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 16:54:40 +02:00
c12f273e24
Merge pull request #2 from MVA-Global-Fret/migration-brevo
Worker: use Forms API for contact creation (no scope required)
2026-05-06 15:57:21 +02:00
MVA Global Fret
2b148a8682 Worker: use Forms API for contact creation (no scope required)
Direct CRM API needed crm.objects.contacts.write scope which the
existing Personal Access Key doesn't have. Using HubSpot Forms API
instead — same endpoint the browser used to call directly, but now
called server-side from the Worker after email verification.

This means HubSpot contact creation works without granting any
additional scopes to the token: anyone can submit a public form.

Also updates the welcome email warning to tell the customer to copy
the address EXACTLY as shown (the reference is now baked into line 1
of the address) and not to modify anything.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:54:58 +02:00
c66ca36620
Merge pull request #1 from MVA-Global-Fret/migration-brevo
Migration brevo
2026-05-06 14:00:51 +02:00
MVA Global Fret
07ccec0808 Anti-spam: only register HubSpot contact AFTER email confirmation
Previously the Forms API created the contact at form submission time —
which meant unverified signups (bots that pass Turnstile, typos, fake
emails) polluted HubSpot. Now:

- Form submit → Worker stores all data in KV (24h TTL) + sends Brevo
  verification email (no HubSpot write)
- User clicks email link → Worker generates ref + creates HubSpot
  contact via CRM API + sends welcome email with ref + Paris address

Plus this commit:
- Email header gets the MVA logo on the left of the dark blue banner
- Welcome email's first address line auto-injects (MVA-XXX) so the
  customer can copy it directly onto their package

Also handles idempotency — clicking the verification link a second time
returns the existing ref without creating a duplicate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 13:50:32 +02:00
MVA Global Fret
82bc8ba358 Switch from Resend to Brevo for transactional emails
Resend requires a verified domain to send to arbitrary recipients —
mvaglobalfret.com isn't registered. Brevo accepts single-sender
verification on a free email address, so we can send from
mvaglobalfret@gmail.com without owning a domain.

- Worker: replace resendSend() with brevoSend() (api.brevo.com/v3/smtp/email)
- Env vars: BREVO_API_KEY, BREVO_SENDER_EMAIL, BREVO_SENDER_NAME
- Update comments in confirmation.js and form-handler.js

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 12:26:50 +02:00
MVA Global Fret
eb5c4f1cee Email verification flow via Resend (Turnstile + click-to-confirm)
Architecture finale :

1. User remplit formulaire + passe Turnstile CAPTCHA → form-handler.js
2. form-handler.js POST au Worker avec action 'requestVerification'
3. Worker valide Turnstile, génère un token UUID, le stocke en KV (TTL 24h)
   avec firstname/email/reference_client, puis envoie un email via Resend
   avec un lien : confirmation.html?token=XXX
4. User reçoit email, clique 'Confirmer mon email'
5. confirmation.html lit le token de l'URL, POST au Worker avec action
   'verifyToken'
6. Worker valide le token, envoie le welcome email via Resend (avec ref +
   adresse Paris depuis env var), marque le token comme utilisé
7. confirmation.html affiche 'Inscription confirmée !'

Ainsi : ref + adresse Paris ne sortent JAMAIS avant validation email,
et les bots sont bloqués à l'étape 1 par Turnstile.

Setup Cloudflare requis (côté user) :
- RESEND_API_KEY  : clé API Resend (re_...)
- RESEND_FROM     : adresse expéditrice ('onboarding@resend.dev' pour test,
                    ou domain vérifié pour prod)
- SITE_URL        : optionnel, défaut https://mva-global-fret.github.io/site-mva-global-fret

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 10:59:26 +02:00
MVA Global Fret
a3a36df811 Anti-spam: add Cloudflare Turnstile (CAPTCHA) on registration form
- contact.html: ajout du widget Turnstile (site key: 0x4AAAAAADKDuc7Rmlb1svIL)
- form-handler.js: blocage de la soumission si pas de token Turnstile valide
- Worker: validation server-side du token via /turnstile/v0/siteverify
  avant chaque appel sendWelcomeNow → bloque les bots qui n'auraient
  pas passé le challenge côté client.

Le secret Turnstile est en env var Cloudflare (TURNSTILE_SECRET).

Limite humain : Turnstile détecte les bots avec très peu d'interaction
côté utilisateur (mode 'Managed', le plus souvent invisible).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 10:47:29 +02:00
MVA Global Fret
313c870ea4 Fix bugs inscription: ref dupliquée + email de bienvenue manquant
Bug 1 — Ref MVA-001 dupliquée :
Le filtre HubSpot 'HAS_PROPERTY' avec value:'' retournait 0 résultats.
Suppression du value:'' → maintenant le worker liste correctement les
contacts avec reference_client et incrémente bien (testé : MVA-004).

Bug 2 — Email post-inscription jamais reçu :
Le double opt-in HubSpot ne se déclenche pas via Forms API sans
subscription consent (impossible à configurer sans nouveaux scopes
Private App). Pivot vers une approche plus simple :
- L'email de bienvenue est désormais envoyé directement après
  soumission du formulaire (pas de DOI HubSpot)
- L'envoi passe par le Cloudflare Worker (action sendWelcomeNow)
  pour que l'adresse Paris reste dans les env vars Cloudflare et
  ne soit JAMAIS dans le JS public
- Worker appelle EmailJS REST avec firstname + reference + paris_address

Cleanup : message de succès reverti à 'Inscription réussie' (FR/EN/MG).

Anti-spam : protection légère via filtre email/téléphone côté formulaire.
La cron-based welcome (post-DOI) reste en place mais sera inerte tant
que aucun contact n'a le statut CONFIRMED côté HubSpot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:52:48 +02:00
MVA Global Fret
e1032b1405 Service Commande: redesign 'Et le transport ?' card
Avant : layout row asymétrique, icône en coin haut-gauche, bouton outline
qui flotte, hiérarchie visuelle plate.

Maintenant :
- Carte centrée 560px max, padding plus respirant, bordure or 6px en haut
- Icône 84px navy/or avec drop-shadow → gros pop visuel
- Prix éclaté : '70 000' en gros chiffre, 'Ar / kg' en doré accent
- Description plus compacte, contenue à 440px
- Bouton primary (or solide) avec flèche animée au hover
- Variant mobile (<480px) avec tailles réduites

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:40:14 +02:00
MVA Global Fret
0ef9f01fd9 Worker: cron post-confirmation pour envoyer le welcome email après opt-in
Architecture finale (Option A choisie) :

1. User submit form → contact créé en HubSpot avec reference_client
2. HubSpot envoie l'email de double opt-in (sans la ref ni l'adresse Paris)
3. User clique 'Confirmer' → HubSpot met hs_emailconfirmationstatus = CONFIRMED
4. Cron Cloudflare (toutes les 5 min) :
   - Liste les contacts CONFIRMED + créés après le cutoff
   - Filtre via Cloudflare KV (welcomed:<email>) pour idempotence
   - Envoie le welcome email via EmailJS REST API avec :
     • firstname
     • reference_client
     • paris_address (depuis env var PARIS_DEPOT_ADDRESS)
   - Marque envoyé dans KV avec TTL 1 an

Protection :
- L'adresse du dépôt Paris ne quitte JAMAIS Cloudflare/EmailJS
- Elle n'arrive au client que dans le mail de bienvenue post-opt-in
- Bots qui n'ont pas un vrai email ne peuvent pas valider → ne reçoivent rien
- Anti-spam et anti-cartons-vides blindé

Ajout d'une action 'triggerWelcomeQueue' pour debug/manual run.
Doc complète dans cloudflare-worker/DEPLOIEMENT.md (étapes 1 à 6).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 23:24:26 +02:00
MVA Global Fret
f534376f90 Add post-confirmation page that triggers welcome email after double opt-in
Flux complet du double opt-in :
1. User soumet le formulaire → contact créé en HubSpot avec sa référence
2. HubSpot envoie un email 'Confirmez votre inscription'
3. User clique 'Confirmer' → HubSpot le marque 'subscribed'
4. HubSpot redirige vers confirmation.html?email=...
5. La page lit l'email, appelle le Worker Cloudflare pour récupérer la
   référence du contact, et déclenche l'envoi de l'email de bienvenue
   via EmailJS (avec la référence dedans)
6. Affiche succès + référence à l'écran

Idempotence via localStorage pour éviter de spammer l'email à chaque
rechargement de la page.

À configurer dans HubSpot Settings > Marketing > Email > Confirmation
d'inscription : URL de redirection après confirmation =
https://mva-global-fret.github.io/site-mva-global-fret/confirmation.html?email={{contact.email}}

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 23:03:19 +02:00
MVA Global Fret
c713d40946 Contact: ne plus afficher la référence avant validation email
- Retire le bloc 'Numéro de référence client' de la page de succès
- Met à jour le message en FR/EN/MG : 'Vous recevrez ensuite votre numéro
  de référence client' après confirmation
- Désactive l'envoi immédiat de l'email EmailJS de bienvenue (qui
  contenait déjà la référence). HubSpot envoie son email de
  double opt-in qui sera customisé pour inclure la référence
  via le token {{contact.reference_client}}.

Résultat : la référence n'est jamais visible avant que l'email ne soit
vérifié (puisque seuls les emails valides reçoivent le double opt-in).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:53:23 +02:00
MVA Global Fret
c2e3b1e0d5 Contact: clarify double opt-in flow on success message
HubSpot double opt-in is now enabled at the account level. After
submitting the form, contacts must click the confirmation link in
their email to be added to the marketing list.

The success message now explicitly tells the user to check their
inbox and click the confirmation link, instead of just saying
'inscription enregistrée'.

- title: 'Vérifiez votre boîte mail !' (FR), 'Check your inbox!' (EN), 'Jereo ny boaty mailaka!' (MG)
- main msg: focus on confirmation step
- icon: enveloppe-circle-check (gold) instead of generic green check
- note: nuance that the reference number is for tracking parcels
- emailSent: kept as is (informative footer)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:45:30 +02:00
MVA Global Fret
5ab50dae3b Tarifs: 'Livraison en Province' = à partir de 6 000 Ar (FR/EN/MG)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:23:54 +02:00
MVA Global Fret
422690c194 Intro: bouton 'Accéder au site' visible immédiatement, sans animation
- Retire l'état caché (scale 0.05 / opacity 0 / offset -27vh)
- Retire les transitions de révélation (transform/opacity 2.2s)
- Retire l'animation de pulse halo (.cta-btn::after)
- Retire le déclenchement JS via la classe .revealed (l'avion qui croise le centre n'a plus d'effet sur le bouton)

Le bouton est désormais centré au milieu du viewport dès le chargement,
toujours cliquable. Hover conserve le scale 1.04 + shine effect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:21:30 +02:00
MVA Global Fret
8ba9fc9161 Service Commande: stack transport card on mobile (button no longer cropped)
Avant : flex row figé même sur mobile → l'icône 60px écrasait la colonne
texte → le bouton 'Voir nos tarifs détaillés' wrappait sur 2 lignes
avec un cadre asymétrique.

Maintenant : sous 600px de large, le layout passe en colonne (icône
au-dessus, contenu centré). Bouton avec white-space: nowrap pour rester
sur 1 ligne. Sur desktop (>=600px), le layout reste en row classique.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:07:51 +02:00
MVA Global Fret
e58e3d674d Mobile menu: scrollable + dvh height fix
- overflow-y: auto pour scroll vertical quand le menu déborde
- height: 100dvh (dynamic viewport) pour meilleur rendu mobile (barre URL)
- -webkit-overflow-scrolling: touch (smooth iOS)
- overscroll-behavior: contain (pas de scroll-chain sur le body en dessous)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:05:45 +02:00
MVA Global Fret
72da4fcfd5 Contact: full gold border around price-reminder block
Avant: border-left 4px (juste à gauche).
Maintenant: border 2px tout autour pour bien encadrer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:03:44 +02:00