feat(marketing): hero section with cosmic orbs + dual CTA + social proof

- 3 radial-gradient orbs (blue 16%, cyan 7%, green 11%) + subtle 40px
  grid + horizontal accent line — FlexiHub cosmic background signature
- H1 clamp(2.5rem,4vw,4rem) font-black with grad-text accent on
  'sans risquer votre permis' tagline
- Eyebrow 11px tracking-[0.18em] grad-text — 'TRANSCRIPTION IA · CONFORME LOI 25 · QUÉBEC'
- Sub-headline ≤25 words declares Loi 25 compliance + 9 ordres pros
- Dual CTA: Réserver une démo (primary gradient+glow) + Voir les tarifs
  → (ghost) — drives demo conversion + pricing self-service
- Social proof microcopy above-the-fold: 5★ + 27 cabinets + Lancement
  printemps 2026
- Staggered tc-fade-in-up animations 0/75/150/300/400ms with
  animation-fill-mode: backwards (no FOIT)
- 6 new tests verify H1 grad-text, dual CTA, orb opacities, social proof,
  staggered delays, eyebrow messaging
This commit is contained in:
Allison
2026-04-27 17:13:02 -04:00
parent 89e2fd29d1
commit 03af2a516d
3 changed files with 117 additions and 14 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,19 +1,62 @@
{% extends 'marketing/base.html' %}
{% block title %}Transcription IA conforme Loi 25 — DictIA pour avocats, CPA, secteur public{% endblock %}
{% block description %}DictIA transcrit vos réunions confidentielles 100% au Québec. Conforme Loi 25, Barreau, CPA, ChAD. Lancement printemps 2026 — 27 cabinets pilotes.{% endblock %}
{% block content %}
<section class="relative overflow-hidden bg-brand-navy text-white py-24 md:py-32">
<div class="max-w-[1200px] mx-auto px-6 text-center">
<p class="eyebrow grad-text mb-6">DICTIA · TRANSCRIPTION IA · CONFORME LOI 25</p>
<h1 class="text-[clamp(2.5rem,4vw,4rem)] font-black leading-[1.05] mb-6">
Refonte en cours — <span class="grad-text">printemps 2026</span>.
</h1>
<p class="text-lg text-white/70 max-w-2xl mx-auto mb-10">
La page marketing complète est en construction. Toutes les fonctionnalités de DictIA restent disponibles via votre compte.
{# ===== HERO ===== #}
<section class="relative overflow-hidden bg-brand-navy text-white py-24 md:py-32" aria-labelledby="hero-title">
{# Cosmic orbs background — 3 radial gradients (blue 16%, cyan 7%, green 11%) + subtle grid + horizontal accent line #}
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
{# Orb 1 — primary blue, top-left #}
<div class="absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full opacity-100"
style="background: radial-gradient(circle, rgba(0,98,255,0.16) 0%, transparent 60%); filter: blur(40px);"></div>
{# Orb 2 — cyan, mid-right #}
<div class="absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full"
style="background: radial-gradient(circle, rgba(0,189,216,0.07) 0%, transparent 60%); filter: blur(40px);"></div>
{# Orb 3 — accent green, bottom-left #}
<div class="absolute bottom-1/4 left-1/3 w-[400px] h-[400px] rounded-full"
style="background: radial-gradient(circle, rgba(0,200,150,0.11) 0%, transparent 60%); filter: blur(40px);"></div>
{# Subtle grid overlay (FlexiHub signature) #}
<div class="absolute inset-0"
style="background-image: linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px); background-size: 40px 40px;"></div>
{# Horizontal accent line — gradient blue→cyan→transparent #}
<div class="absolute top-1/3 left-0 right-0 h-px"
style="background: linear-gradient(90deg, transparent, rgba(0,98,255,0.3), rgba(0,189,216,0.2), transparent);"></div>
</div>
<div class="relative max-w-[1200px] mx-auto px-6">
<div class="max-w-3xl mx-auto text-center">
{# Eyebrow with gradient text and 0.18em tracking #}
<p class="eyebrow grad-text mb-6 animate-tc-fade-in-up" style="animation-delay: 0ms; animation-fill-mode: backwards;">
TRANSCRIPTION IA · CONFORME LOI 25 · QUÉBEC
</p>
<div class="flex flex-col sm:flex-row gap-3 justify-center">
{# H1 — clamp typography + grad-text accent on key phrase #}
<h1 id="hero-title" class="text-[clamp(2.5rem,4vw,4rem)] font-black leading-[1.05] mb-6 animate-tc-fade-in-up" style="animation-delay: 75ms; animation-fill-mode: backwards;">
Transcrivez vos réunions
<span class="grad-text">sans risquer votre permis</span>.
</h1>
{# Sub-headline — ≤25 words, value prop #}
<p class="text-lg text-white/70 max-w-2xl mx-auto mb-10 animate-tc-fade-in-up" style="animation-delay: 150ms; animation-fill-mode: backwards;">
DictIA convertit vos audio en texte, résumé et points d'action — 100% au Québec, conforme Barreau, CPA Québec, ChAD et 6 autres ordres professionnels.
</p>
{# Dual CTA — primary (demo) + secondary ghost (pricing) #}
<div class="flex flex-col sm:flex-row gap-3 justify-center animate-tc-fade-in-up" style="animation-delay: 300ms; animation-fill-mode: backwards;">
{% from 'macros/button.html' import button %}
{{ button('Réserver une démo', href='/contact', variant='primary', size='lg') }}
{{ button('Connexion', href='/login', variant='ghost', size='lg') }}
{{ button('Voir les tarifs →', href='/tarifs', variant='ghost', size='lg') }}
</div>
{# Social proof microcopy — above-the-fold trust signal #}
<p class="mt-8 text-sm text-white/50 animate-tc-fade-in-up" style="animation-delay: 400ms; animation-fill-mode: backwards;">
<span class="text-yellow-400" aria-hidden="true">★★★★★</span>
<span class="ml-2">27 cabinets québécois nous font confiance</span>
<span class="mx-2 text-white/30">·</span>
<span>Lancement printemps 2026</span>
</p>
</div>
</div>
</section>

View File

@@ -80,3 +80,63 @@ def test_landing_no_login_redirect_for_anonymous():
response = client.get('/', follow_redirects=False)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code} — possibly login_required regression"
def test_hero_has_h1_with_grad_text_accent():
"""Hero H1 contains grad-text span on the brand tagline."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'id="hero-title"' in body, "Missing hero-title id on H1"
assert 'grad-text' in body, "Missing grad-text class somewhere"
assert 'sans risquer votre permis' in body, "Missing key brand tagline"
def test_hero_has_dual_cta():
"""Hero has both primary (Réserver une démo) and ghost (Voir les tarifs) CTAs."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'href="/contact"' in body
assert 'href="/tarifs"' in body
assert 'Réserver une démo' in body or 'R&eacute;server une d&eacute;mo' in body
assert 'Voir les tarifs' in body
def test_hero_has_cosmic_orbs_background():
"""Hero has 3 radial gradient orbs (FlexiHub signature)."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
# Look for the 3 orb opacities (16% blue, 7% cyan, 11% green)
assert 'rgba(0,98,255,0.16)' in body, "Missing primary blue orb"
assert 'rgba(0,189,216,0.07)' in body, "Missing cyan orb"
assert 'rgba(0,200,150,0.11)' in body, "Missing green accent orb"
def test_hero_has_social_proof_microcopy():
"""Hero has '27 cabinets' social proof + Lancement printemps 2026."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert '27 cabinets' in body, "Missing social proof '27 cabinets'"
assert 'Lancement printemps 2026' in body, "Missing launch date"
def test_hero_has_staggered_animations():
"""Hero elements use tc-fade-in-up with staggered delays."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'animate-tc-fade-in-up' in body, "Missing fade-in animation"
assert 'animation-delay: 0ms' in body
assert 'animation-delay: 75ms' in body
assert 'animation-delay: 150ms' in body
assert 'animation-delay: 300ms' in body
assert 'animation-delay: 400ms' in body
assert 'animation-fill-mode: backwards' in body, \
"Missing animation-fill-mode (causes flash before delay fires)"
def test_hero_eyebrow_has_brand_messaging():
"""Hero eyebrow declares the 3 brand pillars."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'TRANSCRIPTION IA' in body
assert 'CONFORME LOI 25' in body
assert 'QU' in body # Either QUÉBEC or QU&Eacute;BEC