refactor(pricing): 3 Cloud en rangée + DictIA LOCAL bloc dédié 'Vous en êtes propriétaire'

Restructure _pricing_tiers.html : les 3 forfaits Cloud (Basic 189$/Essentiel 349$/Pro 549$ recommandé) sont maintenant en grid responsive 1/2/3 cols, et DictIA LOCAL est sorti de la grille principale pour devenir un bloc large dédié 'propriété' avec :

- badge 'Au Québec · par InnovA AI' (SVG map-pin, sans emoji 🇨🇦)
- H3 'Vous en êtes propriétaire.' avec grad-text
- 5 bullets checkmark (PC+GPU RTX, 100 % local, assemblé QC, installation incluse, achat direct < 34 700 $)
- CTA 'Voir les serveurs disponibles' → /contact?plan=dictia-local
- mockup serveur à droite (SVG rack + 6 specs : Interface web, PC gaming, RTX 5070 Ti 16 Go, WhisperX+Mistral, DictIA pré-installé, Votre propriété)
- pricing tagline visible '5 998 $ An 1 · 500 $/an dès An 2'
- decorative orbs background (b1 + b3) pour distinguer du grid Cloud

Aussi mis à jour /tarifs (H1 'Trois forfaits Cloud + DictIA LOCAL' au lieu de 'Quatre forfaits') et tests pour refléter le nouveau slug /contact?plan=dictia-local (au lieu du /checkout/dictia-local d'avant). Conserve V3 radii (rounded-none/rounded/rounded-full), palette brand (b1/b2/b3/navy), OQLF NBSP, ARIA WCAG, zéro emoji.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-28 21:28:46 -04:00
parent 1c4cafaf69
commit e06cba2123
5 changed files with 171 additions and 44 deletions

View File

@@ -399,6 +399,9 @@
.-top-20 {
top: calc(var(--spacing) * -20);
}
.-top-32 {
top: calc(var(--spacing) * -32);
}
.top-0 {
top: calc(var(--spacing) * 0);
}
@@ -453,6 +456,9 @@
.-right-24 {
right: calc(var(--spacing) * -24);
}
.-right-32 {
right: calc(var(--spacing) * -32);
}
.right-0 {
right: calc(var(--spacing) * 0);
}
@@ -489,6 +495,9 @@
.-bottom-24 {
bottom: calc(var(--spacing) * -24);
}
.-bottom-32 {
bottom: calc(var(--spacing) * -32);
}
.bottom-0 {
bottom: calc(var(--spacing) * 0);
}
@@ -507,6 +516,9 @@
.-left-20 {
left: calc(var(--spacing) * -20);
}
.-left-32 {
left: calc(var(--spacing) * -32);
}
.left-0 {
left: calc(var(--spacing) * 0);
}
@@ -1411,6 +1423,9 @@
.gap-8 {
gap: calc(var(--spacing) * 8);
}
.gap-10 {
gap: calc(var(--spacing) * 10);
}
.gap-\[1\.5px\] {
gap: 1.5px;
}
@@ -2132,6 +2147,9 @@
.bg-brand-navy2 {
background-color: #0b1525;
}
.bg-brand-navy3\/60 {
background-color: color-mix(in oklab, #0f1e35 60%, transparent);
}
.bg-emerald-600 {
background-color: var(--color-emerald-600);
}
@@ -5256,6 +5274,11 @@
padding: calc(var(--spacing) * 10);
}
}
.md\:p-12 {
@media (width >= 48rem) {
padding: calc(var(--spacing) * 12);
}
}
.md\:px-6 {
@media (width >= 48rem) {
padding-inline: calc(var(--spacing) * 6);
@@ -5434,6 +5457,11 @@
grid-template-columns: 1fr 240px;
}
}
.lg\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,420px\)\] {
@media (width >= 64rem) {
grid-template-columns: minmax(0,1fr) minmax(0,420px);
}
}
.lg\:flex-row {
@media (width >= 64rem) {
flex-direction: row;
@@ -5444,6 +5472,11 @@
gap: calc(var(--spacing) * 10);
}
}
.lg\:gap-12 {
@media (width >= 64rem) {
gap: calc(var(--spacing) * 12);
}
}
.lg\:border-r {
@media (width >= 64rem) {
border-right-style: var(--tw-border-style);

View File

@@ -1,11 +1,11 @@
{# Single source of truth for the v7.0 pricing — used by landing.html#tarifs and /tarifs page.
When prices change, edit ONLY this file (and src/billing/plans.py for Stripe IDs).
v7.0 — 4 forfaits + 1 soumission :
v7.0 — 3 forfaits Cloud (en rangée) + 1 DictIA LOCAL (bloc dédié) + 1 soumission :
- Cloud BASIC 189 $/mois (no setup)
- Cloud ESSENTIEL 349 $/mois (no setup)
- Cloud PRO 549 $/mois + 485 $ onboarding (recommended)
- DictIA LOCAL 5 998 $ An 1 puis 500 $/an dès An 2 (no monthly)
- DictIA LOCAL 5 998 $ An 1 puis 500 $/an dès An 2 (bloc large dédié, "Vous en êtes propriétaire")
- Pro+ soumission personnalisée → /contact?pro-plus=1
Common to all forfaits :
@@ -13,6 +13,7 @@
exports SRT/VTT/TXT/JSON/DOCX, Loi 25 conforme, OVH Beauharnois (Cloud) ou local. #}
{% from 'macros/pricing_card.html' import pricing_card %}
{% from 'macros/button.html' import button %}
{%- set _baseline_features_cloud = [
'WhisperX Large-v3 · 99&nbsp;%+ précision · 99+ langues',
@@ -24,7 +25,8 @@
'Aucune limite utilisateurs'
] -%}
<div class="grid md:grid-cols-2 lg:grid-cols-4 gap-6 items-stretch">
{# === Ligne 1 — 3 forfaits Cloud (1/2/3 cols responsive) === #}
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch">
{{ pricing_card(
slug='cloud-basic',
@@ -70,32 +72,116 @@
cta_label='Commander Pro'
) }}
{{ pricing_card(
slug='dictia-local',
name='DictIA LOCAL',
badge='Local · 100&nbsp;% hors-ligne',
target='Confidentialité maximale · 100&nbsp;% hors-ligne chez vous.',
setup=5998,
yearly_renewal=500,
capacity_audio='~1&nbsp;100&nbsp;h audio/mois',
capacity_storage='2&nbsp;To SSD',
gpu='RTX 5070&nbsp;Ti 16&nbsp;Go (dédié)',
features=[
'WhisperX Large-v3 · 99&nbsp;%+ précision · 99+ langues',
'Diarisation pyannote (qui parle)',
'Résumés IA + Points d&rsquo;action (Mistral 7B local)',
'Exports SRT, VTT, TXT, JSON, DOCX',
'GPU local dédié · transcription locale',
'Données jamais sortantes (chez vous)',
'500&nbsp;$/an dès An&nbsp;2 (MAJ + support)',
'Aucune limite utilisateurs'
],
cta_label='Configurer DictIA Local'
) }}
</div>
{# Pro+ banner — soumission personnalisée pour grands volumes / SLA renforcé #}
{# === Bloc 2 — DictIA LOCAL (large, distinctif, pleine largeur) === #}
<section class="mt-12 relative overflow-hidden bg-brand-navy2 border border-brand-border rounded p-8 md:p-12"
aria-labelledby="dictia-local-title">
{# Decorative orbs background — purely decorative, hidden from AT #}
<div class="absolute -top-32 -right-32 w-[500px] h-[500px] rounded-full pointer-events-none"
style="background: radial-gradient(circle, rgba(37,99,235,0.10) 0%, transparent 70%); filter: blur(60px);" aria-hidden="true"></div>
<div class="absolute -bottom-32 -left-32 w-[400px] h-[400px] rounded-full pointer-events-none"
style="background: radial-gradient(circle, rgba(192,38,211,0.08) 0%, transparent 70%); filter: blur(60px);" aria-hidden="true"></div>
<div class="relative grid lg:grid-cols-[minmax(0,1fr)_minmax(0,420px)] gap-10 lg:gap-12 items-center">
{# === LEFT — copy + checkmarks === #}
<div>
<div class="flex items-center gap-2 mb-4 flex-wrap">
<span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-brand-b1/10 border border-brand-b1/30 text-xs font-semibold text-brand-b1">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-3.5 h-3.5" aria-hidden="true"><path d="M12 2C8 2 5 5 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-4-3-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>
Au Québec
</span>
<span class="text-xs text-white/60">par InnovA AI</span>
</div>
<p class="eyebrow grad-text mb-2">DictIA LOCAL · Serveur souverain</p>
<h3 id="dictia-local-title" class="text-3xl md:text-4xl font-black text-white mb-4 leading-tight">
Vous en êtes <span class="grad-text">propriétaire</span>.
</h3>
<p class="text-base text-white/75 mb-6 leading-relaxed max-w-xl">
On vous vend, configure et installe votre serveur IA directement dans vos locaux. Vous êtes propriétaire du matériel. <strong class="text-white">Vos données ne quittent jamais votre bureau.</strong>
</p>
<ul class="space-y-3 mb-6" role="list">
{% for bullet in [
('PC + GPU RTX vous appartient', 'pas de location, pas d&rsquo;abonnement matériel'),
('Traitement 100&nbsp;% local', 'aucun transit réseau, fonctionne hors-ligne'),
('Assemblé et configuré au Québec par InnovA AI', 'support local inclus'),
('On vient l&rsquo;installer chez vous', 'formation incluse, opérationnel le jour&nbsp;1'),
('Achat direct sans appel d&rsquo;offres si &lt;&nbsp;34&nbsp;700&nbsp;$', 'DictIA LOCAL s&rsquo;y qualifie')
] %}
<li class="flex items-start gap-3 text-sm text-white/80">
<span class="flex-shrink-0 w-5 h-5 grad-bg flex items-center justify-center mt-0.5" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" class="w-3 h-3 text-white"><path d="M5 13l4 4L19 7"/></svg>
</span>
<span><strong class="text-white">{{ bullet[0] | safe }}</strong> — {{ bullet[1] | safe }}</span>
</li>
{% endfor %}
</ul>
<div class="flex flex-wrap gap-3 items-center">
{{ button('Voir les serveurs disponibles', href='/contact?plan=dictia-local', variant='primary', size='md', icon='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M14 5l7 7m0 0l-7 7m7-7H3"/></svg>') }}
<span class="text-sm text-white/60">5&nbsp;998&nbsp;$ An&nbsp;1 · 500&nbsp;$/an dès An&nbsp;2</span>
</div>
</div>
{# === RIGHT — server visual mockup === #}
<div class="relative">
<div class="bg-brand-navy3/60 border border-brand-b1/20 rounded p-6 backdrop-blur-sm">
<p class="eyebrow text-white/60 mb-3 text-center">GPU RTX — DictIA LOCAL</p>
<div class="flex flex-col items-center gap-4">
{# Server icon SVG (rack stylisé) — purely decorative #}
<div class="w-32 h-32 grad-bg flex items-center justify-center relative" aria-hidden="true">
<svg viewBox="0 0 64 64" fill="none" stroke="currentColor" stroke-width="2.5" class="w-16 h-16 text-white">
<rect x="8" y="10" width="48" height="14" rx="0"/>
<circle cx="14" cy="17" r="1.5" fill="currentColor"/>
<circle cx="20" cy="17" r="1.5" fill="currentColor"/>
<line x1="30" y1="17" x2="50" y2="17"/>
<rect x="8" y="28" width="48" height="14" rx="0"/>
<circle cx="14" cy="35" r="1.5" fill="currentColor"/>
<circle cx="20" cy="35" r="1.5" fill="currentColor"/>
<line x1="30" y1="35" x2="50" y2="35"/>
<rect x="8" y="46" width="48" height="14" rx="0"/>
<circle cx="14" cy="53" r="1.5" fill="currentColor"/>
<circle cx="20" cy="53" r="1.5" fill="currentColor"/>
<line x1="30" y1="53" x2="50" y2="53"/>
</svg>
</div>
<p class="text-center text-white font-bold text-base">Serveur DictIA</p>
<ul class="space-y-1.5 text-xs text-white/70 w-full" role="list">
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b2" aria-hidden="true"></span>
<span>Interface web</span>
</li>
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b2" aria-hidden="true"></span>
<span>PC gaming haute performance</span>
</li>
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b2" aria-hidden="true"></span>
<span>GPU RTX 5070&nbsp;Ti 16&nbsp;Go dédié IA</span>
</li>
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b2" aria-hidden="true"></span>
<span>WhisperX + LLM Mistral 7B local</span>
</li>
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b2" aria-hidden="true"></span>
<span>DictIA pré-installé</span>
</li>
<li class="flex items-center gap-2">
<span class="w-1 h-1 rounded-full bg-brand-b3" aria-hidden="true"></span>
<span class="font-semibold text-white">Votre propriété</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</section>
{# === Pro+ banner — soumission personnalisée pour grands volumes / SLA renforcé === #}
<div class="mt-10 max-w-5xl mx-auto p-6 bg-brand-navy text-white border border-brand-b2/30 rounded backdrop-blur-sm relative overflow-hidden">
<div class="absolute inset-0 pointer-events-none opacity-60" aria-hidden="true"
style="background: radial-gradient(circle at 100% 0%, rgba(192,38,211,0.12) 0%, transparent 55%), radial-gradient(circle at 0% 100%, rgba(6,182,212,0.10) 0%, transparent 55%);"></div>
@@ -107,7 +193,6 @@
&gt;&nbsp;660&nbsp;h audio/mois · &gt;&nbsp;500&nbsp;Go stockage · 7+ utilisateurs intensifs · multi-sites · SLA&nbsp;99,9&nbsp;% · SOC&nbsp;2 Type&nbsp;I/II · PHIPA · PIPEDA Ontario · documentation gouv. (SEAO/MCN).
</p>
</div>
{% from 'macros/button.html' import button %}
{{ button('Demander une soumission', href='/contact?pro-plus=1', variant='primary', size='md') }}
</div>
</div>

View File

@@ -1,7 +1,7 @@
{% extends 'marketing/base.html' %}
{% block title %}Tarifs DictIA — 4 forfaits transparents en CAD (Cloud Basic 189 $/mo · Essentiel 349 $ · Pro 549 $ · DictIA Local 5 998 $){% endblock %}
{% block description %}Tarifs DictIA en CAD : Cloud Basic (189 $/mo), Cloud Essentiel (349 $/mo), Cloud Pro (549 $/mo + 485 $ onboarding) et DictIA Local (5 998 $ An 1 puis 500 $/an). Aucune limite utilisateurs, taxes en sus.{% endblock %}
{% block title %}Tarifs DictIA — 3 Cloud + 1 serveur Local en CAD (Cloud Basic 189 $/mo · Essentiel 349 $ · Pro 549 $ · DictIA LOCAL 5 998 $){% endblock %}
{% block description %}Tarifs DictIA en CAD : Cloud Basic (189 $/mo), Cloud Essentiel (349 $/mo), Cloud Pro (549 $/mo + 485 $ onboarding) et DictIA LOCAL (5 998 $ An 1 puis 500 $/an, vous en êtes propriétaire). Aucune limite utilisateurs, taxes en sus.{% endblock %}
{% block content %}
@@ -10,18 +10,18 @@
<div class="max-w-[820px] mx-auto px-6 text-center">
<p class="eyebrow grad-text mb-4">TARIFS</p>
<h1 id="page-title" class="text-[clamp(2.25rem,4vw,3.5rem)] font-black mb-4">
Quatre forfaits&nbsp;: <span class="grad-text">choisissez votre infrastructure</span>.
Trois forfaits Cloud + DictIA&nbsp;LOCAL&nbsp;: <span class="grad-text">choisissez votre infrastructure</span>.
</h1>
<p class="text-lg text-white/80">
3 Cloud souverains au Québec + 1 100&nbsp;% local hors-ligne. Aucune limite utilisateurs, tarifs en CAD, taxes en sus (TPS&nbsp;5&nbsp;% + TVQ&nbsp;9,975&nbsp;%).
3 Cloud souverains hébergés au Québec + 1 serveur 100&nbsp;% local dont vous êtes propriétaire. Aucune limite utilisateurs, tarifs en CAD, taxes en sus (TPS&nbsp;5&nbsp;% + TVQ&nbsp;9,975&nbsp;%).
</p>
</div>
</section>
{# ===== 4 PRICING TIERS + Pro+ ===== #}
{# ===== 3 Cloud + DictIA LOCAL block + Pro+ ===== #}
<section class="bg-brand-bg py-20" aria-labelledby="forfaits-title">
<div class="max-w-[1200px] mx-auto px-6">
<h2 id="forfaits-title" class="sr-only">Quatre forfaits DictIA + Pro+ sur soumission</h2>
<h2 id="forfaits-title" class="sr-only">Trois forfaits Cloud DictIA + DictIA LOCAL + Pro+ sur soumission</h2>
{% include 'marketing/_partials/_pricing_tiers.html' %}
</div>
</section>

View File

@@ -360,28 +360,32 @@ def test_pricing_recommended_tier_is_cloud_pro():
def test_pricing_cta_labels_v7():
"""CTAs reflect v7.0 forfait choice (Démarrer en Cloud / Choisir Essentiel / Commander Pro / Configurer DictIA Local)."""
"""CTAs reflect v7.0 forfait choice — 3 Cloud go to /checkout, DictIA LOCAL goes to /contact?plan=dictia-local."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
for slug in ['cloud-basic', 'cloud-essentiel', 'cloud-pro', 'dictia-local']:
# 3 Cloud forfaits use /checkout/<slug>
for slug in ['cloud-basic', 'cloud-essentiel', 'cloud-pro']:
assert f'href="/checkout/{slug}"' in body, f"Missing checkout link for {slug}"
# CTA labels match the macro callers in _pricing_tiers.html
assert 'Démarrer en Cloud' in body or 'D&eacute;marrer en Cloud' in body
assert 'Choisir Essentiel' in body
assert 'Commander Pro' in body
assert 'Configurer DictIA Local' in body
# DictIA LOCAL now has a dedicated block with a contact CTA (no /checkout slug)
assert 'Voir les serveurs disponibles' in body, "Missing DictIA LOCAL block CTA label"
assert '/contact?plan=dictia-local' in body, "Missing DictIA LOCAL contact CTA href"
def test_pricing_features_use_safe_filter_no_double_escape():
"""Pricing card features piped through | safe — '&nbsp;' must render single-escaped, not double."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
# Capacity chips use NBSP
# Capacity chips use NBSP (3 Cloud forfaits)
assert '~165&nbsp;h audio/mois' in body, "Missing Cloud BASIC capacity chip"
assert '100&nbsp;Go' in body, "Missing Cloud BASIC storage chip"
assert '~660&nbsp;h audio/mois' in body, "Missing Cloud PRO capacity chip"
assert '500&nbsp;Go' in body, "Missing Cloud PRO storage chip"
assert '2&nbsp;To SSD' in body, "Missing DictIA LOCAL storage chip"
# DictIA LOCAL dedicated block — server visual mockup uses NBSP for GPU spec
assert 'RTX 5070&nbsp;Ti 16&nbsp;Go' in body, "Missing DictIA LOCAL GPU spec line in dedicated block"
# WhisperX precision claim w/ NBSP
assert 'WhisperX Large-v3' in body, "Missing WhisperX Large-v3 mention"
# Loi 25 with NBSP
@@ -462,8 +466,9 @@ def test_pricing_cta_url_no_double_slash():
"""pricing_card uses cta_url.rstrip('/') so href never has '//' (regression guard)."""
client = app.test_client()
body = client.get('/').data.decode('utf-8')
# All 4 CTAs use the default cta_url='/checkout' (no trailing slash) — so /checkout/<slug>
for slug in ['cloud-basic', 'cloud-essentiel', 'cloud-pro', 'dictia-local']:
# The 3 Cloud forfaits use the default cta_url='/checkout' (no trailing slash) — so /checkout/<slug>
# DictIA LOCAL is presented in a dedicated block with /contact?plan=dictia-local (not via pricing_card macro)
for slug in ['cloud-basic', 'cloud-essentiel', 'cloud-pro']:
assert f'href="/checkout/{slug}"' in body, f"Missing single-slash href for {slug}"
assert f'href="/checkout//{slug}"' not in body, f"Double-slash regression for {slug}"

View File

@@ -34,7 +34,7 @@ def test_tarifs_has_h1_with_anchor():
def test_tarifs_renders_4_pricing_cards_v7():
"""Tarifs page renders the v7.0 4 forfaits + Pro+ chip."""
"""Tarifs page renders the v7.0 3 Cloud forfaits + DictIA LOCAL dedicated block + Pro+ chip."""
client = app.test_client()
body = client.get('/tarifs').data.decode('utf-8')
for tier in ['Cloud BASIC', 'Cloud ESSENTIEL', 'Cloud PRO', 'DictIA LOCAL']:
@@ -45,11 +45,15 @@ def test_tarifs_renders_4_pricing_cards_v7():
assert '549&nbsp;$' in body
assert '485&nbsp;$' in body # Cloud Pro onboarding
assert '5&nbsp;998&nbsp;$' in body # DictIA Local An 1
# Checkout slugs
# 3 Cloud forfaits use checkout slugs
assert 'href="/checkout/cloud-basic"' in body
assert 'href="/checkout/cloud-essentiel"' in body
assert 'href="/checkout/cloud-pro"' in body
assert 'href="/checkout/dictia-local"' in body
# DictIA LOCAL has its own dedicated block with a contact CTA (no /checkout slug)
assert '/contact?plan=dictia-local' in body, "Missing DictIA LOCAL block contact CTA"
assert 'Vous en êtes' in body or 'Vous en &ecirc;tes' in body, \
"Missing DictIA LOCAL block headline 'Vous en êtes propriétaire'"
assert 'Serveur DictIA' in body, "Missing DictIA LOCAL block server visual mockup label"
# Pro+ chip with /contact link
assert 'Pro+' in body
assert '/contact?pro-plus=1' in body