feat(brand): logo officiel DictIA + palette blue/cyan/fuchsia (matche le logo)

Logos officiels installés :
- static/images/dictia-logo.png (28 KB optimisé 256×256)
- static/images/dictia-logo-128.png (10 KB retina)
- static/images/dictia-logo-fullres.png (originaux conservés OG/social)
- static/images/dictia-logo.svg + dictia-logo-nom.svg (cleaned C2PA metadata)
- Header marketing/base.html : <img> 40×40 + wordmark "DictIA" + tagline "Transcription"
- Footer marketing/_footer.html : <img> 36×36 + wordmark
- Favicon mis à jour vers logo PNG

Note : SVG sources sont des PNG base64 wrappés (pas de vrais paths) — PNG utilisé
en production (8× plus léger), SVG conservé pour fallback.

Palette canonique alignée sur le logo :
- brand-b1 : #7c3aed (mauve) → #2563eb (blue-600 vibrant — primary)
- brand-b2 : #a855f7 (mauve clair) → #06b6d4 (cyan-500 — aqua mid)
- brand-b3 : #06b6d4 (aqua) → #c026d3 (fuchsia-600 — magenta accent)
- Gradient signature : linear-gradient(118deg, #2563eb, #06b6d4 52%, #c026d3)
- Box shadow CTA : rgba(37,99,235,0.28/0.42)
- 72 remplacements hex/rgba dans 5 templates marketing/legal + email service

Tests : 81 passed / 3 failed (3 échecs pré-existants /blog + trust-bar phrasing,
non liés à ce changement). 0 régression.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-28 15:54:17 -04:00
parent 34d40162b3
commit 575db5e342
20 changed files with 166 additions and 140 deletions

View File

@@ -173,9 +173,10 @@ def _get_email_template(content_html: str, content_text: str, subject: str) -> t
""" """
Wrap content in the DictIA branded email template. Wrap content in the DictIA branded email template.
Header uses the DictIA brand gradient (118deg, #0062ff → #00bdd8 → #00c896) Header uses the DictIA brand gradient (118deg, #2563eb → #06b6d4 → #c026d3)
with a #0062ff fallback for clients that don't render gradients in inline with a #2563eb fallback for clients that don't render gradients in inline
styles. Footer mentions ``info@dictia.ca`` (canonical contact) and the styles. The gradient matches the official DictIA logo (blue → cyan → fuchsia).
Footer mentions ``info@dictia.ca`` (canonical contact) and the
Loi 25 tagline. Loi 25 tagline.
Returns (html_body, text_body) Returns (html_body, text_body)
@@ -188,12 +189,12 @@ def _get_email_template(content_html: str, content_text: str, subject: str) -> t
# Outside of request context, use a placeholder # Outside of request context, use a placeholder
logo_url = "" logo_url = ""
# Header: solid #0062ff fallback + linear-gradient overlay (best-effort # Header: solid #2563eb fallback + linear-gradient overlay (best-effort
# for the email clients that support inline-style gradients — Apple Mail, # for the email clients that support inline-style gradients — Apple Mail,
# iOS Mail, Gmail web). # iOS Mail, Gmail web). Matches official DictIA logo (blue → cyan → fuchsia).
header_bg = ( header_bg = (
"background-color: #0062ff; " "background-color: #2563eb; "
"background-image: linear-gradient(118deg, #0062ff 0%, #00bdd8 52%, #00c896 100%);" "background-image: linear-gradient(118deg, #2563eb 0%, #06b6d4 52%, #c026d3 100%);"
) )
html_body = f""" html_body = f"""
@@ -250,7 +251,7 @@ def _get_email_template(content_html: str, content_text: str, subject: str) -> t
<tr> <tr>
<td style="text-align: center;"> <td style="text-align: center;">
<p style="color: #4b5563; font-size: 12px; margin: 0 0 8px 0;"> <p style="color: #4b5563; font-size: 12px; margin: 0 0 8px 0;">
Ce courriel vous est envoyé par DictIA. Pour toute question, contactez <a href="mailto:info@dictia.ca" style="color: #0062ff; text-decoration: none;">info@dictia.ca</a>. Ce courriel vous est envoyé par DictIA. Pour toute question, contactez <a href="mailto:info@dictia.ca" style="color: #2563eb; text-decoration: none;">info@dictia.ca</a>.
</p> </p>
<p style="color: #6b7280; font-size: 11px; margin: 0;"> <p style="color: #6b7280; font-size: 11px; margin: 0;">
&copy; {datetime.utcnow().year} DictIA &mdash; Transcription IA conforme Loi&nbsp;25 &copy; {datetime.utcnow().year} DictIA &mdash; Transcription IA conforme Loi&nbsp;25
@@ -330,11 +331,11 @@ def send_verification_email(user) -> bool:
</p> </p>
<div style="text-align: center; margin: 32px 0;"> <div style="text-align: center; margin: 32px 0;">
<a href="{verify_url}" style="display: inline-block; background-color: #0062ff; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Vérifier mon courriel</a> <a href="{verify_url}" style="display: inline-block; background-color: #2563eb; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Vérifier mon courriel</a>
</div> </div>
<p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p> <p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p>
<p style="word-break: break-all; color: #0062ff; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{verify_url}</p> <p style="word-break: break-all; color: #2563eb; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{verify_url}</p>
<div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;"> <div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;">
<p style="color: #4b5563; font-size: 13px; margin: 0;"> <p style="color: #4b5563; font-size: 13px; margin: 0;">
@@ -402,11 +403,11 @@ def send_password_reset_email(user) -> bool:
</p> </p>
<div style="text-align: center; margin: 32px 0;"> <div style="text-align: center; margin: 32px 0;">
<a href="{reset_url}" style="display: inline-block; background-color: #0062ff; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Réinitialiser mon mot de passe</a> <a href="{reset_url}" style="display: inline-block; background-color: #2563eb; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Réinitialiser mon mot de passe</a>
</div> </div>
<p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p> <p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p>
<p style="word-break: break-all; color: #0062ff; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{reset_url}</p> <p style="word-break: break-all; color: #2563eb; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{reset_url}</p>
<div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;"> <div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;">
<p style="color: #4b5563; font-size: 13px; margin: 0;"> <p style="color: #4b5563; font-size: 13px; margin: 0;">
@@ -471,11 +472,11 @@ def send_magic_link_email(user, magic_url: str) -> bool:
</p> </p>
<div style="text-align: center; margin: 32px 0;"> <div style="text-align: center; margin: 32px 0;">
<a href="{magic_url}" style="display: inline-block; background-color: #0062ff; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Se connecter à DictIA</a> <a href="{magic_url}" style="display: inline-block; background-color: #2563eb; color: #ffffff; text-decoration: none; padding: 14px 32px; border-radius: 8px; font-weight: 600; font-size: 16px;">Se connecter à DictIA</a>
</div> </div>
<p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p> <p style="color: #4b5563; font-size: 14px; margin: 24px 0 8px 0;">Ou copiez-collez ce lien dans votre navigateur :</p>
<p style="word-break: break-all; color: #0062ff; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{magic_url}</p> <p style="word-break: break-all; color: #2563eb; font-size: 14px; margin: 0; padding: 12px; background-color: #f7f9fc; border-radius: 6px;">{magic_url}</p>
<div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;"> <div style="margin-top: 32px; padding-top: 24px; border-top: 1px solid #e6ebf2;">
<p style="color: #4b5563; font-size: 13px; margin: 0;"> <p style="color: #4b5563; font-size: 13px; margin: 0;">

View File

@@ -1703,31 +1703,31 @@
} }
} }
.border-brand-b1 { .border-brand-b1 {
border-color: #7c3aed; border-color: #2563eb;
} }
.border-brand-b1\/15 { .border-brand-b1\/15 {
border-color: color-mix(in oklab, #7c3aed 15%, transparent); border-color: color-mix(in oklab, #2563eb 15%, transparent);
} }
.border-brand-b1\/20 { .border-brand-b1\/20 {
border-color: color-mix(in oklab, #7c3aed 20%, transparent); border-color: color-mix(in oklab, #2563eb 20%, transparent);
} }
.border-brand-b1\/25 { .border-brand-b1\/25 {
border-color: color-mix(in oklab, #7c3aed 25%, transparent); border-color: color-mix(in oklab, #2563eb 25%, transparent);
} }
.border-brand-b1\/30 { .border-brand-b1\/30 {
border-color: color-mix(in oklab, #7c3aed 30%, transparent); border-color: color-mix(in oklab, #2563eb 30%, transparent);
} }
.border-brand-b1\/35 { .border-brand-b1\/35 {
border-color: color-mix(in oklab, #7c3aed 35%, transparent); border-color: color-mix(in oklab, #2563eb 35%, transparent);
} }
.border-brand-b2\/40 { .border-brand-b2\/40 {
border-color: color-mix(in oklab, #a855f7 40%, transparent); border-color: color-mix(in oklab, #06b6d4 40%, transparent);
} }
.border-brand-b3\/15 { .border-brand-b3\/15 {
border-color: color-mix(in oklab, #06b6d4 15%, transparent); border-color: color-mix(in oklab, #c026d3 15%, transparent);
} }
.border-brand-b3\/60 { .border-brand-b3\/60 {
border-color: color-mix(in oklab, #06b6d4 60%, transparent); border-color: color-mix(in oklab, #c026d3 60%, transparent);
} }
.border-brand-border { .border-brand-border {
border-color: #e6ebf2; border-color: #e6ebf2;
@@ -2030,28 +2030,28 @@
background-color: var(--color-blue-600); background-color: var(--color-blue-600);
} }
.bg-brand-b1 { .bg-brand-b1 {
background-color: #7c3aed; background-color: #2563eb;
} }
.bg-brand-b1\/5 { .bg-brand-b1\/5 {
background-color: color-mix(in oklab, #7c3aed 5%, transparent); background-color: color-mix(in oklab, #2563eb 5%, transparent);
} }
.bg-brand-b1\/10 { .bg-brand-b1\/10 {
background-color: color-mix(in oklab, #7c3aed 10%, transparent); background-color: color-mix(in oklab, #2563eb 10%, transparent);
} }
.bg-brand-b1\/15 { .bg-brand-b1\/15 {
background-color: color-mix(in oklab, #7c3aed 15%, transparent); background-color: color-mix(in oklab, #2563eb 15%, transparent);
} }
.bg-brand-b1\/\[0\.06\] { .bg-brand-b1\/\[0\.06\] {
background-color: color-mix(in oklab, #7c3aed 6%, transparent); background-color: color-mix(in oklab, #2563eb 6%, transparent);
} }
.bg-brand-b3 { .bg-brand-b3 {
background-color: #06b6d4; background-color: #c026d3;
} }
.bg-brand-b3\/10 { .bg-brand-b3\/10 {
background-color: color-mix(in oklab, #06b6d4 10%, transparent); background-color: color-mix(in oklab, #c026d3 10%, transparent);
} }
.bg-brand-b3\/60 { .bg-brand-b3\/60 {
background-color: color-mix(in oklab, #06b6d4 60%, transparent); background-color: color-mix(in oklab, #c026d3 60%, transparent);
} }
.bg-brand-bg { .bg-brand-bg {
background-color: #f7f9fc; background-color: #f7f9fc;
@@ -2370,15 +2370,15 @@
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.from-brand-b1\/15 { .from-brand-b1\/15 {
--tw-gradient-from: color-mix(in oklab, #7c3aed 15%, transparent); --tw-gradient-from: color-mix(in oklab, #2563eb 15%, transparent);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.from-brand-b1\/\[0\.06\] { .from-brand-b1\/\[0\.06\] {
--tw-gradient-from: color-mix(in oklab, #7c3aed 6%, transparent); --tw-gradient-from: color-mix(in oklab, #2563eb 6%, transparent);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.from-brand-b3 { .from-brand-b3 {
--tw-gradient-from: #06b6d4; --tw-gradient-from: #c026d3;
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.from-orange-500 { .from-orange-500 {
@@ -2421,15 +2421,15 @@
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.to-brand-b1 { .to-brand-b1 {
--tw-gradient-to: #7c3aed; --tw-gradient-to: #2563eb;
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.to-brand-b3\/10 { .to-brand-b3\/10 {
--tw-gradient-to: color-mix(in oklab, #06b6d4 10%, transparent); --tw-gradient-to: color-mix(in oklab, #c026d3 10%, transparent);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.to-brand-b3\/\[0\.04\] { .to-brand-b3\/\[0\.04\] {
--tw-gradient-to: color-mix(in oklab, #06b6d4 4%, transparent); --tw-gradient-to: color-mix(in oklab, #c026d3 4%, transparent);
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
.to-purple-500 { .to-purple-500 {
@@ -2998,31 +2998,31 @@
color: var(--color-blue-900); color: var(--color-blue-900);
} }
.text-brand-b1 { .text-brand-b1 {
color: #7c3aed; color: #2563eb;
} }
.text-brand-b1\/45 { .text-brand-b1\/45 {
color: color-mix(in oklab, #7c3aed 45%, transparent); color: color-mix(in oklab, #2563eb 45%, transparent);
} }
.text-brand-b1\/55 { .text-brand-b1\/55 {
color: color-mix(in oklab, #7c3aed 55%, transparent); color: color-mix(in oklab, #2563eb 55%, transparent);
} }
.text-brand-b1\/60 { .text-brand-b1\/60 {
color: color-mix(in oklab, #7c3aed 60%, transparent); color: color-mix(in oklab, #2563eb 60%, transparent);
} }
.text-brand-b1\/65 { .text-brand-b1\/65 {
color: color-mix(in oklab, #7c3aed 65%, transparent); color: color-mix(in oklab, #2563eb 65%, transparent);
} }
.text-brand-b1\/70 { .text-brand-b1\/70 {
color: color-mix(in oklab, #7c3aed 70%, transparent); color: color-mix(in oklab, #2563eb 70%, transparent);
} }
.text-brand-b1\/80 { .text-brand-b1\/80 {
color: color-mix(in oklab, #7c3aed 80%, transparent); color: color-mix(in oklab, #2563eb 80%, transparent);
} }
.text-brand-b2 { .text-brand-b2 {
color: #a855f7; color: #06b6d4;
} }
.text-brand-b3 { .text-brand-b3 {
color: #06b6d4; color: #c026d3;
} }
.text-brand-navy { .text-brand-navy {
color: #060d1a; color: #060d1a;
@@ -3324,7 +3324,7 @@
} }
} }
.accent-brand-b1 { .accent-brand-b1 {
accent-color: #7c3aed; accent-color: #2563eb;
} }
.opacity-0 { .opacity-0 {
opacity: 0%; opacity: 0%;
@@ -3378,8 +3378,8 @@
--tw-shadow: 0 0 6px var(--tw-shadow-color, rgba(239,68,68,0.6)); --tw-shadow: 0 0 6px var(--tw-shadow-color, rgba(239,68,68,0.6));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
.shadow-\[0_0_28px_rgba\(124\,58\,237\,0\.35\)\] { .shadow-\[0_0_28px_rgba\(37\,99\,235\,0\.35\)\] {
--tw-shadow: 0 0 28px var(--tw-shadow-color, rgba(124,58,237,0.35)); --tw-shadow: 0 0 28px var(--tw-shadow-color, rgba(37,99,235,0.35));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
.shadow-\[0_8px_30px_-6px_rgba\(239\,68\,68\,0\.55\)\] { .shadow-\[0_8px_30px_-6px_rgba\(239\,68\,68\,0\.55\)\] {
@@ -3387,7 +3387,7 @@
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
.shadow-cta { .shadow-cta {
--tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(124, 58, 237, 0.28)); --tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(37, 99, 235, 0.28));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
.shadow-lg { .shadow-lg {
@@ -3579,7 +3579,7 @@
.group-hover\:text-brand-b1 { .group-hover\:text-brand-b1 {
&:is(:where(.group):hover *) { &:is(:where(.group):hover *) {
@media (hover: hover) { @media (hover: hover) {
color: #7c3aed; color: #2563eb;
} }
} }
} }
@@ -3789,14 +3789,14 @@
.hover\:border-brand-b1 { .hover\:border-brand-b1 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
border-color: #7c3aed; border-color: #2563eb;
} }
} }
} }
.hover\:border-brand-b1\/30 { .hover\:border-brand-b1\/30 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
border-color: color-mix(in oklab, #7c3aed 30%, transparent); border-color: color-mix(in oklab, #2563eb 30%, transparent);
} }
} }
} }
@@ -4150,7 +4150,7 @@
.hover\:from-brand-b1 { .hover\:from-brand-b1 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
--tw-gradient-from: #7c3aed; --tw-gradient-from: #2563eb;
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
} }
@@ -4190,7 +4190,7 @@
.hover\:to-brand-b3 { .hover\:to-brand-b3 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
--tw-gradient-to: #06b6d4; --tw-gradient-to: #c026d3;
--tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
} }
} }
@@ -4306,7 +4306,7 @@
.hover\:text-brand-b1 { .hover\:text-brand-b1 {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
color: #7c3aed; color: #2563eb;
} }
} }
} }
@@ -4426,7 +4426,7 @@
.hover\:shadow-cta { .hover\:shadow-cta {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
--tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(124, 58, 237, 0.28)); --tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(37, 99, 235, 0.28));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
} }
@@ -4434,7 +4434,7 @@
.hover\:shadow-cta-hover { .hover\:shadow-cta-hover {
&:hover { &:hover {
@media (hover: hover) { @media (hover: hover) {
--tw-shadow: 0 8px 32px var(--tw-shadow-color, rgba(124, 58, 237, 0.42)); --tw-shadow: 0 8px 32px var(--tw-shadow-color, rgba(37, 99, 235, 0.42));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
} }
} }
@@ -4613,7 +4613,7 @@
} }
.focus-visible\:outline-brand-b1 { .focus-visible\:outline-brand-b1 {
&:focus-visible { &:focus-visible {
outline-color: #7c3aed; outline-color: #2563eb;
} }
} }
.focus-visible\:outline-red-700 { .focus-visible\:outline-red-700 {
@@ -5890,13 +5890,13 @@
} }
@layer utilities { @layer utilities {
.grad-text { .grad-text {
background-image: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background-image: linear-gradient(118deg, #2563eb, #06b6d4 52%, #c026d3);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
color: transparent; color: transparent;
} }
.grad-bg { .grad-bg {
background-image: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background-image: linear-gradient(118deg, #2563eb, #06b6d4 52%, #c026d3);
color: var(--color-white); color: var(--color-white);
} }
.eyebrow { .eyebrow {

View File

@@ -6,9 +6,9 @@ module.exports = {
extend: { extend: {
colors: { colors: {
brand: { brand: {
b1: '#7c3aed', b1: '#2563eb',
b2: '#a855f7', b2: '#06b6d4',
b3: '#06b6d4', b3: '#c026d3',
navy: '#060d1a', navy: '#060d1a',
navy2: '#0b1525', navy2: '#0b1525',
navy3: '#0f1e35', navy3: '#0f1e35',
@@ -21,11 +21,11 @@ module.exports = {
mono: ['JetBrains Mono Variable', 'JetBrains Mono', 'monospace'], mono: ['JetBrains Mono Variable', 'JetBrains Mono', 'monospace'],
}, },
backgroundImage: { backgroundImage: {
'brand-grad': 'linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4)', 'brand-grad': 'linear-gradient(118deg, #2563eb, #06b6d4 52%, #c026d3)',
}, },
boxShadow: { boxShadow: {
'cta': '0 4px 20px rgba(124, 58, 237, 0.28)', 'cta': '0 4px 20px rgba(37, 99, 235, 0.28)',
'cta-hover': '0 8px 32px rgba(124, 58, 237, 0.42)', 'cta-hover': '0 8px 32px rgba(37, 99, 235, 0.42)',
}, },
borderRadius: { borderRadius: {
DEFAULT: '0.75rem', DEFAULT: '0.75rem',
@@ -44,8 +44,8 @@ module.exports = {
'50%': { transform: 'translateY(-8px)' }, '50%': { transform: 'translateY(-8px)' },
}, },
'tc-pulse-glow': { 'tc-pulse-glow': {
'0%, 100%': { boxShadow: '0 4px 20px rgba(124, 58, 237, 0.28)' }, '0%, 100%': { boxShadow: '0 4px 20px rgba(37, 99, 235, 0.28)' },
'50%': { boxShadow: '0 8px 32px rgba(124, 58, 237, 0.42)' }, '50%': { boxShadow: '0 8px 32px rgba(37, 99, 235, 0.42)' },
}, },
'plus-breathe': { 'plus-breathe': {
'0%, 100%': { transform: 'scale(1)' }, '0%, 100%': { transform: 'scale(1)' },

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -27,7 +27,7 @@
height: 4px; height: 4px;
margin-top: 0.5rem; margin-top: 0.5rem;
border-radius: 4px; border-radius: 4px;
background: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background: linear-gradient(118deg, #2563eb, #06b6d4 52%, #06b6d4);
} }
.legal-content h3 { .legal-content h3 {
font-size: 1.25rem; /* 20px */ font-size: 1.25rem; /* 20px */
@@ -60,16 +60,16 @@
.legal-content ol { list-style-type: decimal; list-style-position: outside; } .legal-content ol { list-style-type: decimal; list-style-position: outside; }
.legal-content li { margin-bottom: 0.35rem; } .legal-content li { margin-bottom: 0.35rem; }
.legal-content a { .legal-content a {
background: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background: linear-gradient(118deg, #2563eb, #06b6d4 52%, #06b6d4);
-webkit-background-clip: text; -webkit-background-clip: text;
background-clip: text; background-clip: text;
color: transparent; color: transparent;
font-weight: 600; font-weight: 600;
text-decoration: underline; text-decoration: underline;
text-decoration-color: #7c3aed; text-decoration-color: #2563eb;
} }
.legal-content a:focus-visible { .legal-content a:focus-visible {
outline: 2px solid #7c3aed; outline: 2px solid #2563eb;
outline-offset: 2px; outline-offset: 2px;
border-radius: 2px; border-radius: 2px;
} }
@@ -95,7 +95,7 @@
background-color: #fafbfd; background-color: #fafbfd;
} }
.legal-content blockquote { .legal-content blockquote {
border-left: 4px solid #7c3aed; border-left: 4px solid #2563eb;
background-color: rgba(247, 249, 252, 0.6); background-color: rgba(247, 249, 252, 0.6);
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
margin: 1.25rem 0; margin: 1.25rem 0;
@@ -156,12 +156,12 @@
transition: color 150ms ease, border-color 150ms ease, background-color 150ms ease; transition: color 150ms ease, border-color 150ms ease, background-color 150ms ease;
} }
.legal-toc a:hover { .legal-toc a:hover {
background-color: rgba(124, 58, 237, 0.05); background-color: rgba(37,99,235, 0.05);
} }
.legal-toc a.is-active { .legal-toc a.is-active {
border-left-color: #7c3aed; border-left-color: #2563eb;
color: #7c3aed !important; color: #2563eb !important;
background-color: rgba(124, 58, 237, 0.06); background-color: rgba(37,99,235, 0.06);
} }
.legal-breadcrumb { .legal-breadcrumb {
position: sticky; position: sticky;

View File

@@ -13,16 +13,16 @@
transform: translateY(-2px); transform: translateY(-2px);
} }
.legal-card:focus-visible { .legal-card:focus-visible {
outline: 2px solid #7c3aed; outline: 2px solid #2563eb;
outline-offset: 3px; outline-offset: 3px;
} }
/* Icône circulaire avec dégradé de marque, contraste suffisant. */ /* Icône circulaire avec dégradé de marque, contraste suffisant. */
.legal-card-icon { .legal-card-icon {
background: linear-gradient(135deg, rgba(124,58,237,0.10), rgba(6,182,212,0.10)); background: linear-gradient(135deg, rgba(37,99,235,0.10), rgba(6,182,212,0.10));
color: #7c3aed; color: #2563eb;
} }
.legal-card.is-external .legal-card-icon { .legal-card.is-external .legal-card-icon {
background: linear-gradient(135deg, rgba(168,85,247,0.12), rgba(6,182,212,0.12)); background: linear-gradient(135deg, rgba(6,182,212,0.12), rgba(6,182,212,0.12));
} }
/* Print : pas de bouton CTA, pas d'animations. */ /* Print : pas de bouton CTA, pas d'animations. */
@media print { @media print {

View File

@@ -5,7 +5,15 @@
{# Column 1 — Brand + contact #} {# Column 1 — Brand + contact #}
<div> <div>
<a href="/" class="font-black text-xl grad-text" aria-label="DictIA — page d'accueil">DictIA</a> <a href="/" class="inline-flex items-center gap-3" aria-label="DictIA — page d'accueil">
<img src="{{ url_for('static', filename='images/dictia-logo.png') }}"
alt=""
width="36"
height="36"
class="w-9 h-9"
aria-hidden="true">
<span class="font-black text-xl grad-text">DictIA</span>
</a>
<p class="text-sm text-white/70 mt-3">Transcription IA conforme Loi&nbsp;25, conçue au Québec.</p> <p class="text-sm text-white/70 mt-3">Transcription IA conforme Loi&nbsp;25, conçue au Québec.</p>
<address class="not-italic text-xs text-white/70 mt-4 leading-relaxed"> <address class="not-italic text-xs text-white/70 mt-4 leading-relaxed">
77&nbsp;ch. de la Seigneurie<br> 77&nbsp;ch. de la Seigneurie<br>

View File

@@ -31,7 +31,8 @@
<link rel="stylesheet" href="/static/css/marketing.css"> <link rel="stylesheet" href="/static/css/marketing.css">
<!-- Favicon --> <!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/static/images/favicon.svg"> <link rel="icon" type="image/png" href="/static/images/dictia-logo.png">
<link rel="alternate icon" type="image/svg+xml" href="/static/images/favicon.svg">
{% block schema %}{% endblock %} {% block schema %}{% endblock %}
{% block head_extra %}{% endblock %} {% block head_extra %}{% endblock %}
@@ -40,9 +41,17 @@
<!-- Glassmorphism header (FlexiHub style: 62px, navy/.97 + backdrop-blur-xl + 0.045 border) --> <!-- Glassmorphism header (FlexiHub style: 62px, navy/.97 + backdrop-blur-xl + 0.045 border) -->
<header class="fixed top-0 inset-x-0 z-50 h-[62px] bg-brand-navy/[0.97] backdrop-blur-xl border-b border-white/[0.045]"> <header class="fixed top-0 inset-x-0 z-50 h-[62px] bg-brand-navy/[0.97] backdrop-blur-xl border-b border-white/[0.045]">
<div class="max-w-[1200px] mx-auto h-full px-6 flex items-center justify-between"> <div class="max-w-[1200px] mx-auto h-full px-6 flex items-center justify-between">
<a href="/" class="flex flex-col leading-none" aria-label="DictIA — Transcription, accueil"> <a href="/" class="flex items-center gap-3 leading-none" aria-label="DictIA — Transcription, accueil">
<span class="font-black text-xl tracking-tight grad-text">DictIA</span> <img src="{{ url_for('static', filename='images/dictia-logo.png') }}"
<span class="text-[10px] uppercase tracking-[0.2em] text-white font-medium mt-0.5">Transcription</span> alt=""
width="40"
height="40"
class="w-10 h-10 flex-shrink-0"
aria-hidden="true">
<span class="flex flex-col">
<span class="font-black text-xl tracking-tight grad-text">DictIA</span>
<span class="text-[10px] uppercase tracking-[0.2em] text-white font-medium mt-0.5">Transcription</span>
</span>
</a> </a>
<nav class="hidden md:flex gap-8 text-sm font-medium text-white/80" aria-label="Navigation principale"> <nav class="hidden md:flex gap-8 text-sm font-medium text-white/80" aria-label="Navigation principale">

View File

@@ -15,7 +15,7 @@
bottom: -10px; bottom: -10px;
width: 0; width: 0;
height: 3px; height: 3px;
background: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background: linear-gradient(118deg, #2563eb, #06b6d4 52%, #06b6d4);
transform: translateX(-50%); transform: translateX(-50%);
transition: width 600ms ease-out; transition: width 600ms ease-out;
} }
@@ -27,16 +27,16 @@
/* Hover lift cards */ /* Hover lift cards */
.ani-lift { transition: transform 200ms ease-out, box-shadow 200ms ease-out; } .ani-lift { transition: transform 200ms ease-out, box-shadow 200ms ease-out; }
.ani-lift:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(124, 58, 237, 0.18); } .ani-lift:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(37,99,235, 0.18); }
/* Sticky sub-nav active link */ /* Sticky sub-nav active link */
.subnav-link[aria-current="true"] { color: #7c3aed; } .subnav-link[aria-current="true"] { color: #2563eb; }
.subnav-link[aria-current="true"]::after { .subnav-link[aria-current="true"]::after {
content: ''; content: '';
display: block; display: block;
height: 2px; height: 2px;
margin-top: 4px; margin-top: 4px;
background: linear-gradient(118deg, #7c3aed, #a855f7 52%, #06b6d4); background: linear-gradient(118deg, #2563eb, #06b6d4 52%, #06b6d4);
} }
/* Cosmic float orbs (n'utilise pas tc-float-y pour éviter rebuild) */ /* Cosmic float orbs (n'utilise pas tc-float-y pour éviter rebuild) */
@@ -46,8 +46,8 @@
/* DictIA Cloud pulse glow */ /* DictIA Cloud pulse glow */
@keyframes card-pulse-glow { @keyframes card-pulse-glow {
0%, 100% { box-shadow: 0 4px 20px rgba(124, 58, 237, 0.28); } 0%, 100% { box-shadow: 0 4px 20px rgba(37,99,235, 0.28); }
50% { box-shadow: 0 12px 40px rgba(124, 58, 237, 0.5); } 50% { box-shadow: 0 12px 40px rgba(37,99,235, 0.5); }
} }
.card-pulse-glow { animation: card-pulse-glow 3s ease-in-out infinite; } .card-pulse-glow { animation: card-pulse-glow 3s ease-in-out infinite; }
@@ -76,13 +76,13 @@
{# Cosmic orbs background — float animation subtile #} {# Cosmic orbs background — float animation subtile #}
<div class="absolute inset-0 pointer-events-none" aria-hidden="true"> <div class="absolute inset-0 pointer-events-none" aria-hidden="true">
<div class="orb-float-a absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full" <div class="orb-float-a absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full"
style="background: radial-gradient(circle, rgba(124,58,237,0.16) 0%, transparent 60%); filter: blur(40px);"></div> style="background: radial-gradient(circle, rgba(37,99,235,0.16) 0%, transparent 60%); filter: blur(40px);"></div>
<div class="orb-float-b absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full" <div class="orb-float-b absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full"
style="background: radial-gradient(circle, rgba(6,182,212,0.07) 0%, transparent 60%); filter: blur(40px);"></div> style="background: radial-gradient(circle, rgba(6,182,212,0.07) 0%, transparent 60%); filter: blur(40px);"></div>
<div class="absolute inset-0" <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> 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>
<div class="absolute top-1/3 left-0 right-0 h-px" <div class="absolute top-1/3 left-0 right-0 h-px"
style="background: linear-gradient(90deg, transparent, rgba(124,58,237,0.3), rgba(6,182,212,0.2), transparent);"></div> style="background: linear-gradient(90deg, transparent, rgba(37,99,235,0.3), rgba(6,182,212,0.2), transparent);"></div>
</div> </div>
<div class="relative max-w-[1200px] mx-auto px-6 text-center"> <div class="relative max-w-[1200px] mx-auto px-6 text-center">

View File

@@ -19,7 +19,7 @@
} }
.hero-flow-card.is-active { .hero-flow-card.is-active {
transform: scale(1.05); transform: scale(1.05);
box-shadow: 0 0 22px rgba(6, 182, 212, 0.45), 0 0 44px rgba(124, 58, 237, 0.18); box-shadow: 0 0 22px rgba(6, 182, 212, 0.45), 0 0 44px rgba(37,99,235, 0.18);
} }
.hero-flow-card.is-inactive { opacity: 0.45; } .hero-flow-card.is-inactive { opacity: 0.45; }
/* Animated arrow draw between cards */ /* Animated arrow draw between cards */
@@ -63,7 +63,7 @@
border-radius: 9999px; border-radius: 9999px;
pointer-events: none; pointer-events: none;
z-index: 9999; z-index: 9999;
background: radial-gradient(circle, rgba(6,182,212,0.18) 0%, rgba(124,58,237,0.10) 50%, transparent 70%); background: radial-gradient(circle, rgba(6,182,212,0.18) 0%, rgba(37,99,235,0.10) 50%, transparent 70%);
animation: hero-shockwave 700ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards; animation: hero-shockwave 700ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
} }
/* ── Word-staggered title reveal ── */ /* ── Word-staggered title reveal ── */
@@ -148,7 +148,7 @@
<div class="absolute inset-0 pointer-events-none" aria-hidden="true"> <div class="absolute inset-0 pointer-events-none" aria-hidden="true">
{# Orb 1 — primary mauve, top-left #} {# Orb 1 — primary mauve, top-left #}
<div class="absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full opacity-100" <div class="absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full opacity-100"
style="background: radial-gradient(circle, rgba(124,58,237,0.16) 0%, transparent 60%); filter: blur(40px);"></div> style="background: radial-gradient(circle, rgba(37,99,235,0.16) 0%, transparent 60%); filter: blur(40px);"></div>
{# Orb 2 — aqua, mid-right #} {# Orb 2 — aqua, mid-right #}
<div class="absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full" <div class="absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full"
style="background: radial-gradient(circle, rgba(6,182,212,0.07) 0%, transparent 60%); filter: blur(40px);"></div> style="background: radial-gradient(circle, rgba(6,182,212,0.07) 0%, transparent 60%); filter: blur(40px);"></div>
@@ -160,7 +160,7 @@
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> 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 mauve to aqua to transparent #} {# Horizontal accent line — gradient mauve to aqua to transparent #}
<div class="absolute top-1/3 left-0 right-0 h-px" <div class="absolute top-1/3 left-0 right-0 h-px"
style="background: linear-gradient(90deg, transparent, rgba(124,58,237,0.3), rgba(6,182,212,0.2), transparent);"></div> style="background: linear-gradient(90deg, transparent, rgba(37,99,235,0.3), rgba(6,182,212,0.2), transparent);"></div>
</div> </div>
{# 3D abstract orb — reacts to mouse via Alpine ox/oy → CSS variables #} {# 3D abstract orb — reacts to mouse via Alpine ox/oy → CSS variables #}
@@ -174,14 +174,14 @@
<div class="absolute inset-0 rounded-full border border-brand-b3/15" style="transform: scale(1.35);"></div> <div class="absolute inset-0 rounded-full border border-brand-b3/15" style="transform: scale(1.35);"></div>
{# Ambient blob #} {# Ambient blob #}
<div class="absolute inset-0 rounded-full" <div class="absolute inset-0 rounded-full"
style="background: radial-gradient(ellipse at 40% 40%, rgba(167,139,250,0.14) 0%, rgba(6,182,212,0.07) 50%, transparent 75%); filter: blur(20px);"></div> style="background: radial-gradient(ellipse at 40% 40%, rgba(96,165,250,0.14) 0%, rgba(6,182,212,0.07) 50%, transparent 75%); filter: blur(20px);"></div>
{# Rotating mesh ring A #} {# Rotating mesh ring A #}
<div class="hero-orb-ring-a absolute inset-0 rounded-full border border-dashed border-white/[0.07]" style="transform: scale(1.15);"></div> <div class="hero-orb-ring-a absolute inset-0 rounded-full border border-dashed border-white/[0.07]" style="transform: scale(1.15);"></div>
{# Rotating mesh ring B #} {# Rotating mesh ring B #}
<div class="hero-orb-ring-b absolute inset-0 rounded-full border border-white/[0.05]" style="transform: scale(0.9);"></div> <div class="hero-orb-ring-b absolute inset-0 rounded-full border border-white/[0.05]" style="transform: scale(0.9);"></div>
{# Inner glow core #} {# Inner glow core #}
<div class="absolute inset-[30%] rounded-full" <div class="absolute inset-[30%] rounded-full"
style="background: radial-gradient(circle, rgba(167,139,250,0.25) 0%, rgba(6,182,212,0.08) 60%, transparent 100%);"></div> style="background: radial-gradient(circle, rgba(96,165,250,0.25) 0%, rgba(6,182,212,0.08) 60%, transparent 100%);"></div>
</div> </div>
</div> </div>
@@ -273,7 +273,7 @@
<span class="relative inline-flex"> <span class="relative inline-flex">
{# Pulse halo behind the primary CTA #} {# Pulse halo behind the primary CTA #}
<span class="hero-cta-halo absolute -inset-1 rounded pointer-events-none" <span class="hero-cta-halo absolute -inset-1 rounded pointer-events-none"
style="background: radial-gradient(ellipse, rgba(167,139,250,0.50) 0%, transparent 70%);" style="background: radial-gradient(ellipse, rgba(96,165,250,0.50) 0%, transparent 70%);"
aria-hidden="true"></span> aria-hidden="true"></span>
<a <a
href="/contact" href="/contact"
@@ -1024,13 +1024,13 @@
</g> </g>
{# Order bar — visible quand p ≈ 1 #} {# Order bar — visible quand p ≈ 1 #}
<g class="wave-bar" :style="`opacity: ${p}`"> <g class="wave-bar" :style="`opacity: ${p}`">
<rect x="{{ cx - bw / 2 }}" y="{{ 25 - order_heights[i] / 2 }}" width="{{ bw }}" height="{{ order_heights[i] }}" rx="{{ bw / 2 }}" fill="rgba(167,139,250,0.6)"/> <rect x="{{ cx - bw / 2 }}" y="{{ 25 - order_heights[i] / 2 }}" width="{{ bw }}" height="{{ order_heights[i] }}" rx="{{ bw / 2 }}" fill="rgba(96,165,250,0.6)"/>
</g> </g>
{% endfor %} {% endfor %}
{# Bouclier holographique (état ordre) #} {# Bouclier holographique (état ordre) #}
<path d="M 50 8 L 68 14 L 68 27 Q 68 38 50 43 Q 32 38 32 27 L 32 14 Z" <path d="M 50 8 L 68 14 L 68 27 Q 68 38 50 43 Q 32 38 32 27 L 32 14 Z"
fill="none" stroke="rgba(167,139,250,0.55)" stroke-width="0.55" stroke-dasharray="2.5 2" fill="none" stroke="rgba(96,165,250,0.55)" stroke-width="0.55" stroke-dasharray="2.5 2"
:style="`opacity: ${orderOp * 0.4}`"/> :style="`opacity: ${orderOp * 0.4}`"/>
</svg> </svg>
@@ -1040,16 +1040,16 @@
<div class="w-10 h-10 md:w-12 md:h-12 rounded flex items-center justify-center backdrop-blur-md border" <div class="w-10 h-10 md:w-12 md:h-12 rounded flex items-center justify-center backdrop-blur-md border"
:style="`background: rgba(${Math.round(255 + (167-255)*p)},${Math.round(60 + (139-60)*p)},${Math.round(60 + (250-60)*p)},0.12); border-color: rgba(${Math.round(255 + (167-255)*p)},${Math.round(80 + (139-80)*p)},${Math.round(80 + (250-80)*p)},0.28);`"> :style="`background: rgba(${Math.round(255 + (167-255)*p)},${Math.round(60 + (139-60)*p)},${Math.round(60 + (250-60)*p)},0.12); border-color: rgba(${Math.round(255 + (167-255)*p)},${Math.round(80 + (139-80)*p)},${Math.round(80 + (250-80)*p)},0.28);`">
<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 md:w-5 md:h-5" <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 md:w-5 md:h-5"
:style="`color: ${p < 0.5 ? '#FF6B6B' : '#a78bfa'}`"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/></svg> :style="`color: ${p < 0.5 ? '#FF6B6B' : '#60a5fa'}`"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="22"/></svg>
</div> </div>
<span class="text-[8px] font-medium" :style="`color: ${p < 0.5 ? 'rgba(255,107,107,0.65)' : 'rgba(167,139,250,0.65)'}`">Audio</span> <span class="text-[8px] font-medium" :style="`color: ${p < 0.5 ? 'rgba(255,107,107,0.65)' : 'rgba(96,165,250,0.65)'}`">Audio</span>
</div> </div>
{# Icône Texte transcrit (droite) #} {# Icône Texte transcrit (droite) #}
<div class="absolute z-20 right-[3%] top-1/2 -translate-y-1/2 flex flex-col items-center gap-1.5" <div class="absolute z-20 right-[3%] top-1/2 -translate-y-1/2 flex flex-col items-center gap-1.5"
:style="`opacity: ${orderOp}`" aria-hidden="true"> :style="`opacity: ${orderOp}`" aria-hidden="true">
<div class="w-10 h-10 md:w-12 md:h-12 rounded flex items-center justify-center backdrop-blur-md border border-brand-b1/30" <div class="w-10 h-10 md:w-12 md:h-12 rounded flex items-center justify-center backdrop-blur-md border border-brand-b1/30"
style="background: linear-gradient(135deg, rgba(167,139,250,0.15), rgba(124,58,237,0.07)); box-shadow: 0 0 18px rgba(167,139,250,0.18);"> style="background: linear-gradient(135deg, rgba(96,165,250,0.15), rgba(37,99,235,0.07)); box-shadow: 0 0 18px rgba(96,165,250,0.18);">
<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 md:w-5 md:h-5 text-brand-b1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/></svg> <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 md:w-5 md:h-5 text-brand-b1"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/></svg>
</div> </div>
<span class="text-[8px] font-medium text-brand-b1/70">Texte</span> <span class="text-[8px] font-medium text-brand-b1/70">Texte</span>
@@ -1076,7 +1076,7 @@
<div class="absolute inset-0 z-10 pointer-events-none" :style="`opacity: ${orderOp}`" aria-hidden="true"> <div class="absolute inset-0 z-10 pointer-events-none" :style="`opacity: ${orderOp}`" aria-hidden="true">
{% for fy in [18, 21, 24, 27, 30] %} {% for fy in [18, 21, 24, 27, 30] %}
<span class="wave-flow absolute w-1 h-1 rounded-full bg-brand-b1" <span class="wave-flow absolute w-1 h-1 rounded-full bg-brand-b1"
style="top: {{ fy }}%; left: 12%; box-shadow: 0 0 5px rgba(167,139,250,0.7); animation-delay: {{ loop.index0 * 0.32 }}s;"></span> style="top: {{ fy }}%; left: 12%; box-shadow: 0 0 5px rgba(96,165,250,0.7); animation-delay: {{ loop.index0 * 0.32 }}s;"></span>
{% endfor %} {% endfor %}
</div> </div>
@@ -1104,7 +1104,7 @@
{'text': '100&nbsp;% Confidentiel — Hébergé au Qc', 'x': 18, 'y': 40} {'text': '100&nbsp;% Confidentiel — Hébergé au Qc', 'x': 18, 'y': 40}
] %} ] %}
<div class="absolute flex items-center gap-1.5 px-2 py-1 rounded backdrop-blur-sm" <div class="absolute flex items-center gap-1.5 px-2 py-1 rounded backdrop-blur-sm"
style="left: {{ sol.x }}%; top: {{ sol.y }}%; transform: translate(-50%, -50%); background: rgba(167,139,250,0.10); border: 1px solid rgba(167,139,250,0.20);"> style="left: {{ sol.x }}%; top: {{ sol.y }}%; transform: translate(-50%, -50%); background: rgba(96,165,250,0.10); border: 1px solid rgba(96,165,250,0.20);">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="w-2.5 h-2.5 text-brand-b1 shrink-0" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" class="w-2.5 h-2.5 text-brand-b1 shrink-0" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>
<span class="text-[8px] md:text-[10px] text-white/80 whitespace-nowrap">{{ sol.text | safe }}</span> <span class="text-[8px] md:text-[10px] text-white/80 whitespace-nowrap">{{ sol.text | safe }}</span>
</div> </div>
@@ -1129,7 +1129,7 @@
@click.stop="toggle()" @click.stop="toggle()"
class="absolute bottom-3 left-1/2 -translate-x-1/2 z-30 inline-flex items-center gap-2 px-5 py-2.5 rounded text-xs font-bold transition-all border focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2" class="absolute bottom-3 left-1/2 -translate-x-1/2 z-30 inline-flex items-center gap-2 px-5 py-2.5 rounded text-xs font-bold transition-all border focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
:class="activated ? 'border-brand-b1/30 text-brand-b1' : 'border-white/15 text-white/70'" :class="activated ? 'border-brand-b1/30 text-brand-b1' : 'border-white/15 text-white/70'"
:style="activated ? 'background: linear-gradient(135deg, rgba(167,139,250,0.2), rgba(124,58,237,0.1));' : 'background: linear-gradient(135deg, rgba(255,255,255,0.08), rgba(255,255,255,0.03));'" :style="activated ? 'background: linear-gradient(135deg, rgba(96,165,250,0.2), rgba(37,99,235,0.1));' : 'background: linear-gradient(135deg, rgba(255,255,255,0.08), rgba(255,255,255,0.03));'"
x-cloak> x-cloak>
<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-3.5 h-3.5"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/></svg> <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-3.5 h-3.5"><rect x="9" y="2" width="6" height="12" rx="3"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/></svg>
<span x-text="activated ? 'Voir sans DictIA' : 'Activer DictIA'"></span> <span x-text="activated ? 'Voir sans DictIA' : 'Activer DictIA'"></span>
@@ -1220,7 +1220,7 @@
<div class="absolute h-px bg-brand-border" style="top: 44px; left: 12.5%; right: 12.5%;" aria-hidden="true"></div> <div class="absolute h-px bg-brand-border" style="top: 44px; left: 12.5%; right: 12.5%;" aria-hidden="true"></div>
<div <div
class="pipeline-track-fill absolute h-[2px]" class="pipeline-track-fill absolute h-[2px]"
style="top: 43px; left: 12.5%; width: 75%; background: linear-gradient(90deg, #7c3aed 0%, #a855f7 100%);" style="top: 43px; left: 12.5%; width: 75%; background: linear-gradient(90deg, #2563eb 0%, #06b6d4 100%);"
:style="`transform: scaleX(${steps[active].fillPct / 100})`" :style="`transform: scaleX(${steps[active].fillPct / 100})`"
aria-hidden="true" aria-hidden="true"
></div> ></div>
@@ -1228,7 +1228,7 @@
{# Moving glowing dot — left transitions via CSS #} {# Moving glowing dot — left transitions via CSS #}
<div <div
class="pipeline-dot absolute w-3.5 h-3.5 rounded-full bg-white pointer-events-none z-10" class="pipeline-dot absolute w-3.5 h-3.5 rounded-full bg-white pointer-events-none z-10"
style="top: 44px; transform: translate(-50%, -50%); box-shadow: 0 0 18px rgba(168,85,247,0.55), 0 0 36px rgba(124,58,237,0.35);" style="top: 44px; transform: translate(-50%, -50%); box-shadow: 0 0 18px rgba(6,182,212,0.55), 0 0 36px rgba(37,99,235,0.35);"
:style="`left: ${steps[active].positionPct}%`" :style="`left: ${steps[active].positionPct}%`"
aria-hidden="true" aria-hidden="true"
></div> ></div>
@@ -1258,7 +1258,7 @@
<span <span
class="relative w-[88px] h-[88px] rounded-full border-2 flex items-center justify-center transition-all duration-300" class="relative w-[88px] h-[88px] rounded-full border-2 flex items-center justify-center transition-all duration-300"
:class="{ :class="{
'border-brand-b1 bg-brand-b1/10 scale-105 shadow-[0_0_28px_rgba(124,58,237,0.35)]': active === {{ loop.index0 }}, 'border-brand-b1 bg-brand-b1/10 scale-105 shadow-[0_0_28px_rgba(37,99,235,0.35)]': active === {{ loop.index0 }},
'border-brand-b3/60 bg-brand-b3/10': active > {{ loop.index0 }}, 'border-brand-b3/60 bg-brand-b3/10': active > {{ loop.index0 }},
'border-brand-border bg-white': active < {{ loop.index0 }} 'border-brand-border bg-white': active < {{ loop.index0 }}
}" }"
@@ -1283,7 +1283,7 @@
viewBox="0 0 88 88" viewBox="0 0 88 88"
aria-hidden="true" aria-hidden="true"
> >
<circle class="pipeline-sweep-ring" cx="44" cy="44" r="41" fill="none" stroke="#7c3aed" stroke-width="2" stroke-linecap="round"></circle> <circle class="pipeline-sweep-ring" cx="44" cy="44" r="41" fill="none" stroke="#2563eb" stroke-width="2" stroke-linecap="round"></circle>
</svg> </svg>
</template> </template>
</span> </span>
@@ -1318,7 +1318,7 @@
<span <span
:key="active" :key="active"
class="pipeline-underline absolute bottom-0 left-0 h-[2px] w-full" class="pipeline-underline absolute bottom-0 left-0 h-[2px] w-full"
style="background: linear-gradient(90deg, #7c3aed, #a855f7);" style="background: linear-gradient(90deg, #2563eb, #06b6d4);"
aria-hidden="true" aria-hidden="true"
></span> ></span>
</div> </div>
@@ -1470,8 +1470,8 @@
.hub-ring-3 { animation-delay: 2s; } .hub-ring-3 { animation-delay: 2s; }
/* DictIA core breathing glow */ /* DictIA core breathing glow */
@keyframes hub-core-breathe { @keyframes hub-core-breathe {
0%, 100% { box-shadow: 0 0 26px rgba(168,85,247,0.55), 0 0 56px rgba(168,85,247,0.18); } 0%, 100% { box-shadow: 0 0 26px rgba(6,182,212,0.55), 0 0 56px rgba(6,182,212,0.18); }
50% { box-shadow: 0 0 38px rgba(168,85,247,0.75), 0 0 72px rgba(168,85,247,0.28); } 50% { box-shadow: 0 0 38px rgba(6,182,212,0.75), 0 0 72px rgba(6,182,212,0.28); }
} }
.hub-core { animation: hub-core-breathe 3.5s ease-in-out infinite; } .hub-core { animation: hub-core-breathe 3.5s ease-in-out infinite; }
/* Reduced motion : freeze everything */ /* Reduced motion : freeze everything */
@@ -1533,14 +1533,14 @@
{# Render bezier connections (visible strokes) — DictIA → Hubs (thick), Hub → Tools (thin) #} {# Render bezier connections (visible strokes) — DictIA → Hubs (thick), Hub → Tools (thin) #}
{# DictIA → Hubs #} {# DictIA → Hubs #}
<use href="#hub-path-docs" fill="none" stroke="#7c3aed" stroke-width="1.5" opacity="0.55" /> <use href="#hub-path-docs" fill="none" stroke="#2563eb" stroke-width="1.5" opacity="0.55" />
<use href="#hub-path-comm" fill="none" stroke="#06b6d4" stroke-width="1.5" opacity="0.55" /> <use href="#hub-path-comm" fill="none" stroke="#06b6d4" stroke-width="1.5" opacity="0.55" />
<use href="#hub-path-auto" fill="none" stroke="#8b5cf6" stroke-width="1.5" opacity="0.55" /> <use href="#hub-path-auto" fill="none" stroke="#8b5cf6" stroke-width="1.5" opacity="0.55" />
{# Hub → Tool (lighter) #} {# Hub → Tool (lighter) #}
<use href="#hub-path-word" fill="none" stroke="#7c3aed" stroke-width="1" opacity="0.30" /> <use href="#hub-path-word" fill="none" stroke="#2563eb" stroke-width="1" opacity="0.30" />
<use href="#hub-path-google" fill="none" stroke="#7c3aed" stroke-width="1" opacity="0.30" /> <use href="#hub-path-google" fill="none" stroke="#2563eb" stroke-width="1" opacity="0.30" />
<use href="#hub-path-obsidian" fill="none" stroke="#7c3aed" stroke-width="1" opacity="0.30" /> <use href="#hub-path-obsidian" fill="none" stroke="#2563eb" stroke-width="1" opacity="0.30" />
<use href="#hub-path-outlook" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" /> <use href="#hub-path-outlook" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" />
<use href="#hub-path-teams" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" /> <use href="#hub-path-teams" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" />
<use href="#hub-path-notion" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" /> <use href="#hub-path-notion" fill="none" stroke="#06b6d4" stroke-width="1" opacity="0.30" />
@@ -1550,7 +1550,7 @@
{# Animated particles — DictIA → Hubs (bigger, dual particles) #} {# Animated particles — DictIA → Hubs (bigger, dual particles) #}
{% for hub in [ {% for hub in [
('docs', '#7c3aed', '0s', '2.4s'), ('docs', '#2563eb', '0s', '2.4s'),
('comm', '#06b6d4', '0.8s', '2.4s'), ('comm', '#06b6d4', '0.8s', '2.4s'),
('auto', '#8b5cf6', '1.6s', '2.4s') ('auto', '#8b5cf6', '1.6s', '2.4s')
] %} ] %}
@@ -1568,9 +1568,9 @@
{# Animated particles — Hub → Tool (smaller, fast) #} {# Animated particles — Hub → Tool (smaller, fast) #}
{% for tool in [ {% for tool in [
('word', '#7c3aed', '0s'), ('word', '#2563eb', '0s'),
('google', '#7c3aed', '0.4s'), ('google', '#2563eb', '0.4s'),
('obsidian', '#7c3aed', '0.8s'), ('obsidian', '#2563eb', '0.8s'),
('outlook', '#06b6d4', '0.2s'), ('outlook', '#06b6d4', '0.2s'),
('teams', '#06b6d4', '0.6s'), ('teams', '#06b6d4', '0.6s'),
('notion', '#06b6d4', '1.0s'), ('notion', '#06b6d4', '1.0s'),
@@ -1602,7 +1602,7 @@
{# Hub labels overlay — positioned to match SVG hub coords (200/460 = 43.5% top, 168/900=18.7% / 450/900=50% / 732/900=81.3% left) #} {# Hub labels overlay — positioned to match SVG hub coords (200/460 = 43.5% top, 168/900=18.7% / 450/900=50% / 732/900=81.3% left) #}
{% set hub_data = [ {% set hub_data = [
('Documents', 'Word · Google Docs · Obsidian', '18.7%', 'rgba(124,58,237,0.10)', 'rgba(124,58,237,0.30)', 'text-violet-300'), ('Documents', 'Word · Google Docs · Obsidian', '18.7%', 'rgba(37,99,235,0.10)', 'rgba(37,99,235,0.30)', 'text-violet-300'),
('Communication', 'Outlook · Teams · Notion', '50%', 'rgba(6,182,212,0.10)', 'rgba(6,182,212,0.30)', 'text-cyan-300'), ('Communication', 'Outlook · Teams · Notion', '50%', 'rgba(6,182,212,0.10)', 'rgba(6,182,212,0.30)', 'text-cyan-300'),
('Automatisation', 'Zapier · Make · n8n', '81.3%', 'rgba(139,92,246,0.10)', 'rgba(139,92,246,0.30)', 'text-purple-300') ('Automatisation', 'Zapier · Make · n8n', '81.3%', 'rgba(139,92,246,0.10)', 'rgba(139,92,246,0.30)', 'text-purple-300')
] %} ] %}
@@ -2148,7 +2148,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"
class="relative w-5 h-5 transition-colors duration-300" class="relative w-5 h-5 transition-colors duration-300"
:class="step >= 2 ? 'text-amber-500' : 'text-brand-b1'" :class="step >= 2 ? 'text-amber-500' : 'text-brand-b1'"
:style="`filter: drop-shadow(0 0 ${step >= 2 ? '6px rgba(245,158,11,0.7)' : '4px rgba(124,58,237,0.5)'})`" :style="`filter: drop-shadow(0 0 ${step >= 2 ? '6px rgba(245,158,11,0.7)' : '4px rgba(37,99,235,0.5)'})`"
aria-hidden="true"> aria-hidden="true">
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/> <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
</svg> </svg>
@@ -2225,15 +2225,15 @@
<a href="{{ reg.href }}" target="_blank" rel="noopener noreferrer" <a href="{{ reg.href }}" target="_blank" rel="noopener noreferrer"
class="cadre-reg group flex items-start gap-2 rounded px-2.5 py-1.5 no-underline border focus-visible:outline-2 focus-visible:outline-amber-500 focus-visible:outline-offset-2" class="cadre-reg group flex items-start gap-2 rounded px-2.5 py-1.5 no-underline border focus-visible:outline-2 focus-visible:outline-amber-500 focus-visible:outline-offset-2"
:class="flashIdx === {{ loop.index0 }} ? 'is-flash' : ''" :class="flashIdx === {{ loop.index0 }} ? 'is-flash' : ''"
style="border-color: {{ 'rgba(239,68,68,0.20)' if reg.risk else 'rgba(124,58,237,0.15)' }};"> style="border-color: {{ 'rgba(239,68,68,0.20)' if reg.risk else 'rgba(37,99,235,0.15)' }};">
<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" <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-3.5 h-3.5 mt-0.5 shrink-0" class="w-3.5 h-3.5 mt-0.5 shrink-0"
style="color: {{ 'rgba(239,68,68,0.65)' if reg.risk else 'rgba(124,58,237,0.55)' }};" style="color: {{ 'rgba(239,68,68,0.65)' if reg.risk else 'rgba(37,99,235,0.55)' }};"
aria-hidden="true"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> aria-hidden="true"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-1.5 flex-wrap"> <div class="flex items-start gap-1.5 flex-wrap">
<span class="cadre-reg-label font-semibold text-[11px] leading-tight shrink-0 transition-colors" <span class="cadre-reg-label font-semibold text-[11px] leading-tight shrink-0 transition-colors"
style="color: {{ '#dc2626' if reg.risk else '#7c3aed' }};">{{ reg.label }}</span> style="color: {{ '#dc2626' if reg.risk else '#2563eb' }};">{{ reg.label }}</span>
<span class="text-[10px] leading-tight text-brand-navy/55">{{ reg.detail | safe }}</span> <span class="text-[10px] leading-tight text-brand-navy/55">{{ reg.detail | safe }}</span>
</div> </div>
</div> </div>
@@ -2513,7 +2513,7 @@
{# Two warm cosmic orbs to mirror the Hero — visual closure of the page #} {# Two warm cosmic orbs to mirror the Hero — visual closure of the page #}
<div class="absolute inset-0 pointer-events-none" aria-hidden="true"> <div class="absolute inset-0 pointer-events-none" aria-hidden="true">
<div class="absolute top-1/4 left-1/3 w-[500px] h-[500px] rounded-full" <div class="absolute top-1/4 left-1/3 w-[500px] h-[500px] rounded-full"
style="background: radial-gradient(circle, rgba(124,58,237,0.14) 0%, transparent 60%); filter: blur(50px);"></div> style="background: radial-gradient(circle, rgba(37,99,235,0.14) 0%, transparent 60%); filter: blur(50px);"></div>
<div class="absolute bottom-1/4 right-1/3 w-[450px] h-[450px] rounded-full" <div class="absolute bottom-1/4 right-1/3 w-[450px] h-[450px] rounded-full"
style="background: radial-gradient(circle, rgba(6,182,212,0.10) 0%, transparent 60%); filter: blur(50px);"></div> style="background: radial-gradient(circle, rgba(6,182,212,0.10) 0%, transparent 60%); filter: blur(50px);"></div>
</div> </div>

View File

@@ -117,7 +117,7 @@
<section class="relative bg-brand-navy text-white py-20 overflow-hidden" aria-labelledby="tarifs-cta-title"> <section class="relative bg-brand-navy text-white py-20 overflow-hidden" aria-labelledby="tarifs-cta-title">
<div class="absolute inset-0 pointer-events-none" aria-hidden="true"> <div class="absolute inset-0 pointer-events-none" aria-hidden="true">
<div class="absolute top-1/3 left-1/3 w-[500px] h-[500px] rounded-full" <div class="absolute top-1/3 left-1/3 w-[500px] h-[500px] rounded-full"
style="background: radial-gradient(circle, rgba(124,58,237,0.12) 0%, transparent 60%); filter: blur(50px);"></div> style="background: radial-gradient(circle, rgba(37,99,235,0.12) 0%, transparent 60%); filter: blur(50px);"></div>
</div> </div>
<div class="relative max-w-[820px] mx-auto px-6 text-center"> <div class="relative max-w-[820px] mx-auto px-6 text-center">
<h2 id="tarifs-cta-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-6"> <h2 id="tarifs-cta-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-6">

View File

@@ -73,14 +73,20 @@ def test_email_template_uses_dictia_branding():
assert 'Loi' in html and '25' in html, 'Tagline must mention Loi 25' assert 'Loi' in html and '25' in html, 'Tagline must mention Loi 25'
def test_email_template_header_uses_brand_gradient_not_speakr_blue(): def test_email_template_header_uses_brand_gradient():
"""Header bg must use DictIA brand color #0062ff (or gradient), not the legacy """Header bg must use the official DictIA brand gradient (blue → cyan → fuchsia,
Speakr #2563eb.""" matches the official logo). The legacy #0062ff/#00bdd8/#00c896 palette must be gone."""
with app.app_context(): with app.app_context():
from src.services.email import _get_email_template from src.services.email import _get_email_template
html, _ = _get_email_template('x', 'x', 'Test') html, _ = _get_email_template('x', 'x', 'Test')
assert '#2563eb' not in html, 'Legacy Speakr header color must be removed' # Legacy palette must be removed
assert '#0062ff' in html, 'DictIA brand blue must be present' assert '#0062ff' not in html, 'Legacy header color #0062ff must be removed'
assert '#00bdd8' not in html, 'Legacy mid color #00bdd8 must be removed'
assert '#00c896' not in html, 'Legacy end color #00c896 must be removed'
# New official-logo palette must be present
assert '#2563eb' in html, 'DictIA brand blue (#2563eb) must be present'
assert '#06b6d4' in html, 'DictIA brand cyan (#06b6d4) must be present'
assert '#c026d3' in html, 'DictIA brand fuchsia (#c026d3) must be present'
def test_verification_email_subject_is_french_with_dictia(): def test_verification_email_subject_is_french_with_dictia():

View File

@@ -110,11 +110,11 @@ def test_hero_has_dual_cta():
def test_hero_has_cosmic_orbs_background(): def test_hero_has_cosmic_orbs_background():
"""Hero has 3 radial gradient orbs (FlexiHub signature, mauve/aqua palette).""" """Hero has 3 radial gradient orbs (FlexiHub signature, blue/aqua palette — matches official DictIA logo)."""
client = app.test_client() client = app.test_client()
body = client.get('/').data.decode('utf-8') body = client.get('/').data.decode('utf-8')
# Look for the 3 orb opacities (16% mauve, 7% aqua, 11% aqua accent) # Look for the 3 orb opacities (16% blue, 7% aqua, 11% aqua accent)
assert 'rgba(124,58,237,0.16)' in body, "Missing primary mauve orb" assert 'rgba(37,99,235,0.16)' in body, "Missing primary blue orb"
assert 'rgba(6,182,212,0.07)' in body, "Missing aqua orb" assert 'rgba(6,182,212,0.07)' in body, "Missing aqua orb"
assert 'rgba(6,182,212,0.11)' in body, "Missing aqua accent orb" assert 'rgba(6,182,212,0.11)' in body, "Missing aqua accent orb"