refactor(marketing): Cycle cinematic PRO — palette brand uniformisée + USA map + Quebec outline + halo brand

Round 5 cinématique de la section "Trois options. Une seule est conforme." :
- Palette brand uniformisée (blue/cyan/fuchsia) — col 3 passe de emerald/green à brand-b1+brand-b2 + accents fuchsia
- Connecting horizontal beam progressive 0→33→66→100% entre les 3 colonnes (gris→rouge→cyan)
- Spotlight active column (opacity 0.65 inactif, 1 actif + scale 1.02)
- Col 1 : stack papiers stagger reveal 180ms + horloge 2.5s + counter \$315
- Col 2 : USA map silhouette subtle bg + server rack 3-leds + 12 paquets data .wav/.aac flying vers top-right + screen shake + flash red + chevrons + sound icon pulse
- Col 3 : Quebec province outline subtle + mini logo DictIA + halo multi-couches blue+cyan+fuchsia + drawn ring SVG (fuchsia accent) + shield-with-microphone + checkmark cyan + badge Loi 25 conforme gradient brand + big 173 \$ en grad-text
- Section Économies : counters en grad-text + save chips "+économies" + chips contextuels + icônes distinctives (loutre/Teams T/sténographe humain)
- Phase delays cinématiques 400/1100/2000/3100ms + cubic-bezier overshoot
- Vignette ambiante + grid pattern 40×40 + orbes décoratifs blur

WCAG : aria-labels préservés + prefers-reduced-motion désactive radar/particles/screen-shake/halo/beam.
Mobile : leak particles + orbes + halo heavy + screen shake désactivés via @media (max-width: 768px).
Performance : will-change GPU hints sur stamp/halo/leak.

Tests cycle round 4 (3) toujours passants. 65/68 tests pass (3 failures pré-existantes : /blog nav).
HTTP 200 vérifié sur http://127.0.0.1:8899/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-28 17:07:59 -04:00
parent 575db5e342
commit e8c7e5cd43
2 changed files with 541 additions and 218 deletions

View File

@@ -398,6 +398,9 @@
.-top-12 { .-top-12 {
top: calc(var(--spacing) * -12); top: calc(var(--spacing) * -12);
} }
.-top-20 {
top: calc(var(--spacing) * -20);
}
.top-0 { .top-0 {
top: calc(var(--spacing) * 0); top: calc(var(--spacing) * 0);
} }
@@ -449,6 +452,9 @@
.-right-12 { .-right-12 {
right: calc(var(--spacing) * -12); right: calc(var(--spacing) * -12);
} }
.-right-24 {
right: calc(var(--spacing) * -24);
}
.right-0 { .right-0 {
right: calc(var(--spacing) * 0); right: calc(var(--spacing) * 0);
} }
@@ -482,6 +488,9 @@
.right-\[6\%\] { .right-\[6\%\] {
right: 6%; right: 6%;
} }
.-bottom-24 {
bottom: calc(var(--spacing) * -24);
}
.bottom-0 { .bottom-0 {
bottom: calc(var(--spacing) * 0); bottom: calc(var(--spacing) * 0);
} }
@@ -497,6 +506,9 @@
.bottom-full { .bottom-full {
bottom: 100%; bottom: 100%;
} }
.-left-20 {
left: calc(var(--spacing) * -20);
}
.left-0 { .left-0 {
left: calc(var(--spacing) * 0); left: calc(var(--spacing) * 0);
} }
@@ -854,17 +866,17 @@
.h-\[1\.5px\] { .h-\[1\.5px\] {
height: 1.5px; height: 1.5px;
} }
.h-\[1px\] {
height: 1px;
}
.h-\[2px\] { .h-\[2px\] {
height: 2px; height: 2px;
} }
.h-\[3px\] {
height: 3px;
}
.h-\[17px\] { .h-\[17px\] {
height: 17px; height: 17px;
} }
.h-\[52px\] { .h-\[56px\] {
height: 52px; height: 56px;
} }
.h-\[62px\] { .h-\[62px\] {
height: 62px; height: 62px;
@@ -881,9 +893,15 @@
.h-\[95vh\] { .h-\[95vh\] {
height: 95vh; height: 95vh;
} }
.h-\[360px\] {
height: 360px;
}
.h-\[400px\] { .h-\[400px\] {
height: 400px; height: 400px;
} }
.h-\[420px\] {
height: 420px;
}
.h-\[450px\] { .h-\[450px\] {
height: 450px; height: 450px;
} }
@@ -1043,11 +1061,8 @@
.w-80 { .w-80 {
width: calc(var(--spacing) * 80); width: calc(var(--spacing) * 80);
} }
.w-\[3px\] { .w-\[56px\] {
width: 3px; width: 56px;
}
.w-\[52px\] {
width: 52px;
} }
.w-\[68px\] { .w-\[68px\] {
width: 68px; width: 68px;
@@ -1061,9 +1076,15 @@
.w-\[100px\] { .w-\[100px\] {
width: 100px; width: 100px;
} }
.w-\[360px\] {
width: 360px;
}
.w-\[400px\] { .w-\[400px\] {
width: 400px; width: 400px;
} }
.w-\[420px\] {
width: 420px;
}
.w-\[450px\] { .w-\[450px\] {
width: 450px; width: 450px;
} }
@@ -1389,6 +1410,9 @@
.gap-\[1\.5px\] { .gap-\[1\.5px\] {
gap: 1.5px; gap: 1.5px;
} }
.gap-\[3px\] {
gap: 3px;
}
.space-y-0\.5 { .space-y-0\.5 {
:where(& > :not(:last-child)) { :where(& > :not(:last-child)) {
--tw-space-y-reverse: 0; --tw-space-y-reverse: 0;
@@ -1541,6 +1565,9 @@
.rounded { .rounded {
border-radius: 0.75rem; border-radius: 0.75rem;
} }
.rounded-\[2px\] {
border-radius: 2px;
}
.rounded-full { .rounded-full {
border-radius: calc(infinity * 1px); border-radius: calc(infinity * 1px);
} }
@@ -1705,9 +1732,6 @@
.border-brand-b1 { .border-brand-b1 {
border-color: #2563eb; border-color: #2563eb;
} }
.border-brand-b1\/15 {
border-color: color-mix(in oklab, #2563eb 15%, transparent);
}
.border-brand-b1\/20 { .border-brand-b1\/20 {
border-color: color-mix(in oklab, #2563eb 20%, transparent); border-color: color-mix(in oklab, #2563eb 20%, transparent);
} }
@@ -1717,12 +1741,27 @@
.border-brand-b1\/30 { .border-brand-b1\/30 {
border-color: color-mix(in oklab, #2563eb 30%, transparent); border-color: color-mix(in oklab, #2563eb 30%, transparent);
} }
.border-brand-b1\/35 { .border-brand-b1\/40 {
border-color: color-mix(in oklab, #2563eb 35%, transparent); border-color: color-mix(in oklab, #2563eb 40%, transparent);
}
.border-brand-b2\/20 {
border-color: color-mix(in oklab, #06b6d4 20%, transparent);
}
.border-brand-b2\/25 {
border-color: color-mix(in oklab, #06b6d4 25%, transparent);
}
.border-brand-b2\/30 {
border-color: color-mix(in oklab, #06b6d4 30%, transparent);
} }
.border-brand-b2\/40 { .border-brand-b2\/40 {
border-color: color-mix(in oklab, #06b6d4 40%, transparent); border-color: color-mix(in oklab, #06b6d4 40%, transparent);
} }
.border-brand-b2\/45 {
border-color: color-mix(in oklab, #06b6d4 45%, transparent);
}
.border-brand-b2\/50 {
border-color: color-mix(in oklab, #06b6d4 50%, transparent);
}
.border-brand-b3\/15 { .border-brand-b3\/15 {
border-color: color-mix(in oklab, #c026d3 15%, transparent); border-color: color-mix(in oklab, #c026d3 15%, transparent);
} }
@@ -1732,21 +1771,6 @@
.border-brand-border { .border-brand-border {
border-color: #e6ebf2; border-color: #e6ebf2;
} }
.border-emerald-100 {
border-color: var(--color-emerald-100);
}
.border-emerald-500\/40 {
border-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-emerald-500) 40%, transparent);
}
}
.border-emerald-500\/45 {
border-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 45%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-emerald-500) 45%, transparent);
}
}
.border-gray-300 { .border-gray-300 {
border-color: var(--color-gray-300); border-color: var(--color-gray-300);
} }
@@ -1786,6 +1810,12 @@
.border-red-200 { .border-red-200 {
border-color: var(--color-red-200); border-color: var(--color-red-200);
} }
.border-red-200\/70 {
border-color: color-mix(in srgb, oklch(88.5% 0.062 18.334) 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
border-color: color-mix(in oklab, var(--color-red-200) 70%, transparent);
}
}
.border-red-300 { .border-red-300 {
border-color: var(--color-red-300); border-color: var(--color-red-300);
} }
@@ -2032,17 +2062,17 @@
.bg-brand-b1 { .bg-brand-b1 {
background-color: #2563eb; background-color: #2563eb;
} }
.bg-brand-b1\/5 {
background-color: color-mix(in oklab, #2563eb 5%, transparent);
}
.bg-brand-b1\/10 { .bg-brand-b1\/10 {
background-color: color-mix(in oklab, #2563eb 10%, transparent); background-color: color-mix(in oklab, #2563eb 10%, transparent);
} }
.bg-brand-b1\/15 { .bg-brand-b1\/\[0\.08\] {
background-color: color-mix(in oklab, #2563eb 15%, transparent); background-color: color-mix(in oklab, #2563eb 8%, transparent);
} }
.bg-brand-b1\/\[0\.06\] { .bg-brand-b2 {
background-color: color-mix(in oklab, #2563eb 6%, transparent); background-color: #06b6d4;
}
.bg-brand-b2\/20 {
background-color: color-mix(in oklab, #06b6d4 20%, transparent);
} }
.bg-brand-b3 { .bg-brand-b3 {
background-color: #c026d3; background-color: #c026d3;
@@ -2065,6 +2095,9 @@
.bg-brand-border { .bg-brand-border {
background-color: #e6ebf2; background-color: #e6ebf2;
} }
.bg-brand-border\/60 {
background-color: color-mix(in oklab, #e6ebf2 60%, transparent);
}
.bg-brand-navy { .bg-brand-navy {
background-color: #060d1a; background-color: #060d1a;
} }
@@ -2086,21 +2119,6 @@
.bg-brand-navy2 { .bg-brand-navy2 {
background-color: #0b1525; background-color: #0b1525;
} }
.bg-emerald-50 {
background-color: var(--color-emerald-50);
}
.bg-emerald-500\/12 {
background-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 12%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-emerald-500) 12%, transparent);
}
}
.bg-emerald-500\/15 {
background-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 15%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-emerald-500) 15%, transparent);
}
}
.bg-emerald-600 { .bg-emerald-600 {
background-color: var(--color-emerald-600); background-color: var(--color-emerald-600);
} }
@@ -2209,6 +2227,12 @@
background-color: color-mix(in oklab, var(--color-red-50) 40%, transparent); background-color: color-mix(in oklab, var(--color-red-50) 40%, transparent);
} }
} }
.bg-red-50\/80 {
background-color: color-mix(in srgb, oklch(97.1% 0.013 17.38) 80%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-red-50) 80%, transparent);
}
}
.bg-red-100 { .bg-red-100 {
background-color: var(--color-red-100); background-color: var(--color-red-100);
} }
@@ -2218,6 +2242,12 @@
background-color: color-mix(in oklab, var(--color-red-100) 60%, transparent); background-color: color-mix(in oklab, var(--color-red-100) 60%, transparent);
} }
} }
.bg-red-300\/60 {
background-color: color-mix(in srgb, oklch(80.8% 0.114 19.571) 60%, transparent);
@supports (color: color-mix(in lab, red, red)) {
background-color: color-mix(in oklab, var(--color-red-300) 60%, transparent);
}
}
.bg-red-400 { .bg-red-400 {
background-color: var(--color-red-400); background-color: var(--color-red-400);
} }
@@ -2369,12 +2399,12 @@
--tw-gradient-from: var(--color-blue-600); --tw-gradient-from: var(--color-blue-600);
--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\/20 {
--tw-gradient-from: color-mix(in oklab, #2563eb 15%, transparent); --tw-gradient-from: color-mix(in oklab, #2563eb 20%, 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\.07\] {
--tw-gradient-from: color-mix(in oklab, #2563eb 6%, transparent); --tw-gradient-from: color-mix(in oklab, #2563eb 7.000000000000001%, 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 {
@@ -2389,6 +2419,10 @@
--tw-gradient-from: var(--color-red-500); --tw-gradient-from: var(--color-red-500);
--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-transparent {
--tw-gradient-from: 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));
}
.from-violet-500 { .from-violet-500 {
--tw-gradient-from: var(--color-violet-500); --tw-gradient-from: var(--color-violet-500);
--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));
@@ -2400,6 +2434,26 @@
} }
--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));
} }
.via-brand-b1\/30 {
--tw-gradient-via: color-mix(in oklab, #2563eb 30%, transparent);
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
--tw-gradient-stops: var(--tw-gradient-via-stops);
}
.via-brand-b2\/15 {
--tw-gradient-via: color-mix(in oklab, #06b6d4 15%, transparent);
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
--tw-gradient-stops: var(--tw-gradient-via-stops);
}
.via-brand-b2\/\[0\.04\] {
--tw-gradient-via: color-mix(in oklab, #06b6d4 4%, transparent);
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
--tw-gradient-stops: var(--tw-gradient-via-stops);
}
.via-brand-b3\/30 {
--tw-gradient-via: color-mix(in oklab, #c026d3 30%, transparent);
--tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);
--tw-gradient-stops: var(--tw-gradient-via-stops);
}
.via-purple-500\/10 { .via-purple-500\/10 {
--tw-gradient-via: color-mix(in srgb, oklch(62.7% 0.265 303.9) 10%, transparent); --tw-gradient-via: color-mix(in srgb, oklch(62.7% 0.265 303.9) 10%, transparent);
@supports (color: color-mix(in lab, red, red)) { @supports (color: color-mix(in lab, red, red)) {
@@ -2424,6 +2478,10 @@
--tw-gradient-to: #2563eb; --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-b2\/30 {
--tw-gradient-to: color-mix(in oklab, #06b6d4 30%, 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));
}
.to-brand-b3\/10 { .to-brand-b3\/10 {
--tw-gradient-to: color-mix(in oklab, #c026d3 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));
@@ -2582,6 +2640,9 @@
.py-24 { .py-24 {
padding-block: calc(var(--spacing) * 24); padding-block: calc(var(--spacing) * 24);
} }
.py-px {
padding-block: 1px;
}
.pt-0 { .pt-0 {
padding-top: calc(var(--spacing) * 0); padding-top: calc(var(--spacing) * 0);
} }
@@ -2751,6 +2812,12 @@
font-size: var(--text-xs); font-size: var(--text-xs);
line-height: var(--tw-leading, var(--text-xs--line-height)); line-height: var(--tw-leading, var(--text-xs--line-height));
} }
.text-\[6px\] {
font-size: 6px;
}
.text-\[7px\] {
font-size: 7px;
}
.text-\[8px\] { .text-\[8px\] {
font-size: 8px; font-size: 8px;
} }
@@ -2848,9 +2915,9 @@
--tw-tracking: 0.2em; --tw-tracking: 0.2em;
letter-spacing: 0.2em; letter-spacing: 0.2em;
} }
.tracking-\[0\.14em\] { .tracking-\[0\.10em\] {
--tw-tracking: 0.14em; --tw-tracking: 0.10em;
letter-spacing: 0.14em; letter-spacing: 0.10em;
} }
.tracking-\[0\.16em\] { .tracking-\[0\.16em\] {
--tw-tracking: 0.16em; --tw-tracking: 0.16em;
@@ -3000,15 +3067,6 @@
.text-brand-b1 { .text-brand-b1 {
color: #2563eb; color: #2563eb;
} }
.text-brand-b1\/45 {
color: color-mix(in oklab, #2563eb 45%, transparent);
}
.text-brand-b1\/55 {
color: color-mix(in oklab, #2563eb 55%, transparent);
}
.text-brand-b1\/60 {
color: color-mix(in oklab, #2563eb 60%, transparent);
}
.text-brand-b1\/65 { .text-brand-b1\/65 {
color: color-mix(in oklab, #2563eb 65%, transparent); color: color-mix(in oklab, #2563eb 65%, transparent);
} }
@@ -3018,6 +3076,9 @@
.text-brand-b1\/80 { .text-brand-b1\/80 {
color: color-mix(in oklab, #2563eb 80%, transparent); color: color-mix(in oklab, #2563eb 80%, transparent);
} }
.text-brand-b1\/85 {
color: color-mix(in oklab, #2563eb 85%, transparent);
}
.text-brand-b2 { .text-brand-b2 {
color: #06b6d4; color: #06b6d4;
} }
@@ -3072,18 +3133,6 @@
.text-emerald-500 { .text-emerald-500 {
color: var(--color-emerald-500); color: var(--color-emerald-500);
} }
.text-emerald-600 {
color: var(--color-emerald-600);
}
.text-emerald-600\/70 {
color: color-mix(in srgb, oklch(59.6% 0.145 163.225) 70%, transparent);
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, var(--color-emerald-600) 70%, transparent);
}
}
.text-emerald-700 {
color: var(--color-emerald-700);
}
.text-gray-200 { .text-gray-200 {
color: var(--color-gray-200); color: var(--color-gray-200);
} }
@@ -3356,12 +3405,18 @@
.opacity-90 { .opacity-90 {
opacity: 90%; opacity: 90%;
} }
.opacity-95 {
opacity: 95%;
}
.opacity-100 { .opacity-100 {
opacity: 100%; opacity: 100%;
} }
.opacity-\[0\.02\] { .opacity-\[0\.02\] {
opacity: 0.02; opacity: 0.02;
} }
.opacity-\[0\.04\] {
opacity: 0.04;
}
.shadow { .shadow {
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
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);
@@ -3382,8 +3437,8 @@
--tw-shadow: 0 0 28px var(--tw-shadow-color, rgba(37,99,235,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_12px_40px_-6px_rgba\(239\,68\,68\,0\.65\)\] {
--tw-shadow: 0 8px 30px -6px var(--tw-shadow-color, rgba(239,68,68,0.55)); --tw-shadow: 0 12px 40px -6px var(--tw-shadow-color, rgba(239,68,68,0.65));
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 {

View File

@@ -411,10 +411,69 @@
{# ===== CYCLE — "Trois options. Une seule est conforme." ===== #} {# ===== CYCLE — "Trois options. Une seule est conforme." ===== #}
{# Source canonique : InnovA-AI/Website-Sanity/components/sections/dictai-cycle.tsx {# Source canonique : InnovA-AI/Website-Sanity/components/sections/dictai-cycle.tsx
Round 4 cinématique : phase reveal séquentiel + horloge accélérée + prix counter + stamp impact NON CONFORME Round 5 cinématique PRO : palette brand uniformisée (blue/cyan/fuchsia, zéro vert)
+ checkmark draw + glow vert + connecting line dash flow + section "Économies annuelles" avec 3 counters animés #} + connecting beam progressive 0→33→66→100 + spotlight active column + USA map silhouette col 2
+ Quebec outline col 3 + halo multi-couches blue+cyan + screen shake + 12 paquets data flying
+ grad-text counters + chips contextuels + phase delays cinématiques 400/1100/2000/3100ms #}
<style> <style>
/* Cycle pulse rings — nœud source "Réunion en cours" */ /* === ROUND 5 — Cycle background ambiance (vignette + grid + orbes) === */
.cycle-section-bg {
background:
radial-gradient(ellipse 60% 40% at 12% 0%, rgba(37,99,235,0.045) 0%, transparent 70%),
radial-gradient(ellipse 60% 40% at 88% 100%, rgba(6,182,212,0.045) 0%, transparent 70%);
}
.cycle-grid-bg {
background-image:
linear-gradient(rgba(11,15,26,0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(11,15,26,0.025) 1px, transparent 1px);
background-size: 40px 40px;
}
@keyframes cycle-orb-float {
0%, 100% { transform: translate(0,0) scale(1); }
50% { transform: translate(8px,-12px) scale(1.04); }
}
.cycle-orb { animation: cycle-orb-float 8s ease-in-out infinite; }
.cycle-orb-2 { animation-delay: 2.5s; animation-duration: 10s; }
/* === ROUND 5 — Connecting horizontal beam progressive 0→33→66→100 === */
.cycle-beam {
height: 2px;
background: linear-gradient(90deg,
rgba(148,163,184,0.55) 0%,
rgba(148,163,184,0.55) 33%,
rgba(239,68,68,0.55) 33%,
rgba(239,68,68,0.55) 66%,
rgba(6,182,212,0.85) 66%,
rgba(37,99,235,0.85) 100%);
width: var(--beam, 0%);
transition: width 800ms cubic-bezier(0.34, 1.56, 0.64, 1);
box-shadow: 0 0 8px rgba(37,99,235,0.25);
}
/* Loading dot qui suit la beam */
@keyframes cycle-beam-dot {
0% { left: 4%; background: rgba(148,163,184,1); }
33% { left: 33%; background: rgba(148,163,184,1); }
50% { left: 50%; background: rgba(239,68,68,1); }
66% { left: 66%; background: rgba(239,68,68,1); }
100% { left: 96%; background: rgba(6,182,212,1); }
}
.cycle-beam-dot {
width: 6px; height: 6px; border-radius: 9999px;
top: 50%; transform: translate(-50%,-50%);
box-shadow: 0 0 10px currentColor;
animation: cycle-beam-dot 4s ease-in-out 0.4s 1 forwards;
}
/* === ROUND 5 — Spotlight active column === */
.cycle-col-card {
transition: opacity 600ms cubic-bezier(0.34, 1.56, 0.64, 1),
transform 600ms cubic-bezier(0.34, 1.56, 0.64, 1);
opacity: 0.65;
}
.cycle-col-card.is-active { opacity: 1; transform: scale(1.015); }
.cycle-col-card.is-revealed { opacity: 1; }
/* === Cycle pulse rings — nœud source "Réunion en cours" === */
@keyframes cycle-pulse-ring { @keyframes cycle-pulse-ring {
0% { transform: scale(1); opacity: 0.5; } 0% { transform: scale(1); opacity: 0.5; }
100% { transform: scale(2.1); opacity: 0; } 100% { transform: scale(2.1); opacity: 0; }
@@ -430,102 +489,182 @@
} }
.cycle-live-dot { animation: cycle-live-dot 1.4s ease-in-out infinite; } .cycle-live-dot { animation: cycle-live-dot 1.4s ease-in-out infinite; }
/* Cycle col 3 (DictIA) — bordure lumineuse pulsante VERT (round 4 : conformité) */ /* === ROUND 5 — Cycle col 3 (DictIA) — halo multi-couches blue+cyan (PALETTE BRAND) === */
@keyframes cycle-conforme-glow { @keyframes cycle-conforme-glow {
0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.18), 0 0 0 0 rgba(6,182,212,0.10); } 0%, 100% { box-shadow: 0 0 0 0 rgba(37,99,235,0.20), 0 0 0 0 rgba(6,182,212,0.12), 0 0 0 0 rgba(192,38,211,0.06); }
50% { box-shadow: 0 0 32px 2px rgba(34,197,94,0.32), 0 0 60px 0 rgba(6,182,212,0.14); } 50% { box-shadow: 0 0 36px 3px rgba(37,99,235,0.45), 0 0 64px 6px rgba(6,182,212,0.20), 0 0 96px 12px rgba(192,38,211,0.10); }
} }
.cycle-card-dictia.is-visible { animation: cycle-conforme-glow 3.4s ease-in-out infinite; } .cycle-card-dictia.is-visible { animation: cycle-conforme-glow 3.4s ease-in-out infinite; will-change: box-shadow; }
.cycle-card-dictia { transition: transform 400ms ease-out; will-change: transform; }
.cycle-card-dictia.is-visible:hover { transform: translateY(-3px) scale(1.03); }
/* Cycle col 3 — anneaux concentriques autour du Lock */ /* Cycle col 3 — anneaux concentriques autour du Shield (multi-couches drawn) */
@keyframes cycle-ring-out { @keyframes cycle-ring-out {
0%, 100% { transform: scale(1); opacity: 0.45; } 0%, 100% { transform: scale(1); opacity: 0.55; }
50% { transform: scale(1.07); opacity: 0.18; } 50% { transform: scale(1.08); opacity: 0.20; }
} }
.cycle-ring-outer.is-visible { animation: cycle-ring-out 3.8s ease-in-out infinite; } .cycle-ring-outer.is-visible { animation: cycle-ring-out 3.8s ease-in-out infinite; }
.cycle-ring-inner.is-visible { animation: cycle-ring-out 2.9s ease-in-out infinite 0.5s; } .cycle-ring-inner.is-visible { animation: cycle-ring-out 2.9s ease-in-out infinite 0.5s; }
/* Cycle SVG lignes de connexion — drawn via stroke-dashoffset, dash flow continu (round 4) */ /* Ring SVG drawn line cycling (round 5) */
@keyframes cycle-ring-draw {
0% { stroke-dashoffset: 220; }
100% { stroke-dashoffset: 0; }
}
.cycle-ring-draw-svg circle {
stroke-dasharray: 220;
stroke-dashoffset: 220;
transform-origin: center;
transform: rotate(-90deg);
}
.cycle-ring-draw-svg.is-visible circle { animation: cycle-ring-draw 4s linear infinite; }
/* Cycle SVG lignes de connexion — drawn via stroke-dashoffset, dash flow continu */
.cycle-line { stroke-dasharray: 1.2 0.9; stroke-dashoffset: 50; transition: stroke-dashoffset 600ms ease-out; } .cycle-line { stroke-dasharray: 1.2 0.9; stroke-dashoffset: 50; transition: stroke-dashoffset 600ms ease-out; }
.cycle-line.is-visible { stroke-dashoffset: 0; } .cycle-line.is-visible { stroke-dashoffset: 0; }
@keyframes cycle-dash-flow { to { stroke-dashoffset: -42; } } @keyframes cycle-dash-flow { to { stroke-dashoffset: -42; } }
.cycle-line.is-visible.cycle-line-flow { animation: cycle-dash-flow 12s linear infinite; } .cycle-line.is-visible.cycle-line-flow { animation: cycle-dash-flow 12s linear infinite; }
/* Cycle phase reveal */ /* Cycle phase reveal */
.cycle-reveal { opacity: 0; transform: translateX(14px); transition: opacity 380ms ease-out, transform 380ms ease-out; } .cycle-reveal { opacity: 0; transform: translateX(14px); transition: opacity 380ms cubic-bezier(0.34, 1.56, 0.64, 1), transform 380ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.cycle-reveal.is-visible { opacity: 1; transform: translateX(0); } .cycle-reveal.is-visible { opacity: 1; transform: translateX(0); }
.cycle-reveal-up { opacity: 0; transform: translateY(10px); transition: opacity 500ms ease-out, transform 500ms ease-out; } .cycle-reveal-up { opacity: 0; transform: translateY(10px); transition: opacity 500ms cubic-bezier(0.34, 1.56, 0.64, 1), transform 500ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.cycle-reveal-up.is-visible { opacity: 1; transform: translateY(0); } .cycle-reveal-up.is-visible { opacity: 1; transform: translateY(0); }
/* Cycle horloge rotation (col 1)accélérée 1 tour / 3s pour rendre "lent" PALPABLE */ /* === ROUND 5 — Col 1 — Stack papiers stagger reveal === */
@keyframes cycle-paper-in {
0% { opacity: 0; transform: translateY(8px) rotate(var(--rot, 0deg)); }
100% { opacity: 1; transform: translateY(0) rotate(var(--rot, 0deg)); }
}
.cycle-paper-stack.is-active .cycle-paper {
animation: cycle-paper-in 400ms ease-out forwards;
opacity: 0;
}
/* Cycle horloge rotation (col 1) — accélérée 1 tour / 2.5s + motion blur subtle */
@keyframes cycle-clock-spin { to { transform: rotate(360deg); } } @keyframes cycle-clock-spin { to { transform: rotate(360deg); } }
.cycle-clock { animation: cycle-clock-spin 3s linear infinite; transform-origin: center; display: inline-block; } .cycle-clock { animation: cycle-clock-spin 2.5s linear infinite; transform-origin: center; display: inline-block; will-change: transform; }
/* Cycle col 2 — fuite particules rouges (continu, plus dense round 4) */ /* === ROUND 5 — Col 2 — Data leak particles AMÉLIORÉES (12 paquets vers USA top-right) === */
@keyframes cycle-leak { @keyframes cycle-leak {
0% { transform: translate(0,0) scale(1); opacity: 0; } 0% { transform: translate(0,0) rotate(var(--rot, 0deg)) scale(0.85); opacity: 0; }
20% { opacity: 0.85; } 18% { opacity: 0.9; }
100% { transform: translate(var(--lx,18px), var(--ly,-22px)) scale(0.35); opacity: 0; } 100% { transform: translate(var(--lx, 60px), var(--ly, -80px)) rotate(var(--rot, 0deg)) scale(0.35); opacity: 0; }
} }
.cycle-leak-particle { animation: cycle-leak 1.8s ease-out infinite; } .cycle-leak-particle { animation: cycle-leak 2.2s ease-out infinite; will-change: transform, opacity; }
/* Cycle col 2 — STAMP NON CONFORME impact (round 4 : tampon huissier qui claque) */ /* Cycle col 2 — server rack LED pulse */
@keyframes cycle-led-pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; box-shadow: 0 0 6px currentColor; }
}
.cycle-led { animation: cycle-led-pulse 1.2s ease-in-out infinite; }
.cycle-led-2 { animation-delay: 0.3s; }
.cycle-led-3 { animation-delay: 0.6s; }
/* Warning chevrons slide */
@keyframes cycle-chev-slide {
0%, 100% { transform: translateX(0); opacity: 0.4; }
50% { transform: translateX(-6px); opacity: 1; }
}
.cycle-chev { animation: cycle-chev-slide 1.4s ease-in-out infinite; }
.cycle-chev-2 { animation-delay: 0.2s; }
.cycle-chev-3 { animation-delay: 0.4s; }
/* Cycle col 2 — STAMP NON CONFORME impact (overshoot + screen shake + flash red) */
@keyframes cycle-stamp-impact { @keyframes cycle-stamp-impact {
0% { transform: translate(-50%,-50%) rotate(-22deg) scale(2.4); opacity: 0; filter: blur(2px); } 0% { transform: translate(-50%,-50%) rotate(-25deg) scale(3); opacity: 0; filter: blur(3px); }
55% { transform: translate(-50%,-50%) rotate(-7deg) scale(0.92); opacity: 1; filter: blur(0); } 55% { transform: translate(-50%,-50%) rotate(-9deg) scale(0.90); opacity: 1; filter: blur(0); }
70% { transform: translate(-50%,-50%) rotate(-3deg) scale(1.06); } 70% { transform: translate(-50%,-50%) rotate(-6deg) scale(1.08); }
100% { transform: translate(-50%,-50%) rotate(-3deg) scale(1); opacity: 1; } 100% { transform: translate(-50%,-50%) rotate(-8deg) scale(1); opacity: 1; }
} }
.cycle-stamp.is-visible { animation: cycle-stamp-impact 720ms cubic-bezier(0.5,1.6,0.4,1) forwards; } .cycle-stamp.is-visible { animation: cycle-stamp-impact 700ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards; will-change: transform, opacity; }
/* Cycle col 2 — flash background rouge à l'impact stamp */ /* Screen shake on stamp impact */
@keyframes cycle-shake {
0%, 100% { transform: translate(0,0); }
20% { transform: translate(-3px, 2px); }
40% { transform: translate(4px, -2px); }
60% { transform: translate(-2px, 3px); }
80% { transform: translate(3px, -1px); }
}
.cycle-col-shake.is-visible { animation: cycle-shake 320ms ease-out 480ms 1; }
/* Cycle col 2 — flash background rouge à l'impact stamp (amplifié) */
@keyframes cycle-flash-red { @keyframes cycle-flash-red {
0% { background-color: rgba(239,68,68,0); } 0% { background-color: rgba(239,68,68,0); }
35% { background-color: rgba(239,68,68,0.18); } 30% { background-color: rgba(239,68,68,0.22); }
100% { background-color: rgba(239,68,68,0); } 100% { background-color: rgba(239,68,68,0); }
} }
.cycle-col-flash.is-visible { animation: cycle-flash-red 700ms ease-out 350ms forwards; } .cycle-col-flash.is-visible { animation: cycle-flash-red 700ms ease-out 480ms forwards; }
/* Cycle col 3checkmark draw (stroke-dashoffset) */ /* Cycle col 2sound icon pulse */
.cycle-check-svg path { stroke-dasharray: 24; stroke-dashoffset: 24; transition: stroke-dashoffset 350ms ease-out 200ms; } @keyframes cycle-alert-pulse {
0%, 100% { opacity: 0.7; transform: scale(1); }
50% { opacity: 1; transform: scale(1.2); }
}
.cycle-alert-icon { animation: cycle-alert-pulse 0.9s ease-in-out infinite; }
/* === ROUND 5 — Col 3 — checkmark draw CYAN (au lieu de vert) === */
.cycle-check-svg path { stroke-dasharray: 24; stroke-dashoffset: 24; transition: stroke-dashoffset 400ms ease-out 220ms; stroke: #06b6d4; stroke-width: 3.5; }
.cycle-check-svg.is-visible path { stroke-dashoffset: 0; } .cycle-check-svg.is-visible path { stroke-dashoffset: 0; }
/* Cycle col 3 — badge "Loi 25 conforme" pulse subtil */ /* === ROUND 5 — Col 3 — badge "Loi 25 conforme" pulse BLUE+CYAN (palette brand) === */
@keyframes cycle-badge-pulse { @keyframes cycle-badge-pulse {
0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(34,197,94,0.4); } 0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(37,99,235,0.45); }
50% { transform: scale(1.04); box-shadow: 0 0 0 6px rgba(34,197,94,0); } 50% { transform: scale(1.04); box-shadow: 0 0 0 7px rgba(37,99,235,0); }
} }
.cycle-conforme-badge.is-visible { animation: cycle-badge-pulse 2.4s ease-in-out infinite 600ms; } .cycle-conforme-badge.is-visible { animation: cycle-badge-pulse 2.4s ease-in-out infinite 600ms; }
/* Cycle "Économies annuelles" cards — hover lift + glow */ /* === ROUND 5 — Cycle "Économies annuelles" cards — hover lift + glow BRAND BLUE === */
.cycle-savings-card { .cycle-savings-card {
transition: transform 220ms ease-out, box-shadow 220ms ease-out, border-color 220ms ease-out; transition: transform 240ms cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 240ms ease-out, border-color 240ms ease-out;
} }
.cycle-savings-card:hover { .cycle-savings-card:hover {
transform: translateY(-2px); transform: translateY(-3px);
box-shadow: 0 8px 24px -8px rgba(34,197,94,0.35), 0 4px 12px -4px rgba(11,15,26,0.08); box-shadow: 0 12px 28px -8px rgba(37,99,235,0.30), 0 6px 14px -4px rgba(11,15,26,0.08);
border-color: rgba(34,197,94,0.45); border-color: rgba(37,99,235,0.45);
} }
/* Save chip subtle pulse */
@keyframes cycle-save-chip {
0%, 100% { opacity: 0.85; }
50% { opacity: 1; }
}
.cycle-save-chip { animation: cycle-save-chip 2.5s ease-in-out infinite; }
/* Mobile — désactiver fuites particules + glow heavy */ /* === ROUND 5 — Phase 4 zoom-out subtle (suggère "all options revealed") === */
.cycle-grid-zoom { transition: transform 700ms ease-out; transform: scale(1.02); }
.cycle-grid-zoom.is-revealed { transform: scale(1); }
/* Mobile — désactiver fuites particules + glow heavy + screen shake */
@media (max-width: 768px) { @media (max-width: 768px) {
.cycle-leak-particle { display: none; } .cycle-leak-particle, .cycle-orb, .cycle-orb-2 { display: none; }
.cycle-card-dictia.is-visible { animation: none; } .cycle-card-dictia.is-visible { animation: none; }
.cycle-col-shake.is-visible, .cycle-col-flash.is-visible { animation: none; }
.cycle-ring-draw-svg.is-visible circle { animation: none; }
.cycle-col-card { opacity: 1 !important; transform: none !important; }
} }
/* Reduced motion — TOUT figé */ /* Reduced motion — TOUT figé (mode statique) */
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
.cycle-pulse, .cycle-card-dictia, .cycle-ring-outer, .cycle-ring-inner, .cycle-pulse, .cycle-card-dictia, .cycle-ring-outer, .cycle-ring-inner,
.cycle-clock, .cycle-leak-particle, .cycle-live-dot, .cycle-conforme-badge, .cycle-clock, .cycle-leak-particle, .cycle-live-dot, .cycle-conforme-badge,
.cycle-line.cycle-line-flow, .cycle-stamp, .cycle-col-flash { animation: none !important; } .cycle-line.cycle-line-flow, .cycle-stamp, .cycle-col-flash, .cycle-col-shake,
.cycle-led, .cycle-chev, .cycle-alert-icon, .cycle-orb, .cycle-orb-2,
.cycle-save-chip, .cycle-paper-stack.is-active .cycle-paper,
.cycle-ring-draw-svg.is-visible circle, .cycle-beam-dot { animation: none !important; }
.cycle-paper-stack .cycle-paper { opacity: 1 !important; }
.cycle-reveal, .cycle-reveal-up { opacity: 1 !important; transform: none !important; } .cycle-reveal, .cycle-reveal-up { opacity: 1 !important; transform: none !important; }
.cycle-line { stroke-dashoffset: 0 !important; } .cycle-line { stroke-dashoffset: 0 !important; }
.cycle-check-svg path { stroke-dashoffset: 0 !important; } .cycle-check-svg path { stroke-dashoffset: 0 !important; }
.cycle-savings-card { transition: none !important; } .cycle-savings-card { transition: none !important; }
.cycle-col-card { opacity: 1 !important; transform: none !important; transition: none !important; }
.cycle-beam { width: 100% !important; transition: none !important; }
.cycle-grid-zoom { transform: none !important; transition: none !important; }
} }
</style> </style>
<section <section
class="bg-white py-20 border-y border-brand-border relative overflow-hidden" class="cycle-section-bg bg-white py-20 border-y border-brand-border relative overflow-hidden"
aria-labelledby="cycle-title" aria-labelledby="cycle-title"
x-data="{ x-data="{
phase: 0, phase: 0,
@@ -544,24 +683,32 @@
}; };
requestAnimationFrame(tick); requestAnimationFrame(tick);
}, },
fmt(n) { return n.toLocaleString('fr-CA').replace(//g, ' '); } fmt(n) { return n.toLocaleString('fr-CA').replace(//g, ' '); },
/* Round 5 — beam progressive % par phase */
get beamPct() {
if (this.phase >= 4) return 100;
if (this.phase >= 3) return 66;
if (this.phase >= 2) return 33;
return 0;
}
}" }"
x-init=" x-init="
observer = new IntersectionObserver((entries) => { observer = new IntersectionObserver((entries) => {
entries.forEach(e => { entries.forEach(e => {
if (e.isIntersecting && phase === 0) { if (e.isIntersecting && phase === 0) {
setTimeout(() => { phase = 1; }, 250); /* Round 5 — phase delays cinématiques 400/1100/2000/3100ms */
setTimeout(() => { phase = 1; }, 400);
setTimeout(() => { phase = 2; countTo('priceHumain', 315, 1400); }, 1100); setTimeout(() => { phase = 2; countTo('priceHumain', 315, 1400); }, 1100);
setTimeout(() => phase = 3, 2200); setTimeout(() => phase = 3, 2000);
setTimeout(() => { setTimeout(() => {
phase = 4; phase = 4;
/* Savings counters fire 600ms after col 3 reveal (round 4) */ /* Savings counters fire 700ms after col 3 reveal (round 5) */
setTimeout(() => { setTimeout(() => {
countTo('sav1', 3924, 1500); countTo('sav1', 3924, 1500);
countTo('sav2', 6924, 1500); countTo('sav2', 6924, 1500);
countTo('sav3', 2004, 1500); countTo('sav3', 2004, 1500);
}, 700); }, 700);
}, 3000); }, 3100);
observer.disconnect(); observer.disconnect();
} }
}); });
@@ -569,10 +716,17 @@
observer.observe($el); observer.observe($el);
" "
> >
{# Subtle dot-grid bg #} {# Round 5 — Subtle grid pattern bg + dot grid overlay #}
<div class="absolute inset-0 pointer-events-none" aria-hidden="true" <div class="cycle-grid-bg absolute inset-0 pointer-events-none" aria-hidden="true"></div>
<div class="absolute inset-0 pointer-events-none opacity-50" aria-hidden="true"
style="background-image: radial-gradient(circle, rgba(11,15,26,0.04) 1px, transparent 1px); background-size: 28px 28px;"></div> style="background-image: radial-gradient(circle, rgba(11,15,26,0.04) 1px, transparent 1px); background-size: 28px 28px;"></div>
{# Round 5 — Decorative orbs ambiance #}
<div class="cycle-orb absolute -top-20 -left-20 w-[360px] h-[360px] rounded-full pointer-events-none" aria-hidden="true"
style="background: radial-gradient(circle, rgba(37,99,235,0.10) 0%, transparent 65%); filter: blur(40px);"></div>
<div class="cycle-orb cycle-orb-2 absolute -bottom-24 -right-24 w-[420px] h-[420px] rounded-full pointer-events-none" aria-hidden="true"
style="background: radial-gradient(circle, rgba(6,182,212,0.08) 0%, transparent 65%); filter: blur(50px);"></div>
<div class="relative max-w-[1200px] mx-auto px-6"> <div class="relative max-w-[1200px] mx-auto px-6">
<div class="max-w-2xl mb-10"> <div class="max-w-2xl mb-10">
<p class="eyebrow text-amber-600 mb-4 inline-flex items-center gap-1.5"> <p class="eyebrow text-amber-600 mb-4 inline-flex items-center gap-1.5">
@@ -609,7 +763,7 @@
</div> </div>
</div> </div>
{# Lignes de connexion SVG — de la source vers les 3 colonnes (round 4 : dash flow continu) #} {# Lignes de connexion SVG — de la source vers les 3 colonnes #}
<div class="relative h-10"> <div class="relative h-10">
<svg class="w-full h-full" viewBox="0 0 100 10" preserveAspectRatio="none" aria-hidden="true"> <svg class="w-full h-full" viewBox="0 0 100 10" preserveAspectRatio="none" aria-hidden="true">
<line class="cycle-line cycle-line-flow" :class="phase >= 1 ? 'is-visible' : ''" <line class="cycle-line cycle-line-flow" :class="phase >= 1 ? 'is-visible' : ''"
@@ -621,27 +775,43 @@
style="transition-delay: 80ms; animation-delay: 0.4s;" /> style="transition-delay: 80ms; animation-delay: 0.4s;" />
<line class="cycle-line cycle-line-flow" :class="phase >= 1 ? 'is-visible' : ''" <line class="cycle-line cycle-line-flow" :class="phase >= 1 ? 'is-visible' : ''"
x1="50" y1="0" x2="86" y2="10" x1="50" y1="0" x2="86" y2="10"
stroke="rgba(34,197,94,0.6)" stroke-width="0.3" stroke="rgba(6,182,212,0.7)" stroke-width="0.3"
style="transition-delay: 160ms; animation-delay: 0.8s;" /> style="transition-delay: 160ms; animation-delay: 0.8s;" />
</svg> </svg>
</div> </div>
{# Grille 3 colonnes — équivalence du grid-cols-[2fr_2fr_3fr] desktop #} {# Round 5 — Connecting horizontal beam progressive 0->33->66->100 #}
<div class="grid grid-cols-1 md:grid-cols-[2fr_2fr_3fr] gap-3 items-stretch"> <div class="relative h-3 mb-4" aria-hidden="true">
<div class="absolute inset-x-0 top-1/2 -translate-y-1/2 h-[2px] bg-brand-border/60"></div>
<div class="cycle-beam absolute top-1/2 left-0 -translate-y-1/2 rounded-full"
:style="`--beam: ${beamPct}%`"></div>
<template x-if="phase >= 1">
<div class="cycle-beam-dot absolute"></div>
</template>
</div>
{# COL 1 — Retranscription humaine #} {# Grille 3 colonnes — équivalence du grid-cols-[2fr_2fr_3fr] desktop, avec spotlight active #}
<div class="cycle-reveal-up flex flex-col rounded border border-brand-border bg-brand-bg overflow-hidden" <div class="cycle-grid-zoom grid grid-cols-1 md:grid-cols-[2fr_2fr_3fr] gap-3 items-stretch"
:class="phase >= 2 ? 'is-visible' : ''"> :class="phase >= 4 ? 'is-revealed' : ''">
<div class="px-5 py-3 border-b border-brand-border">
{# COL 1 — Retranscription humaine (sténographe) #}
<div class="cycle-col-card cycle-reveal-up flex flex-col rounded border border-brand-border bg-brand-bg overflow-hidden relative"
:class="{ 'is-visible': phase >= 2, 'is-revealed': phase >= 4, 'is-active': phase === 2 }">
{# Subtle "cahier" lines bg #}
<div class="absolute inset-0 pointer-events-none opacity-[0.04]" aria-hidden="true"
style="background-image: linear-gradient(rgba(11,15,26,1) 1px, transparent 1px); background-size: 100% 18px;"></div>
<div class="relative px-5 py-3 border-b border-brand-border">
<div class="font-mono text-[10px] tracking-[0.28em] uppercase text-brand-navy/40 mb-0.5">01</div> <div class="font-mono text-[10px] tracking-[0.28em] uppercase text-brand-navy/40 mb-0.5">01</div>
<div class="font-bold text-sm text-brand-navy/55">Retranscription humaine</div> <div class="font-bold text-sm text-brand-navy/55">Retranscription humaine</div>
</div> </div>
<div class="flex-1 flex flex-col items-center justify-center px-5 py-7 gap-6"> <div class="relative flex-1 flex flex-col items-center justify-center px-5 py-7 gap-6">
{# Stack de papiers #} {# Stack de papiers (round 5 : stagger reveal stagger 180ms) #}
<div class="relative w-[100px] h-[90px]" aria-hidden="true"> <div class="cycle-paper-stack relative w-[100px] h-[90px]"
:class="phase >= 2 ? 'is-active' : ''"
aria-hidden="true">
{% for offset in [0,1,2,3,4] %} {% for offset in [0,1,2,3,4] %}
<div class="absolute left-0 right-0 h-[17px] rounded-sm flex items-center px-2 gap-1.5 bg-white border border-brand-border" <div class="cycle-paper absolute left-0 right-0 h-[17px] rounded-sm flex items-center px-2 gap-1.5 bg-white border border-brand-border shadow-sm"
style="bottom: {{ offset * 15 }}px; transform: rotate({{ '1deg' if offset is even else '-1deg' }});"> style="bottom: {{ offset * 15 }}px; --rot: {{ '1deg' if offset is even else '-1deg' }}; transform: rotate({{ '1deg' if offset is even else '-1deg' }}); animation-delay: {{ offset * 180 }}ms;">
<div class="w-2.5 h-1.5 rounded-sm bg-brand-navy/15 shrink-0"></div> <div class="w-2.5 h-1.5 rounded-sm bg-brand-navy/15 shrink-0"></div>
<div class="flex-1 h-[1.5px] rounded-full bg-brand-navy/10"></div> <div class="flex-1 h-[1.5px] rounded-full bg-brand-navy/10"></div>
</div> </div>
@@ -661,7 +831,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="px-5 pb-5 pt-4 border-t border-brand-border"> <div class="relative px-5 pb-5 pt-4 border-t border-brand-border">
<div class="flex items-baseline gap-1.5 mb-2"> <div class="flex items-baseline gap-1.5 mb-2">
<span class="font-black text-3xl leading-none text-brand-navy/65 tabular-nums" x-text="priceHumain">315</span> <span class="font-black text-3xl leading-none text-brand-navy/65 tabular-nums" x-text="priceHumain">315</span>
<span class="text-xs text-brand-navy/45">$&nbsp;/&nbsp;réunion</span> <span class="text-xs text-brand-navy/45">$&nbsp;/&nbsp;réunion</span>
@@ -673,41 +843,72 @@
</div> </div>
</div> </div>
{# COL 2 — IA cloud américaine #} {# COL 2 — IA cloud américaine (DRAMATIC : USA map + 12 paquets + screen shake) #}
<div class="cycle-reveal-up cycle-col-flash relative flex flex-col rounded border border-red-200 bg-red-50/30 overflow-hidden" <div class="cycle-col-card cycle-reveal-up cycle-col-flash cycle-col-shake relative flex flex-col rounded border border-red-200 bg-red-50/30 overflow-hidden"
:class="phase >= 2 ? 'is-visible' : ''" :class="{ 'is-visible': phase >= 3, 'is-revealed': phase >= 4, 'is-active': phase === 3 }"
style="transition-delay: 120ms;"> style="transition-delay: 120ms;">
{# Overlay légal NON CONFORME (phase 3) — round 4 : STAMP huissier qui claque #} {# Round 5 — USA map silhouette subtle background #}
<svg class="absolute pointer-events-none" aria-hidden="true"
style="top: 22%; right: 8%; width: 110px; height: 70px; opacity: 0.55;"
viewBox="0 0 110 70" preserveAspectRatio="xMidYMid meet">
<path d="M5,25 L8,18 L18,15 L32,12 L48,10 L65,11 L82,14 L92,18 L102,22 L105,28 L100,35 L95,42 L88,48 L78,52 L68,55 L58,57 L48,58 L38,57 L28,55 L18,52 L10,45 L6,38 Z"
fill="rgba(239,68,68,0.05)" stroke="rgba(239,68,68,0.20)" stroke-width="0.8"/>
<circle cx="78" cy="32" r="2.2" fill="rgba(239,68,68,0.55)"/>
<circle cx="78" cy="32" r="4.5" fill="none" stroke="rgba(239,68,68,0.35)" stroke-width="0.6"/>
</svg>
{# Overlay légal NON CONFORME (phase 3) — STAMP huissier amplifié round 5 #}
<div class="absolute inset-0 z-30 flex flex-col items-center justify-center pointer-events-none" <div class="absolute inset-0 z-30 flex flex-col items-center justify-center pointer-events-none"
:class="phase >= 3 ? 'opacity-100' : 'opacity-0'" :class="phase >= 3 ? 'opacity-100' : 'opacity-0'"
style="transition: opacity 220ms ease-out; backdrop-filter: blur(6px); background: rgba(255,255,255,0.78);"> style="transition: opacity 220ms ease-out; backdrop-filter: blur(6px); background: rgba(255,255,255,0.78);">
<div class="cycle-stamp absolute top-1/2 left-1/2 flex flex-col items-center gap-3 px-6 py-5 rounded bg-white border-[3px] border-red-500 shadow-[0_8px_30px_-6px_rgba(239,68,68,0.55)]" <div class="cycle-stamp absolute top-1/2 left-1/2 flex flex-col items-center gap-3 px-7 py-6 rounded bg-white border-[3px] border-red-500 shadow-[0_12px_40px_-6px_rgba(239,68,68,0.65)]"
:class="phase >= 3 ? 'is-visible' : ''" :class="phase >= 3 ? 'is-visible' : ''"
style="transform: translate(-50%,-50%) scale(0); opacity: 0;"> style="transform: translate(-50%,-50%) scale(0); opacity: 0;">
<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="w-7 h-7 text-red-500" 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="flex items-center gap-2.5">
<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="w-8 h-8 text-red-500" 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>
<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="cycle-alert-icon w-5 h-5 text-red-500" aria-hidden="true"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><line x1="23" y1="9" x2="17" y2="15"/><line x1="17" y1="9" x2="23" y2="15"/></svg>
</div>
<div class="text-center"> <div class="text-center">
<div class="font-mono font-bold tracking-[0.14em] text-sm uppercase text-red-600">NON CONFORME</div> <div class="font-mono font-black tracking-[0.16em] text-2xl uppercase text-red-600 leading-none">NON CONFORME</div>
<div class="font-mono text-[10px] tracking-[0.20em] uppercase mt-1.5 text-red-500/70">Loi&nbsp;25 · Cloud Act américain</div> <div class="font-mono text-[10px] tracking-[0.20em] uppercase mt-2 text-red-500/70">Loi&nbsp;25 · Cloud Act américain</div>
</div> </div>
</div> </div>
</div> </div>
<div class="px-5 py-3 border-b border-red-100"> <div class="relative px-5 py-3 border-b border-red-100">
<div class="font-mono text-[10px] tracking-[0.28em] uppercase text-red-500/60 mb-0.5">02</div> <div class="font-mono text-[10px] tracking-[0.28em] uppercase text-red-500/60 mb-0.5">02</div>
<div class="font-bold text-sm text-red-500/75">IA cloud américaine</div> <div class="font-bold text-sm text-red-500/75">IA cloud américaine</div>
</div> </div>
<div class="relative flex-1 flex flex-col items-center justify-center px-5 py-6 gap-5"> <div class="relative flex-1 flex flex-col items-center justify-center px-5 py-6 gap-5">
{# Server rack icon (round 5) — 3 stacked rectangles avec leds rouges #}
<div class="relative flex flex-col items-center gap-2"> <div class="relative flex flex-col items-center gap-2">
<div class="relative w-14 h-14 rounded flex items-center justify-center bg-red-100/60 border border-red-200" aria-hidden="true"> <div class="relative w-16 h-14 rounded-sm flex flex-col items-center justify-center gap-[3px] bg-red-100/60 border border-red-200 px-2 py-1.5" aria-hidden="true">
<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="w-6 h-6 text-red-500/70"><path d="M2 12s3-7 10-7c2.5 0 4.7.9 6.4 2.4M22 12s-3 7-10 7c-2.5 0-4.7-.9-6.4-2.4"/><line x1="2" y1="2" x2="22" y2="22"/></svg> {% for rack_i in [0,1,2] %}
{# Particules de fuite (round 4 : 10 particules, plus dense) #} <div class="w-full h-2.5 rounded-[2px] bg-red-50/80 border border-red-200/70 flex items-center px-1 gap-1">
{% for i in range(10) %} <span class="cycle-led{% if rack_i > 0 %} cycle-led-{{ rack_i + 1 }}{% endif %} w-1 h-1 rounded-full bg-red-500"></span>
<span class="cycle-leak-particle absolute w-[3px] h-[3px] rounded-full bg-red-400 pointer-events-none" <span class="cycle-led cycle-led-{{ ((rack_i + 1) % 3) + 1 }} w-1 h-1 rounded-full bg-red-500"></span>
style="left: 50%; top: 50%; --lx: {{ (-32 + i*8) }}px; --ly: -{{ 12 + (i % 4) * 7 }}px; animation-delay: {{ i * 0.16 }}s; box-shadow: 0 0 4px rgba(239,68,68,0.55);"></span> <span class="flex-1 h-[1px] rounded-full bg-red-300/60"></span>
<span class="cycle-led cycle-led-{{ ((rack_i + 2) % 3) + 1 }} w-1 h-1 rounded-full bg-red-500"></span>
</div>
{% endfor %}
{# Round 5 — 12 paquets data .wav/.aac qui s'envolent vers TOP-RIGHT (USA direction) #}
{% for i in range(12) %}
<span class="cycle-leak-particle absolute pointer-events-none flex items-center justify-center font-mono font-bold uppercase text-white text-[6px] rounded-sm"
style="left: {{ 25 + (i % 4) * 12 }}%; top: {{ 30 + (i % 3) * 18 }}%;
width: 18px; height: 9px;
background: rgba(239,68,68,0.65); border: 1px solid rgba(239,68,68,0.85);
box-shadow: 0 0 4px rgba(239,68,68,0.55);
--lx: {{ 50 + i*6 }}px; --ly: -{{ 70 + (i % 4) * 15 }}px;
--rot: {{ -8 + (i % 5) * 4 }}deg;
animation-delay: {{ i * 0.18 }}s;">{{ '.wav' if i is even else '.aac' }}</span>
{% endfor %} {% endfor %}
</div> </div>
<div class="px-2 py-0.5 rounded bg-red-50 border border-red-100"> <div class="px-2 py-0.5 rounded bg-red-50 border border-red-100 inline-flex items-center gap-1">
<span class="cycle-chev font-mono font-bold text-[8px] text-red-500/70">&lt;</span>
<span class="cycle-chev cycle-chev-2 font-mono font-bold text-[8px] text-red-500/70">&lt;</span>
<span class="cycle-chev cycle-chev-3 font-mono font-bold text-[8px] text-red-500/70">&lt;</span>
<span class="font-mono text-[9px] tracking-[0.22em] uppercase text-red-500/65">USA</span> <span class="font-mono text-[9px] tracking-[0.22em] uppercase text-red-500/65">USA</span>
</div> </div>
</div> </div>
@@ -732,7 +933,7 @@
</div> </div>
</div> </div>
<div class="px-5 pb-5 pt-4 border-t border-red-100"> <div class="relative px-5 pb-5 pt-4 border-t border-red-100">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="w-1.5 h-1.5 rounded-full bg-red-400"></div> <div class="w-1.5 h-1.5 rounded-full bg-red-400"></div>
<span class="font-mono text-[9px] tracking-[0.20em] uppercase text-red-500/70">Violation légale possible</span> <span class="font-mono text-[9px] tracking-[0.20em] uppercase text-red-500/70">Violation légale possible</span>
@@ -740,93 +941,127 @@
</div> </div>
</div> </div>
{# COL 3 — DictIA (featured, 3fr) #} {# COL 3 — DictIA (featured, 3fr) — PALETTE BRAND BLUE+CYAN+FUCHSIA #}
<div class="cycle-card-dictia cycle-reveal-up relative flex flex-col rounded border border-brand-b1/35 bg-gradient-to-br from-brand-b1/[0.06] to-brand-b3/[0.04] overflow-hidden" <div class="cycle-col-card cycle-card-dictia cycle-reveal-up relative flex flex-col rounded border border-brand-b1/40 bg-gradient-to-br from-brand-b1/[0.07] via-brand-b2/[0.04] to-brand-b3/[0.04] overflow-hidden"
:class="phase >= 4 ? 'is-visible' : ''" :class="{ 'is-visible': phase >= 4, 'is-revealed': phase >= 4, 'is-active': phase >= 4 }"
style="transition-delay: 240ms;"> style="transition-delay: 240ms;">
{# Halo ambiant #} {# Halo ambiant blue->cyan->fuchsia #}
<div class="absolute inset-0 pointer-events-none" aria-hidden="true" <div class="absolute inset-0 pointer-events-none" aria-hidden="true"
style="background: radial-gradient(ellipse 80% 35% at 50% 0%, rgba(6,182,212,0.12) 0%, transparent 65%);"></div> style="background: radial-gradient(ellipse 80% 35% at 50% 0%, rgba(6,182,212,0.18) 0%, transparent 65%), radial-gradient(ellipse 60% 50% at 50% 100%, rgba(37,99,235,0.10) 0%, transparent 70%);"></div>
<div class="relative px-5 py-3 border-b border-brand-b1/15 flex items-center gap-2.5"> {# Round 5 — Quebec province outline subtle background #}
{# Numéro 03 → checkmark vert (round 4) #} <svg class="absolute pointer-events-none" aria-hidden="true"
<span class="relative w-5 h-5 rounded-full flex items-center justify-center shrink-0 bg-emerald-500/15 border border-emerald-500/45" aria-hidden="true"> style="top: 18%; right: 6%; width: 95px; height: 95px; opacity: 0.6;"
<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="cycle-check-svg w-3 h-3 text-emerald-600" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet">
<path d="M22,10 L35,8 L48,9 L62,11 L74,15 L82,22 L86,32 L88,45 L85,58 L80,68 L72,76 L62,82 L52,85 L42,84 L32,80 L24,72 L18,62 L15,50 L14,38 L17,26 Z"
fill="rgba(37,99,235,0.06)" stroke="rgba(37,99,235,0.28)" stroke-width="1"/>
<circle cx="48" cy="62" r="2.2" fill="rgba(6,182,212,0.85)"/>
<circle cx="48" cy="62" r="5" fill="none" stroke="rgba(6,182,212,0.45)" stroke-width="0.8"/>
<text x="40" y="71" font-family="Inter, sans-serif" font-size="7" fill="rgba(192,38,211,0.7)" font-weight="bold">QC</text>
</svg>
<div class="relative px-5 py-3 border-b border-brand-b1/20 flex items-center gap-2.5">
{# Round 5 — mini logo DictIA (subtle) connecte le brand visuellement #}
<img src="{{ url_for('static', filename='images/dictia-logo.png') }}"
alt="" aria-hidden="true"
class="w-7 h-7 rounded shrink-0 opacity-95"
width="28" height="28" loading="lazy">
{# Numéro 03 → checkmark CYAN (round 5 : palette brand) #}
<span class="relative w-5 h-5 rounded-full flex items-center justify-center shrink-0 bg-brand-b2/20 border border-brand-b2/50" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" class="cycle-check-svg w-3 h-3"
:class="phase >= 4 ? 'is-visible' : ''"><path d="M5 13l4 4L19 7"/></svg> :class="phase >= 4 ? 'is-visible' : ''"><path d="M5 13l4 4L19 7"/></svg>
</span> </span>
<span class="text-[11px] uppercase tracking-[0.22em] font-semibold text-brand-b1/80">Solution</span> <span class="text-[11px] uppercase tracking-[0.22em] font-semibold text-brand-b1/85">Solution</span>
{# Badge top-right : Loi 25 conforme (round 4) #} {# Badge top-right : Loi 25 conforme round 5 : gradient brand blue->fuchsia #}
<span class="cycle-conforme-badge ml-auto inline-flex items-center gap-1 rounded-full px-2 py-0.5 bg-emerald-500/12 border border-emerald-500/40" <span class="cycle-conforme-badge ml-auto inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 border border-brand-b2/50"
:class="phase >= 4 ? 'is-visible' : ''" aria-label="Loi 25 conforme"> :class="phase >= 4 ? 'is-visible' : ''" aria-label="Loi 25 conforme"
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="w-2.5 h-2.5 text-emerald-600" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg> style="background: linear-gradient(135deg, rgba(37,99,235,0.22), rgba(192,38,211,0.18));">
<span class="font-mono font-bold text-[8px] tracking-[0.16em] uppercase text-emerald-700">Loi&nbsp;25 conforme</span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="w-2.5 h-2.5 text-white" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/></svg>
<span class="font-mono font-bold text-[8px] tracking-[0.16em] uppercase text-white">Loi&nbsp;25 conforme</span>
</span> </span>
</div> </div>
<div class="relative flex-1 flex flex-col items-center justify-center px-5 py-7 gap-5"> <div class="relative flex-1 flex flex-col items-center justify-center px-5 py-7 gap-5">
{# Lock + anneaux concentriques #} {# Shield + microphone (round 5) + halo multi-couches blue+cyan + drawn ring SVG #}
<div class="relative flex items-center justify-center" aria-hidden="true"> <div class="relative flex items-center justify-center" aria-hidden="true">
<span class="cycle-ring-outer absolute rounded-full border border-brand-b1/15" {# Couche externe drawn ring SVG (fuchsia accent) #}
<svg class="cycle-ring-draw-svg absolute" :class="phase >= 4 ? 'is-visible' : ''"
width="108" height="108" viewBox="0 0 80 80">
<circle cx="40" cy="40" r="35" fill="none" stroke="rgba(192,38,211,0.32)" stroke-width="1" stroke-linecap="round"/>
</svg>
<span class="cycle-ring-outer absolute rounded-full border border-brand-b1/25"
:class="phase >= 4 ? 'is-visible' : ''" :class="phase >= 4 ? 'is-visible' : ''"
style="width: 96px; height: 96px;"></span> style="width: 96px; height: 96px;"></span>
<span class="cycle-ring-inner absolute rounded-full border border-brand-b1/25" <span class="cycle-ring-inner absolute rounded-full border border-brand-b2/40"
:class="phase >= 4 ? 'is-visible' : ''" :class="phase >= 4 ? 'is-visible' : ''"
style="width: 68px; height: 68px;"></span> style="width: 68px; height: 68px;"></span>
<div class="relative w-[52px] h-[52px] rounded flex items-center justify-center bg-gradient-to-br from-brand-b1/15 to-brand-b3/10 border border-brand-b1/35"> <div class="relative w-[56px] h-[56px] rounded flex items-center justify-center bg-gradient-to-br from-brand-b1/20 via-brand-b2/15 to-brand-b3/10 border border-brand-b2/45"
<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="w-6 h-6 text-brand-b1"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg> style="box-shadow: 0 0 24px rgba(37,99,235,0.35), 0 0 48px rgba(6,182,212,0.18);">
{# Shield extérieur #}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" class="w-7 h-7 text-brand-b1">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
{# Microphone à l'intérieur #}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5 text-brand-b2 absolute"
style="top: 50%; left: 50%; transform: translate(-50%, -45%);">
<rect x="9" y="6" width="6" height="9" rx="3"/>
<path d="M12 17v3"/>
<path d="M9 20h6"/>
</svg>
</div> </div>
</div> </div>
{# Flux sécurisé #} {# Flux sécurisé (palette brand b1+b2) #}
<div class="cycle-reveal flex items-center gap-2 px-3.5 py-1.5 rounded bg-brand-b1/5 border border-brand-b1/15" <div class="cycle-reveal flex items-center gap-2 px-3.5 py-1.5 rounded bg-brand-b1/10 border border-brand-b2/25"
:class="phase >= 4 ? 'is-visible' : ''" :class="phase >= 4 ? 'is-visible' : ''"
style="transition-delay: 350ms;"> style="transition-delay: 350ms;">
<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 h-3 shrink-0 text-brand-b1/55" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/></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 h-3 shrink-0 text-brand-b1/65" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/></svg>
<span class="text-[11px] text-brand-b1/70">Transcription sécurisée</span> <span class="text-[11px] text-brand-b1/80 font-medium">Transcription sécurisée</span>
<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 h-3 text-brand-b1/45" aria-hidden="true"><path d="M5 12h14M13 5l7 7-7 7"/></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 h-3 text-brand-b2" aria-hidden="true"><path d="M5 12h14M13 5l7 7-7 7"/></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 h-3 shrink-0 text-brand-b1/55" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></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 h-3 shrink-0 text-brand-b1/65" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
</div> </div>
{# Badges conformité #} {# Badges conformité (palette brand b1+b2 cyan checkmark) #}
<div class="flex flex-col gap-2 w-full"> <div class="flex flex-col gap-2 w-full">
{% for badge_label in ['Loi 25 conforme', '100&nbsp;% hébergé au Québec', 'Données jamais partagées'] %} {% for badge_label in ['Loi 25 conforme', '100&nbsp;% hébergé au Québec', 'Données jamais partagées'] %}
<div class="cycle-reveal flex items-center gap-2.5 px-3.5 py-2.5 rounded bg-brand-b1/[0.06] border border-brand-b1/20" <div class="cycle-reveal flex items-center gap-2.5 px-3.5 py-2.5 rounded bg-brand-b1/[0.08] border border-brand-b2/25"
:class="phase >= 4 ? 'is-visible' : ''" :class="phase >= 4 ? 'is-visible' : ''"
style="transition-delay: {{ 180 + loop.index0 * 170 }}ms;"> style="transition-delay: {{ 180 + loop.index0 * 170 }}ms;">
<span class="w-4 h-4 rounded-full flex items-center justify-center shrink-0 bg-brand-b1/15 border border-brand-b1/30"> <span class="w-4 h-4 rounded-full flex items-center justify-center shrink-0 bg-brand-b2/20 border border-brand-b2/45">
<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" 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-b2" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>
</span> </span>
<span class="text-[12px] font-medium text-brand-navy/75">{{ badge_label | safe }}</span> <span class="text-[12px] font-medium text-brand-navy/80">{{ badge_label | safe }}</span>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div class="relative px-5 pb-5 pt-4 border-t border-brand-b1/15"> <div class="relative px-5 pb-5 pt-4 border-t border-brand-b2/20">
<div class="flex items-center gap-2 mb-2.5"> <div class="flex items-center gap-2 mb-2.5">
<span class="flex-1 h-px bg-brand-b1/15"></span> <span class="flex-1 h-px bg-gradient-to-r from-transparent via-brand-b1/30 to-brand-b2/30"></span>
<span class="font-mono font-bold text-[10px] uppercase tracking-[0.20em] text-brand-b1">UTILISATEURS ILLIMITÉS</span> <span class="font-mono font-bold text-[10px] uppercase tracking-[0.20em] grad-text">UTILISATEURS ILLIMITÉS</span>
<span class="flex-1 h-px bg-brand-b1/15"></span> <span class="flex-1 h-px bg-gradient-to-l from-transparent via-brand-b3/30 to-brand-b2/30"></span>
</div> </div>
<p class="text-center text-[10px] mb-3.5 text-brand-b1/55">Zéro frais caché · Du jamais vu</p> <p class="text-center text-[10px] mb-3.5 text-brand-b1/65">Zéro frais caché · Du jamais vu</p>
<div class="flex items-baseline gap-2"> <div class="flex items-baseline gap-2">
<span class="font-black leading-none text-5xl text-brand-b1">173</span> {# Round 5 — big number en grad-text (blue->cyan->fuchsia) #}
<span class="text-sm text-brand-navy/45 mb-0.5">$ / mois</span> <span class="font-black leading-none text-5xl grad-text">173</span>
<span class="text-sm text-brand-navy/55 mb-0.5 font-semibold">$ / mois</span>
</div> </div>
<div class="flex items-center gap-1.5 mt-2"> <div class="flex items-center gap-1.5 mt-2">
<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 h-3 text-brand-b1/65" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></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 h-3 text-brand-b2" aria-hidden="true"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
<p class="text-[10px] text-brand-b1/60">Conforme Loi&nbsp;25 · 100&nbsp;% Québec</p> <p class="text-[10px] text-brand-b1/70 font-medium">Conforme Loi&nbsp;25 · 100&nbsp;% Québec</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{# Section "Économies annuelles · 25 utilisateurs" — round 4 : 3 cards avec counter animation #} {# Section "Économies annuelles · 25 utilisateurs" — round 5 : 3 cards palette brand + chips contextuels #}
<div class="cycle-reveal-up mt-12" <div class="cycle-reveal-up mt-12"
:class="phase >= 4 ? 'is-visible' : ''" :class="phase >= 4 ? 'is-visible' : ''"
style="transition-delay: 700ms;"> style="transition-delay: 700ms;">
<div class="flex items-center justify-center gap-2.5 mb-5"> <div class="flex items-center justify-center gap-2.5 mb-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 text-emerald-500" aria-hidden="true"><polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/><polyline points="17 18 23 18 23 12"/></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 text-brand-b1" aria-hidden="true"><polyline points="23 18 13.5 8.5 8.5 13.5 1 6"/><polyline points="17 18 23 18 23 12"/></svg>
<span class="font-mono font-bold text-[10px] uppercase tracking-[0.22em] text-brand-navy/65"> <span class="font-mono font-bold text-[10px] uppercase tracking-[0.22em] text-brand-navy/65">
Économies annuelles · 25&nbsp;utilisateurs Économies annuelles · 25&nbsp;utilisateurs
</span> </span>
@@ -835,28 +1070,61 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-3" role="list" aria-label="Trois comparaisons d'économies annuelles"> <div class="grid grid-cols-1 md:grid-cols-3 gap-3" role="list" aria-label="Trois comparaisons d'économies annuelles">
{% for sav in [ {% for sav in [
{'icon': 'otter', 'val_prop': 'sav1', 'val_static': '3&nbsp;924', 'label': 'vs Otter.ai', 'sub': 'IA cloud US'}, {'icon': 'otter', 'val_prop': 'sav1', 'val_static': '3&nbsp;924', 'label': 'vs Otter.ai', 'sub': 'IA cloud US', 'chip': 'IA cloud US'},
{'icon': 'teams', 'val_prop': 'sav2', 'val_static': '6&nbsp;924', 'label': 'vs MS Teams', 'sub': 'Copilot premium'}, {'icon': 'teams', 'val_prop': 'sav2', 'val_static': '6&nbsp;924', 'label': 'vs MS Teams', 'sub': 'Copilot premium', 'chip': 'Copilot premium'},
{'icon': 'scribe','val_prop': 'sav3', 'val_static': '2&nbsp;004', 'label': 'vs Sténographe','sub': 'Service humain'} {'icon': 'scribe','val_prop': 'sav3', 'val_static': '2&nbsp;004', 'label': 'vs Sténographe','sub': 'Service humain', 'chip': 'Service humain'}
] %} ] %}
<div class="cycle-savings-card flex items-center gap-3 px-4 py-4 rounded border border-brand-border bg-white" role="listitem"> <div class="cycle-savings-card flex items-center gap-3 px-4 py-4 rounded border border-brand-border bg-white relative overflow-hidden" role="listitem">
<span class="shrink-0 w-10 h-10 rounded flex items-center justify-center bg-emerald-50 border border-emerald-100 text-emerald-600" aria-hidden="true"> {# Round 5 — subtle blue tint bg layer #}
<div class="absolute inset-0 pointer-events-none opacity-60" aria-hidden="true"
style="background: linear-gradient(135deg, rgba(37,99,235,0.04) 0%, transparent 60%);"></div>
<span class="relative shrink-0 w-10 h-10 rounded flex items-center justify-center bg-brand-b1/10 border border-brand-b2/30 text-brand-b1" aria-hidden="true">
{% if sav.icon == 'otter' %} {% if sav.icon == 'otter' %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5"><path d="M2 12s3-7 10-7c2.5 0 4.7.9 6.4 2.4M22 12s-3 7-10 7c-2.5 0-4.7-.9-6.4-2.4"/><circle cx="12" cy="12" r="3"/></svg> {# Round 5 — silhouette de loutre stylisée (tête + oreilles + moustache) #}
<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="w-5 h-5">
<path d="M5 8 C5 5, 7 3, 8 3 C8.5 4, 9 5, 8.5 6"/>
<path d="M19 8 C19 5, 17 3, 16 3 C15.5 4, 15 5, 15.5 6"/>
<ellipse cx="12" cy="13" rx="6" ry="6.5"/>
<circle cx="9.5" cy="11.5" r="0.8" fill="currentColor"/>
<circle cx="14.5" cy="11.5" r="0.8" fill="currentColor"/>
<path d="M11 15 Q12 16 13 15"/>
<path d="M9 16 L7.5 16.5 M15 16 L16.5 16.5"/>
</svg>
{% elif sav.icon == 'teams' %} {% elif sav.icon == 'teams' %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg> {# Round 5 — carré avec "T" stylisé Teams #}
<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="w-5 h-5">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M8 8h8"/>
<path d="M12 8v9"/>
</svg>
{% else %} {% else %}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="w-5 h-5"><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="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg> {# Round 5 — silhouette humain (sténographe) avec doc #}
<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="w-5 h-5">
<circle cx="9" cy="6" r="3"/>
<path d="M3 21v-1.5C3 17 5.7 15 9 15s6 2 6 4.5V21"/>
<rect x="15.5" y="11" width="6" height="8" rx="0.8"/>
<line x1="17" y1="13.5" x2="20" y2="13.5"/>
<line x1="17" y1="15.5" x2="20" y2="15.5"/>
</svg>
{% endif %} {% endif %}
</span> </span>
<div class="flex-1 min-w-0"> <div class="relative flex-1 min-w-0">
{# Round 5 — save chip "+économies" au-dessus du big number #}
<span class="cycle-save-chip inline-flex items-center gap-1 rounded-full px-1.5 py-px mb-1 bg-brand-b1/10 border border-brand-b1/25">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" class="w-2 h-2 text-brand-b1" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
<span class="font-mono font-bold text-[7px] tracking-[0.16em] uppercase text-brand-b1">+économies</span>
</span>
<div class="flex items-baseline"> <div class="flex items-baseline">
{# Round 5 — big number en grad-text (blue->cyan->fuchsia) #}
{# OQLF NBSP entre nombre et $ — préservé en placeholder statique pour SEO/no-JS, JS écrase via x-html #} {# OQLF NBSP entre nombre et $ — préservé en placeholder statique pour SEO/no-JS, JS écrase via x-html #}
<span class="font-black text-2xl leading-none text-emerald-600 tabular-nums" <span class="font-black text-2xl leading-none grad-text tabular-nums"
x-html="fmt({{ sav.val_prop }}) + '&nbsp;<span class=&quot;text-sm text-emerald-600/70 font-bold&quot;>$</span>'">{{ sav.val_static | safe }}&nbsp;$</span> x-html="fmt({{ sav.val_prop }}) + '&nbsp;<span class=&quot;text-sm font-bold&quot;>$</span>'">{{ sav.val_static | safe }}&nbsp;$</span>
</div> </div>
<div class="text-[11px] font-semibold text-brand-navy/85 mt-1">{{ sav.label }}</div> <div class="text-[11px] font-semibold text-brand-navy/85 mt-1">{{ sav.label }}</div>
<div class="text-[10px] text-brand-navy/45">{{ sav.sub }}</div> <div class="inline-flex items-center gap-1 mt-0.5">
<span class="w-1 h-1 rounded-full bg-brand-b2"></span>
<span class="font-mono text-[9px] tracking-[0.10em] text-brand-navy/50">{{ sav.chip }}</span>
</div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}