feat(marketing): PAS frame sections (Problème + Solution) after trust bar

- Problème section (light bg-brand-bg, white cards): 3 risk cards
  (Cloud Act, Loi 25 biométrie art. 60.1 LPRPSP, sanctions disciplinaires
  9 ordres pros). H2 grad-text accent on 'violent la Loi 25' — defensible
  legal claim citing CAI + LPRPSP statutes by name. text-brand-navy/70 for
  all body text (WCAG AA compliant, no /40 or /50 regression).
- Solution section (bg-brand-navy with single subtle green orb): 3 pillars
  (100% local, Conforme Loi 25, Précision FR-CA). H2 grad-text accent on
  'par design'. Pillars cite specific tech (WhisperX Large-v3, Mistral 7B,
  pyannote, OVH Beauharnois, AGPL v3) — all factually verifiable.
- French typography: NBSP via   + |safe before %, $, and within
  'Loi 25' to prevent line break separation (OQLF rule).
- 4 new tests verify both sections, 3 cards each, key tech mentions,
  and WCAG-safe opacity policy.
This commit is contained in:
Allison
2026-04-27 17:42:46 -04:00
parent 54168e443b
commit 3c471a72d1
3 changed files with 110 additions and 1 deletions

File diff suppressed because one or more lines are too long

View File

@@ -118,4 +118,70 @@
</p>
</div>
</section>
{# ===== PROBLÈME (P de PAS) ===== #}
<section class="bg-brand-bg py-20" aria-labelledby="probleme-title">
<div class="max-w-[1200px] mx-auto px-6">
<div class="text-center max-w-2xl mx-auto mb-12">
<p class="eyebrow grad-text mb-4">LE PROBLÈME — TRANSCRIPTION CLOUD</p>
<h2 id="probleme-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4">
Vos réunions confidentielles dans Teams Copilot ou Otter.ai
<span class="grad-text">violent la Loi 25</span>.
</h2>
<p class="text-lg text-brand-navy/70">
Le transfert de données vocales hors-Québec sans consentement explicite expose les professionnels réglementés à des sanctions disciplinaires de leurs ordres et à des amendes CAI jusqu'à 25 M$ ou 4 % du chiffre d'affaires mondial.
</p>
</div>
{# 3 problem cards on white surface — Cloud Act, Loi 25, Sanctions #}
<div class="grid md:grid-cols-3 gap-6 mt-12">
{% for card in [
('Cloud Act', 'Loi américaine 2018', 'Microsoft, Google et OpenAI sont soumis au Cloud Act. Vos données peuvent être saisies par les autorités américaines sans votre consentement ni notification — y compris les enregistrements de vos réunions client.', '⚖️'),
('Loi 25 — biométrie', 'Sanction CAI jusqu\'à 25 M$', 'La voix est une donnée biométrique au sens de l\'article 60.1 LPRPSP. Tout traitement nécessite un consentement explicite, une déclaration CAI et un transfert vers un territoire offrant une protection équivalente — ce que les États-Unis n\'offrent pas.', '🛡️'),
('Sanctions disciplinaires', '252 000+ pros réglementés QC', 'Le Barreau du Québec, la Chambre des notaires, CPA Québec et 6 autres ordres considèrent le transfert de données client hors-juridiction sans accord exprès comme un manquement à l\'obligation de confidentialité — radiation possible.', '⚠️')
] %}
<article class="bg-white p-6 rounded-[0.75rem] border border-brand-border">
<div class="text-3xl mb-4" aria-hidden="true">{{ card[3] }}</div>
<h3 class="text-lg font-bold mb-1 text-brand-navy">{{ card[0] }}</h3>
<p class="text-xs uppercase tracking-wider text-brand-navy/70 mb-3 font-semibold">{{ card[1] }}</p>
<p class="text-sm text-brand-navy/70 leading-relaxed">{{ card[2] }}</p>
</article>
{% endfor %}
</div>
</div>
</section>
{# ===== SOLUTION (S de PAS) ===== #}
<section class="relative bg-brand-navy text-white py-20 overflow-hidden" aria-labelledby="solution-title">
{# Single subtle orb in solution bg — less busy than hero #}
<div class="absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full pointer-events-none" aria-hidden="true"
style="background: radial-gradient(circle, rgba(0,200,150,0.08) 0%, transparent 60%); filter: blur(60px);"></div>
<div class="relative max-w-[1200px] mx-auto px-6">
<div class="text-center max-w-2xl mx-auto mb-12">
<p class="eyebrow grad-text mb-4">LA SOLUTION — DICTIA</p>
<h2 id="solution-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4">
Conforme <span class="grad-text">par design</span>, pas par défaut.
</h2>
<p class="text-lg text-white/70">
DictIA reproduit la précision des outils cloud — WhisperX Large-v3 + Mistral 7B — mais avec une architecture où vos données ne quittent jamais vos murs ou nos serveurs OVH Beauharnois.
</p>
</div>
{# 3 solution pillars — dark cards with grad-bg icon corners #}
<div class="grid md:grid-cols-3 gap-6">
{% for pillar in [
('100&nbsp;% local', 'Vos données ne sortent jamais de vos murs. Inférence GPU sur place ou VPS Québec OVH Beauharnois — vous gardez le contrôle, l\'audit, et les clés.'),
('Conforme Loi&nbsp;25', 'Audit trail intégré (qui a écouté quoi, quand). Déclaration CAI prête. Consentement explicite tracé pour chaque enregistrement. Code source AGPL v3 — transparence vérifiable.'),
('Précision FR-CA', 'WhisperX Large-v3 fine-tuné français québécois. Diarisation pyannote 8 locuteurs. Résumés Mistral 7B local — aucune connexion OpenAI/Google/Microsoft.')
] %}
<article class="bg-white/[0.05] backdrop-blur-sm p-6 rounded-[0.75rem] border border-white/[0.08]">
<div class="w-10 h-10 grad-bg rounded-[0.5rem] mb-4 flex items-center justify-center font-black text-white shadow-cta" aria-hidden="true"></div>
<h3 class="text-lg font-bold mb-2 text-white">{{ pillar[0] | safe }}</h3>
<p class="text-sm text-white/70 leading-relaxed">{{ pillar[1] | safe }}</p>
</article>
{% endfor %}
</div>
</div>
</section>
{% endblock %}

View File

@@ -192,3 +192,46 @@ def test_trust_bar_has_methodology_footnote():
assert 'm&eacute;thodologie disponible sur demande' in body or 'méthodologie disponible sur demande' in body
assert 'audio professionnel qu&eacute;b&eacute;cois' in body or 'audio professionnel québécois' in body
assert 'info@dictia.ca' in body
def test_pas_probleme_section_present():
"""Problème section (P of PAS frame) is present after trust bar."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'PROBL' in body and 'TRANSCRIPTION CLOUD' in body, "Missing Problème eyebrow"
assert 'violent la Loi 25' in body, "Missing legal-risk H2 anchor phrase"
assert 'Cloud Act' in body, "Missing Cloud Act card"
assert 'biom' in body and 'Loi 25' in body, "Missing Loi 25 biometric card"
assert 'Sanctions disciplinaires' in body, "Missing sanctions disciplinaires card"
def test_pas_solution_section_present():
"""Solution section (S of PAS frame) is present after Problème."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert 'LA SOLUTION' in body and 'DICTIA' in body, "Missing Solution eyebrow"
assert 'Conforme' in body and 'par design' in body, "Missing solution H2"
assert 'WhisperX' in body, "Missing WhisperX mention"
assert 'Mistral 7B' in body, "Missing Mistral 7B mention"
assert 'OVH Beauharnois' in body, "Missing Quebec hosting mention"
def test_pas_solution_3_pillars_with_check_icon():
"""Solution has 3 pillars: 100% local, Conforme Loi 25, Précision FR-CA."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
assert '100&nbsp;%' in body and 'local' in body, "Missing 100% local pillar"
assert 'Conforme Loi&nbsp;25' in body or 'Conforme Loi&#160;25' in body, "Missing Conforme Loi 25 pillar"
assert 'Précision FR-CA' in body or 'Pr&eacute;cision FR-CA' in body, "Missing Précision FR-CA pillar"
assert 'AGPL v3' in body, "Missing AGPL v3 transparency mention"
def test_pas_uses_wcag_safe_text_opacity():
"""PAS section text uses /70 opacity (WCAG AA compliant), not /40 or /50."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
# Text on white surface in problem cards must use /70 minimum
# Check the problem card paragraph text uses navy/70 not navy/40 or /50
assert 'text-brand-navy/70 leading-relaxed' in body or 'text-brand-navy/70 mb-3' in body
# No regression to /40 in this section
# (Other sections may use /40 for decorative text — we just verify the new content uses /70)