feat(marketing): refonte fonctionnalites avec contenu canonique + animations modernes subtiles
7 sections (hero stats counter, sticky sub-nav, 6 fonctionnalités bento avec chips specs, 3 sous-groupes intégrations, tableau architecture 3 tiers, conformité résumée + lien /conformite, CTA final). Contenu canonique extrait du site prod (WhisperX Large-v3, pyannote-audio, Mistral 7B, RAG sentence-transformers, 8 locuteurs, 30× temps réel, 95%+ FR-CA, prix 3 450/5 750/369 $). Animations: counter rAF easeOutCubic via Alpine + IntersectionObserver, fade-in stagger via data-ani-fade, animated underline H2, hover lift cards, sticky sub-nav avec active highlight, cosmic orbs flottantes, pulse glow sur card recommandée. Toutes les animations respectent prefers-reduced-motion via media query inline. Conserve les sections exports/specs/integrations grid pour rétro-compat tests. 13 assertions pytest fonctionnalites passent (les 2 failures conformite sont pré-existantes sur Windows — mojibake console, non liées à cette refonte).
This commit is contained in:
@@ -94,6 +94,7 @@
|
|||||||
--container-sm: 24rem;
|
--container-sm: 24rem;
|
||||||
--container-md: 28rem;
|
--container-md: 28rem;
|
||||||
--container-lg: 32rem;
|
--container-lg: 32rem;
|
||||||
|
--container-xl: 36rem;
|
||||||
--container-2xl: 42rem;
|
--container-2xl: 42rem;
|
||||||
--container-3xl: 48rem;
|
--container-3xl: 48rem;
|
||||||
--container-4xl: 56rem;
|
--container-4xl: 56rem;
|
||||||
@@ -128,6 +129,7 @@
|
|||||||
--tracking-wide: 0.025em;
|
--tracking-wide: 0.025em;
|
||||||
--tracking-wider: 0.05em;
|
--tracking-wider: 0.05em;
|
||||||
--tracking-widest: 0.1em;
|
--tracking-widest: 0.1em;
|
||||||
|
--leading-tight: 1.25;
|
||||||
--leading-snug: 1.375;
|
--leading-snug: 1.375;
|
||||||
--leading-relaxed: 1.625;
|
--leading-relaxed: 1.625;
|
||||||
--radius-md: 0.375rem;
|
--radius-md: 0.375rem;
|
||||||
@@ -403,6 +405,9 @@
|
|||||||
.top-\[42px\] {
|
.top-\[42px\] {
|
||||||
top: 42px;
|
top: 42px;
|
||||||
}
|
}
|
||||||
|
.top-\[62px\] {
|
||||||
|
top: 62px;
|
||||||
|
}
|
||||||
.top-full {
|
.top-full {
|
||||||
top: 100%;
|
top: 100%;
|
||||||
}
|
}
|
||||||
@@ -505,6 +510,12 @@
|
|||||||
.z-\[9999\] {
|
.z-\[9999\] {
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
}
|
}
|
||||||
|
.order-1 {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
.order-2 {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
.col-span-1 {
|
.col-span-1 {
|
||||||
grid-column: span 1 / span 1;
|
grid-column: span 1 / span 1;
|
||||||
}
|
}
|
||||||
@@ -559,6 +570,9 @@
|
|||||||
.-mt-6 {
|
.-mt-6 {
|
||||||
margin-top: calc(var(--spacing) * -6);
|
margin-top: calc(var(--spacing) * -6);
|
||||||
}
|
}
|
||||||
|
.mt-0 {
|
||||||
|
margin-top: calc(var(--spacing) * 0);
|
||||||
|
}
|
||||||
.mt-0\.5 {
|
.mt-0\.5 {
|
||||||
margin-top: calc(var(--spacing) * 0.5);
|
margin-top: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -631,6 +645,9 @@
|
|||||||
.mb-4 {
|
.mb-4 {
|
||||||
margin-bottom: calc(var(--spacing) * 4);
|
margin-bottom: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.mb-5 {
|
||||||
|
margin-bottom: calc(var(--spacing) * 5);
|
||||||
|
}
|
||||||
.mb-6 {
|
.mb-6 {
|
||||||
margin-bottom: calc(var(--spacing) * 6);
|
margin-bottom: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
@@ -643,8 +660,8 @@
|
|||||||
.mb-12 {
|
.mb-12 {
|
||||||
margin-bottom: calc(var(--spacing) * 12);
|
margin-bottom: calc(var(--spacing) * 12);
|
||||||
}
|
}
|
||||||
.mb-16 {
|
.mb-14 {
|
||||||
margin-bottom: calc(var(--spacing) * 16);
|
margin-bottom: calc(var(--spacing) * 14);
|
||||||
}
|
}
|
||||||
.ml-0\.5 {
|
.ml-0\.5 {
|
||||||
margin-left: calc(var(--spacing) * 0.5);
|
margin-left: calc(var(--spacing) * 0.5);
|
||||||
@@ -835,9 +852,6 @@
|
|||||||
.min-h-\[8rem\] {
|
.min-h-\[8rem\] {
|
||||||
min-height: 8rem;
|
min-height: 8rem;
|
||||||
}
|
}
|
||||||
.min-h-\[60vh\] {
|
|
||||||
min-height: 60vh;
|
|
||||||
}
|
|
||||||
.min-h-\[calc\(100vh-62px\)\] {
|
.min-h-\[calc\(100vh-62px\)\] {
|
||||||
min-height: calc(100vh - 62px);
|
min-height: calc(100vh - 62px);
|
||||||
}
|
}
|
||||||
@@ -964,6 +978,9 @@
|
|||||||
.max-w-\[1060px\] {
|
.max-w-\[1060px\] {
|
||||||
max-width: 1060px;
|
max-width: 1060px;
|
||||||
}
|
}
|
||||||
|
.max-w-\[1100px\] {
|
||||||
|
max-width: 1100px;
|
||||||
|
}
|
||||||
.max-w-\[1200px\] {
|
.max-w-\[1200px\] {
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
}
|
}
|
||||||
@@ -979,6 +996,9 @@
|
|||||||
.max-w-sm {
|
.max-w-sm {
|
||||||
max-width: var(--container-sm);
|
max-width: var(--container-sm);
|
||||||
}
|
}
|
||||||
|
.max-w-xl {
|
||||||
|
max-width: var(--container-xl);
|
||||||
|
}
|
||||||
.max-w-xs {
|
.max-w-xs {
|
||||||
max-width: var(--container-xs);
|
max-width: var(--container-xs);
|
||||||
}
|
}
|
||||||
@@ -1015,6 +1035,9 @@
|
|||||||
.flex-shrink-0 {
|
.flex-shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
.shrink-0 {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
.flex-grow {
|
.flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
@@ -1105,6 +1128,9 @@
|
|||||||
.resize-y {
|
.resize-y {
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
}
|
}
|
||||||
|
.scroll-mt-32 {
|
||||||
|
scroll-margin-top: calc(var(--spacing) * 32);
|
||||||
|
}
|
||||||
.list-inside {
|
.list-inside {
|
||||||
list-style-position: inside;
|
list-style-position: inside;
|
||||||
}
|
}
|
||||||
@@ -1167,9 +1193,6 @@
|
|||||||
.justify-start {
|
.justify-start {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
.justify-items-center {
|
|
||||||
justify-items: center;
|
|
||||||
}
|
|
||||||
.gap-0\.5 {
|
.gap-0\.5 {
|
||||||
gap: calc(var(--spacing) * 0.5);
|
gap: calc(var(--spacing) * 0.5);
|
||||||
}
|
}
|
||||||
@@ -1341,24 +1364,6 @@
|
|||||||
.rounded {
|
.rounded {
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
}
|
}
|
||||||
.rounded-\[0\.5rem\] {
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
.rounded-\[0\.75rem\] {
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
}
|
|
||||||
.rounded-\[12px\] {
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
.rounded-\[14px\] {
|
|
||||||
border-radius: 14px;
|
|
||||||
}
|
|
||||||
.rounded-\[18px\] {
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
.rounded-\[20px\] {
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
||||||
.rounded-full {
|
.rounded-full {
|
||||||
border-radius: calc(infinity * 1px);
|
border-radius: calc(infinity * 1px);
|
||||||
}
|
}
|
||||||
@@ -1368,6 +1373,9 @@
|
|||||||
.rounded-md {
|
.rounded-md {
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
}
|
}
|
||||||
|
.rounded-none {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
.rounded-xl {
|
.rounded-xl {
|
||||||
border-radius: var(--radius-xl);
|
border-radius: var(--radius-xl);
|
||||||
}
|
}
|
||||||
@@ -1762,6 +1770,12 @@
|
|||||||
.bg-brand-bg {
|
.bg-brand-bg {
|
||||||
background-color: #f7f9fc;
|
background-color: #f7f9fc;
|
||||||
}
|
}
|
||||||
|
.bg-brand-bg\/50 {
|
||||||
|
background-color: color-mix(in oklab, #f7f9fc 50%, transparent);
|
||||||
|
}
|
||||||
|
.bg-brand-bg\/60 {
|
||||||
|
background-color: color-mix(in oklab, #f7f9fc 60%, transparent);
|
||||||
|
}
|
||||||
.bg-brand-border {
|
.bg-brand-border {
|
||||||
background-color: #e6ebf2;
|
background-color: #e6ebf2;
|
||||||
}
|
}
|
||||||
@@ -1918,6 +1932,12 @@
|
|||||||
background-color: color-mix(in oklab, var(--color-white) 30%, transparent);
|
background-color: color-mix(in oklab, var(--color-white) 30%, transparent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bg-white\/95 {
|
||||||
|
background-color: color-mix(in srgb, #fff 95%, transparent);
|
||||||
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
|
background-color: color-mix(in oklab, var(--color-white) 95%, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
.bg-white\/\[0\.05\] {
|
.bg-white\/\[0\.05\] {
|
||||||
background-color: color-mix(in srgb, #fff 5%, transparent);
|
background-color: color-mix(in srgb, #fff 5%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -1960,9 +1980,6 @@
|
|||||||
--tw-gradient-position: to right in oklab;
|
--tw-gradient-position: to right in oklab;
|
||||||
background-image: linear-gradient(var(--tw-gradient-stops));
|
background-image: linear-gradient(var(--tw-gradient-stops));
|
||||||
}
|
}
|
||||||
.bg-brand-grad {
|
|
||||||
background-image: linear-gradient(118deg, #0062ff, #00bdd8 52%, #00c896);
|
|
||||||
}
|
|
||||||
.from-\[var\(--bg-accent\)\] {
|
.from-\[var\(--bg-accent\)\] {
|
||||||
--tw-gradient-from: var(--bg-accent);
|
--tw-gradient-from: var(--bg-accent);
|
||||||
--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));
|
||||||
@@ -2183,6 +2200,9 @@
|
|||||||
.pt-8 {
|
.pt-8 {
|
||||||
padding-top: calc(var(--spacing) * 8);
|
padding-top: calc(var(--spacing) * 8);
|
||||||
}
|
}
|
||||||
|
.pt-12 {
|
||||||
|
padding-top: calc(var(--spacing) * 12);
|
||||||
|
}
|
||||||
.pt-\[62px\] {
|
.pt-\[62px\] {
|
||||||
padding-top: 62px;
|
padding-top: 62px;
|
||||||
}
|
}
|
||||||
@@ -2216,12 +2236,24 @@
|
|||||||
.pb-2 {
|
.pb-2 {
|
||||||
padding-bottom: calc(var(--spacing) * 2);
|
padding-bottom: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
|
.pb-3 {
|
||||||
|
padding-bottom: calc(var(--spacing) * 3);
|
||||||
|
}
|
||||||
.pb-4 {
|
.pb-4 {
|
||||||
padding-bottom: calc(var(--spacing) * 4);
|
padding-bottom: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
|
.pb-5 {
|
||||||
|
padding-bottom: calc(var(--spacing) * 5);
|
||||||
|
}
|
||||||
.pb-6 {
|
.pb-6 {
|
||||||
padding-bottom: calc(var(--spacing) * 6);
|
padding-bottom: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
|
.pb-16 {
|
||||||
|
padding-bottom: calc(var(--spacing) * 16);
|
||||||
|
}
|
||||||
|
.pb-20 {
|
||||||
|
padding-bottom: calc(var(--spacing) * 20);
|
||||||
|
}
|
||||||
.pl-2 {
|
.pl-2 {
|
||||||
padding-left: calc(var(--spacing) * 2);
|
padding-left: calc(var(--spacing) * 2);
|
||||||
}
|
}
|
||||||
@@ -2255,6 +2287,9 @@
|
|||||||
.align-middle {
|
.align-middle {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
.align-text-top {
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
.align-top {
|
.align-top {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
@@ -2328,6 +2363,9 @@
|
|||||||
.text-\[clamp\(2\.25rem\,4vw\,3\.5rem\)\] {
|
.text-\[clamp\(2\.25rem\,4vw\,3\.5rem\)\] {
|
||||||
font-size: clamp(2.25rem, 4vw, 3.5rem);
|
font-size: clamp(2.25rem, 4vw, 3.5rem);
|
||||||
}
|
}
|
||||||
|
.text-\[clamp\(2\.25rem\,4vw\,3\.75rem\)\] {
|
||||||
|
font-size: clamp(2.25rem, 4vw, 3.75rem);
|
||||||
|
}
|
||||||
.text-\[clamp\(2rem\,3vw\,2\.5rem\)\] {
|
.text-\[clamp\(2rem\,3vw\,2\.5rem\)\] {
|
||||||
font-size: clamp(2rem, 3vw, 2.5rem);
|
font-size: clamp(2rem, 3vw, 2.5rem);
|
||||||
}
|
}
|
||||||
@@ -2354,6 +2392,10 @@
|
|||||||
--tw-leading: var(--leading-snug);
|
--tw-leading: var(--leading-snug);
|
||||||
line-height: var(--leading-snug);
|
line-height: var(--leading-snug);
|
||||||
}
|
}
|
||||||
|
.leading-tight {
|
||||||
|
--tw-leading: var(--leading-tight);
|
||||||
|
line-height: var(--leading-tight);
|
||||||
|
}
|
||||||
.font-black {
|
.font-black {
|
||||||
--tw-font-weight: var(--font-weight-black);
|
--tw-font-weight: var(--font-weight-black);
|
||||||
font-weight: var(--font-weight-black);
|
font-weight: var(--font-weight-black);
|
||||||
@@ -2374,6 +2416,10 @@
|
|||||||
--tw-font-weight: var(--font-weight-semibold);
|
--tw-font-weight: var(--font-weight-semibold);
|
||||||
font-weight: var(--font-weight-semibold);
|
font-weight: var(--font-weight-semibold);
|
||||||
}
|
}
|
||||||
|
.tracking-\[0\.2em\] {
|
||||||
|
--tw-tracking: 0.2em;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
}
|
||||||
.tracking-tight {
|
.tracking-tight {
|
||||||
--tw-tracking: var(--tracking-tight);
|
--tw-tracking: var(--tracking-tight);
|
||||||
letter-spacing: var(--tracking-tight);
|
letter-spacing: var(--tracking-tight);
|
||||||
@@ -2501,6 +2547,9 @@
|
|||||||
.text-brand-navy {
|
.text-brand-navy {
|
||||||
color: #060d1a;
|
color: #060d1a;
|
||||||
}
|
}
|
||||||
|
.text-brand-navy\/40 {
|
||||||
|
color: color-mix(in oklab, #060d1a 40%, transparent);
|
||||||
|
}
|
||||||
.text-brand-navy\/50 {
|
.text-brand-navy\/50 {
|
||||||
color: color-mix(in oklab, #060d1a 50%, transparent);
|
color: color-mix(in oklab, #060d1a 50%, transparent);
|
||||||
}
|
}
|
||||||
@@ -2621,6 +2670,12 @@
|
|||||||
color: color-mix(in oklab, var(--color-white) 50%, transparent);
|
color: color-mix(in oklab, var(--color-white) 50%, transparent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.text-white\/60 {
|
||||||
|
color: color-mix(in srgb, #fff 60%, transparent);
|
||||||
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
|
color: color-mix(in oklab, var(--color-white) 60%, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
.text-white\/70 {
|
.text-white\/70 {
|
||||||
color: color-mix(in srgb, #fff 70%, transparent);
|
color: color-mix(in srgb, #fff 70%, transparent);
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
@supports (color: color-mix(in lab, red, red)) {
|
||||||
@@ -2633,12 +2688,6 @@
|
|||||||
color: color-mix(in oklab, var(--color-white) 80%, transparent);
|
color: color-mix(in oklab, var(--color-white) 80%, transparent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.text-white\/\[0\.04\] {
|
|
||||||
color: color-mix(in srgb, #fff 4%, transparent);
|
|
||||||
@supports (color: color-mix(in lab, red, red)) {
|
|
||||||
color: color-mix(in oklab, var(--color-white) 4%, transparent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.text-yellow-400 {
|
.text-yellow-400 {
|
||||||
color: var(--color-yellow-400);
|
color: var(--color-yellow-400);
|
||||||
}
|
}
|
||||||
@@ -2698,6 +2747,9 @@
|
|||||||
.opacity-0 {
|
.opacity-0 {
|
||||||
opacity: 0%;
|
opacity: 0%;
|
||||||
}
|
}
|
||||||
|
.opacity-20 {
|
||||||
|
opacity: 20%;
|
||||||
|
}
|
||||||
.opacity-30 {
|
.opacity-30 {
|
||||||
opacity: 30%;
|
opacity: 30%;
|
||||||
}
|
}
|
||||||
@@ -2800,6 +2852,9 @@
|
|||||||
--tw-backdrop-blur: blur(var(--blur-xl));
|
--tw-backdrop-blur: blur(var(--blur-xl));
|
||||||
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
||||||
}
|
}
|
||||||
|
.backdrop-filter {
|
||||||
|
backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
|
||||||
|
}
|
||||||
.transition {
|
.transition {
|
||||||
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
|
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
|
||||||
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
||||||
@@ -2905,13 +2960,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.group-hover\:text-brand-navy {
|
|
||||||
&:is(:where(.group):hover *) {
|
|
||||||
@media (hover: hover) {
|
|
||||||
color: #060d1a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.group-hover\:opacity-100 {
|
.group-hover\:opacity-100 {
|
||||||
&:is(:where(.group):hover *) {
|
&:is(:where(.group):hover *) {
|
||||||
@media (hover: hover) {
|
@media (hover: hover) {
|
||||||
@@ -3759,6 +3807,43 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.focus\:not-sr-only {
|
||||||
|
&:focus {
|
||||||
|
position: static;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: visible;
|
||||||
|
clip-path: none;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:fixed {
|
||||||
|
&:focus {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:top-2 {
|
||||||
|
&:focus {
|
||||||
|
top: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:left-2 {
|
||||||
|
&:focus {
|
||||||
|
left: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:z-\[100\] {
|
||||||
|
&:focus {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:rounded-none {
|
||||||
|
&:focus {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
.focus\:border-\[var\(--border-accent\)\] {
|
.focus\:border-\[var\(--border-accent\)\] {
|
||||||
&:focus {
|
&:focus {
|
||||||
border-color: var(--border-accent);
|
border-color: var(--border-accent);
|
||||||
@@ -3774,6 +3859,26 @@
|
|||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.focus\:bg-brand-navy {
|
||||||
|
&:focus {
|
||||||
|
background-color: #060d1a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:px-4 {
|
||||||
|
&:focus {
|
||||||
|
padding-inline: calc(var(--spacing) * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:py-2 {
|
||||||
|
&:focus {
|
||||||
|
padding-block: calc(var(--spacing) * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focus\:text-white {
|
||||||
|
&:focus {
|
||||||
|
color: var(--color-white);
|
||||||
|
}
|
||||||
|
}
|
||||||
.focus\:ring-1 {
|
.focus\:ring-1 {
|
||||||
&:focus {
|
&:focus {
|
||||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||||
@@ -4023,11 +4128,6 @@
|
|||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sm\:grid-cols-5 {
|
|
||||||
@media (width >= 40rem) {
|
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.sm\:flex-row {
|
.sm\:flex-row {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -4043,6 +4143,11 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:justify-end {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:gap-2 {
|
.sm\:gap-2 {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
gap: calc(var(--spacing) * 2);
|
gap: calc(var(--spacing) * 2);
|
||||||
@@ -4171,6 +4276,11 @@
|
|||||||
padding-bottom: calc(var(--spacing) * 6);
|
padding-bottom: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.sm\:text-right {
|
||||||
|
@media (width >= 40rem) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
.sm\:text-base {
|
.sm\:text-base {
|
||||||
@media (width >= 40rem) {
|
@media (width >= 40rem) {
|
||||||
font-size: var(--text-base);
|
font-size: var(--text-base);
|
||||||
@@ -4289,6 +4399,11 @@
|
|||||||
gap: calc(var(--spacing) * 4);
|
gap: calc(var(--spacing) * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:gap-5 {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
gap: calc(var(--spacing) * 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:p-2 {
|
.md\:p-2 {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
padding: calc(var(--spacing) * 2);
|
padding: calc(var(--spacing) * 2);
|
||||||
@@ -4304,6 +4419,11 @@
|
|||||||
padding: calc(var(--spacing) * 6);
|
padding: calc(var(--spacing) * 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:p-7 {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
padding: calc(var(--spacing) * 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:p-8 {
|
.md\:p-8 {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
padding: calc(var(--spacing) * 8);
|
padding: calc(var(--spacing) * 8);
|
||||||
@@ -4329,6 +4449,11 @@
|
|||||||
padding-block: calc(var(--spacing) * 3);
|
padding-block: calc(var(--spacing) * 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:py-28 {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
padding-block: calc(var(--spacing) * 28);
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:py-32 {
|
.md\:py-32 {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
padding-block: calc(var(--spacing) * 32);
|
padding-block: calc(var(--spacing) * 32);
|
||||||
@@ -4351,12 +4476,24 @@
|
|||||||
line-height: var(--tw-leading, var(--text-4xl--line-height));
|
line-height: var(--tw-leading, var(--text-4xl--line-height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:text-5xl {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
font-size: var(--text-5xl);
|
||||||
|
line-height: var(--tw-leading, var(--text-5xl--line-height));
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:text-base {
|
.md\:text-base {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
font-size: var(--text-base);
|
font-size: var(--text-base);
|
||||||
line-height: var(--tw-leading, var(--text-base--line-height));
|
line-height: var(--tw-leading, var(--text-base--line-height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.md\:text-lg {
|
||||||
|
@media (width >= 48rem) {
|
||||||
|
font-size: var(--text-lg);
|
||||||
|
line-height: var(--tw-leading, var(--text-lg--line-height));
|
||||||
|
}
|
||||||
|
}
|
||||||
.md\:text-sm {
|
.md\:text-sm {
|
||||||
@media (width >= 48rem) {
|
@media (width >= 48rem) {
|
||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
@@ -4393,6 +4530,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:grid {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:hidden {
|
.lg\:hidden {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -4439,14 +4581,19 @@
|
|||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:grid-cols-5 {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:grid-cols-7 {
|
.lg\:grid-cols-7 {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.lg\:grid-cols-9 {
|
.lg\:grid-cols-\[1fr_240px\] {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
grid-template-columns: repeat(9, minmax(0, 1fr));
|
grid-template-columns: 1fr 240px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.lg\:flex-row {
|
.lg\:flex-row {
|
||||||
@@ -4454,6 +4601,11 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.lg\:gap-10 {
|
||||||
|
@media (width >= 64rem) {
|
||||||
|
gap: calc(var(--spacing) * 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
.lg\:border-r {
|
.lg\:border-r {
|
||||||
@media (width >= 64rem) {
|
@media (width >= 64rem) {
|
||||||
border-right-style: var(--tw-border-style);
|
border-right-style: var(--tw-border-style);
|
||||||
|
|||||||
@@ -1,54 +1,464 @@
|
|||||||
{% extends 'marketing/base.html' %}
|
{% extends 'marketing/base.html' %}
|
||||||
|
|
||||||
{% block title %}Fonctionnalités DictIA — Transcription IA WhisperX, diarisation, résumés Mistral 7B local{% endblock %}
|
{% block title %}Fonctionnalités DictIA — WhisperX FR-CA, diarisation 8 locuteurs, Mistral 7B local, Q&R, exports DOCX/PDF/SRT{% endblock %}
|
||||||
{% block description %}Toutes les fonctionnalités de DictIA : WhisperX Large-v3 fine-tuné FR-CA, diarisation 8 locuteurs, Mistral 7B local, Q&R RAG, exports DOCX/PDF/SRT, intégrations Word/Outlook/Teams.{% endblock %}
|
{% block description %}Toutes les fonctionnalités de DictIA : transcription WhisperX Large-v3 fine-tunée FR-CA, diarisation pyannote 8 locuteurs, résumés Mistral 7B local, chat Q&R RAG, synchronisation audio-texte, exports multi-formats, intégrations Word, Outlook, Teams, Notion, Obsidian, Zapier.{% endblock %}
|
||||||
|
|
||||||
|
{% block head_extra %}
|
||||||
|
{# Page-scoped CSS — animations subtiles sans dépendre d'un rebuild Tailwind ; respecte prefers-reduced-motion via base.css. #}
|
||||||
|
<style>
|
||||||
|
/* Animated underline H2 — visible classe ajoutée via IntersectionObserver */
|
||||||
|
.ani-underline { position: relative; display: inline-block; }
|
||||||
|
.ani-underline::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: -10px;
|
||||||
|
width: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(118deg, #0062ff, #00bdd8 52%, #00c896);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
transition: width 600ms ease-out;
|
||||||
|
}
|
||||||
|
.ani-underline.is-visible::after { width: 56px; }
|
||||||
|
|
||||||
|
/* Stagger fade-in cards — class ajoutée par IntersectionObserver */
|
||||||
|
.ani-fade { opacity: 0; transform: translateY(16px); transition: opacity 600ms ease-out, transform 600ms ease-out; transition-delay: var(--delay, 0ms); }
|
||||||
|
.ani-fade.is-visible { opacity: 1; transform: translateY(0); }
|
||||||
|
|
||||||
|
/* Hover lift cards */
|
||||||
|
.ani-lift { transition: transform 200ms ease-out, box-shadow 200ms ease-out; }
|
||||||
|
.ani-lift:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(0, 98, 255, 0.18); }
|
||||||
|
|
||||||
|
/* Sticky sub-nav active link */
|
||||||
|
.subnav-link[aria-current="true"] { color: #0062ff; }
|
||||||
|
.subnav-link[aria-current="true"]::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
height: 2px;
|
||||||
|
margin-top: 4px;
|
||||||
|
background: linear-gradient(118deg, #0062ff, #00bdd8 52%, #00c896);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cosmic float orbs (n'utilise pas tc-float-y pour éviter rebuild) */
|
||||||
|
@keyframes orb-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
|
||||||
|
.orb-float-a { animation: orb-float 8s ease-in-out infinite; }
|
||||||
|
.orb-float-b { animation: orb-float 11s ease-in-out infinite reverse; }
|
||||||
|
|
||||||
|
/* DictIA Cloud pulse glow */
|
||||||
|
@keyframes card-pulse-glow {
|
||||||
|
0%, 100% { box-shadow: 0 4px 20px rgba(0, 98, 255, 0.28); }
|
||||||
|
50% { box-shadow: 0 12px 40px rgba(0, 98, 255, 0.5); }
|
||||||
|
}
|
||||||
|
.card-pulse-glow { animation: card-pulse-glow 3s ease-in-out infinite; }
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.ani-fade { opacity: 1; transform: none; transition: none; }
|
||||||
|
.ani-underline::after { transition: none; width: 56px; }
|
||||||
|
.ani-lift { transition: none; }
|
||||||
|
.ani-lift:hover { transform: none; }
|
||||||
|
.orb-float-a, .orb-float-b, .card-pulse-glow { animation: none; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{# ===== HEADER ===== #}
|
|
||||||
<section class="bg-brand-navy text-white py-20" aria-labelledby="page-title">
|
|
||||||
<div class="max-w-[820px] mx-auto px-6 text-center">
|
|
||||||
<p class="eyebrow grad-text mb-4">FONCTIONNALITÉS</p>
|
|
||||||
<h1 id="page-title" class="text-[clamp(2.25rem,4vw,3.5rem)] font-black mb-4">
|
|
||||||
Tout ce qu'il faut pour transcrire <span class="grad-text">en restant chez soi</span>.
|
|
||||||
</h1>
|
|
||||||
<p class="text-lg text-white/80">
|
|
||||||
Une pile technique 100 % québécoise, sans dépendance à un fournisseur cloud américain. Détails techniques sur demande : <a href="mailto:info@dictia.ca" class="grad-text font-semibold hover:underline">info@dictia.ca</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{# ===== 6 BENTO FEATURES ===== #}
|
|
||||||
<section class="bg-white py-20" aria-labelledby="features-title">
|
|
||||||
<div class="max-w-[1060px] mx-auto px-6">
|
|
||||||
<h2 id="features-title" class="sr-only">Six fonctionnalités principales</h2>
|
|
||||||
{# NOTE: bento card content is duplicated between landing.html and fonctionnalites.html.
|
|
||||||
When editing, sync both files. Future refactor: extract to _partials/_bento_features.html.
|
|
||||||
Icon SVGs (heroicons-style outline) are inlined directly because the macro renders `icon | safe`. #}
|
|
||||||
{% from 'macros/bento.html' import bento_card %}
|
|
||||||
{%- set icon_microphone = '<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-7 h-7" aria-hidden="true"><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>' -%}
|
{%- set icon_microphone = '<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-7 h-7" aria-hidden="true"><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>' -%}
|
||||||
{%- set icon_users = '<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-7 h-7" 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"/><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>' -%}
|
{%- set icon_users = '<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-7 h-7" 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"/><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>' -%}
|
||||||
{%- set icon_document = '<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-7 h-7" 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"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="9" y1="17" x2="15" y2="17"/></svg>' -%}
|
{%- set icon_document = '<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-7 h-7" 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"/><polyline points="14 2 14 8 20 8"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="9" y1="17" x2="15" y2="17"/></svg>' -%}
|
||||||
{%- set icon_chat = '<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-7 h-7" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>' -%}
|
{%- set icon_chat = '<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-7 h-7" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>' -%}
|
||||||
|
{%- set icon_sync = '<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-7 h-7" aria-hidden="true"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"/><path d="M20.49 15a9 9 0 0 1-14.85 3.36L1 14"/></svg>' -%}
|
||||||
{%- set icon_export = '<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-7 h-7" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>' -%}
|
{%- set icon_export = '<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-7 h-7" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>' -%}
|
||||||
{%- set icon_plug = '<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-7 h-7" aria-hidden="true"><path d="M9 2v6"/><path d="M15 2v6"/><path d="M5 8h14v4a5 5 0 0 1-5 5h-4a5 5 0 0 1-5-5z"/><path d="M12 17v5"/></svg>' -%}
|
{%- set icon_check = '<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-4 h-4 mt-0.5 flex-shrink-0 text-brand-b3" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>' -%}
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-[1.5px] bg-brand-border rounded overflow-hidden">
|
{%- set icon_link = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M5 12h14M13 5l7 7-7 7"/></svg>' -%}
|
||||||
{{ bento_card('01', 'Transcription WhisperX', 'Large-v3 fine-tuné FR-CA. Précision 95 %+ sur réunions, dictées, audiences (méthodologie disponible sur demande).', icon_microphone) }}
|
|
||||||
{{ bento_card('02', 'Diarisation 8 locuteurs', 'pyannote sépare automatiquement les intervenants. Identification par embeddings vocaux.', icon_users) }}
|
{# ===== HERO ===== #}
|
||||||
{{ bento_card('03', 'Résumés Mistral 7B', 'IA locale génère résumés, points d\'action et procès-verbaux. Aucune connexion cloud.', icon_document) }}
|
<section class="relative overflow-hidden bg-brand-navy text-white py-24 md:py-28" aria-labelledby="page-title">
|
||||||
{{ bento_card('04', 'Q&R sur enregistrement', 'Posez des questions à vos réunions. RAG local sur embeddings sentence-transformers.', icon_chat) }}
|
{# Cosmic orbs background — float animation subtile #}
|
||||||
{{ bento_card('05', 'Exports multiples', 'DOCX, PDF, SRT, VTT, TXT, JSON, MD. Formats avocat, notaire, CPA.', icon_export) }}
|
<div class="absolute inset-0 pointer-events-none" aria-hidden="true">
|
||||||
{{ bento_card('06', 'Intégrations', 'Word, Outlook, Teams, Notion, Obsidian, Zapier, Make, n8n.', icon_plug) }}
|
<div class="orb-float-a absolute top-1/4 left-1/4 w-[600px] h-[600px] rounded-full"
|
||||||
|
style="background: radial-gradient(circle, rgba(0,98,255,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"
|
||||||
|
style="background: radial-gradient(circle, rgba(0,189,216,0.07) 0%, transparent 60%); filter: blur(40px);"></div>
|
||||||
|
<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>
|
||||||
|
<div class="absolute top-1/3 left-0 right-0 h-px"
|
||||||
|
style="background: linear-gradient(90deg, transparent, rgba(0,98,255,0.3), rgba(0,189,216,0.2), transparent);"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="relative max-w-[1200px] mx-auto px-6 text-center">
|
||||||
|
<p class="eyebrow grad-text mb-5 animate-tc-fade-in-up" style="animation-delay: 0ms; animation-fill-mode: backwards;">
|
||||||
|
FONCTIONNALITÉS · WHISPERX · MISTRAL 7B
|
||||||
|
</p>
|
||||||
|
<h1 id="page-title" class="text-[clamp(2.25rem,4vw,3.75rem)] font-black leading-[1.05] mb-5 max-w-3xl mx-auto animate-tc-fade-in-up" style="animation-delay: 75ms; animation-fill-mode: backwards;">
|
||||||
|
Tout ce qu'il vous faut pour transcrire <span class="grad-text">en restant chez soi</span>.
|
||||||
|
</h1>
|
||||||
|
<p class="text-lg text-white/70 max-w-2xl mx-auto mb-12 animate-tc-fade-in-up" style="animation-delay: 150ms; animation-fill-mode: backwards;">
|
||||||
|
Pile technique 100 % québécoise. Inférence sur GPU local ou OVH Beauharnois. Aucun transit cloud américain. Conçu avec 9 ordres professionnels.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{# Stats hero — counter via Alpine x-data + IntersectionObserver pour déclenchement #}
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-8 max-w-4xl mx-auto" role="list">
|
||||||
|
{% for stat in [
|
||||||
|
{'target': 95, 'suffix': ' %+', 'label': "précision FR-CA", 'sub': 'WhisperX Large-v3'},
|
||||||
|
{'target': 30, 'suffix': '×', 'label': "vitesse temps réel", 'sub': '1 h audio → ~5 min'},
|
||||||
|
{'target': 8, 'suffix': '', 'label': "locuteurs simultanés", 'sub': 'pyannote-audio'},
|
||||||
|
{'target': 0, 'suffix': '', 'label': "transit cloud", 'sub': '100 % local'}
|
||||||
|
] %}
|
||||||
|
<div class="text-center" role="listitem"
|
||||||
|
x-data="{ value: 0, target: {{ stat.target }} }"
|
||||||
|
x-init="
|
||||||
|
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
|
if (reduced) { value = target; return; }
|
||||||
|
const io = new IntersectionObserver((entries) => {
|
||||||
|
if (!entries[0].isIntersecting) return;
|
||||||
|
const start = performance.now();
|
||||||
|
const dur = 1200;
|
||||||
|
const tick = (now) => {
|
||||||
|
const t = Math.min(1, (now - start) / dur);
|
||||||
|
value = Math.round(target * (1 - Math.pow(1 - t, 3)));
|
||||||
|
if (t < 1) requestAnimationFrame(tick);
|
||||||
|
};
|
||||||
|
requestAnimationFrame(tick);
|
||||||
|
io.disconnect();
|
||||||
|
}, { threshold: 0.5 });
|
||||||
|
io.observe($el);
|
||||||
|
">
|
||||||
|
<div class="text-5xl font-black grad-text mb-2 tabular-nums">
|
||||||
|
<span x-text="value"></span><span>{{ stat.suffix | safe }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-semibold text-white mb-1">{{ stat.label }}</div>
|
||||||
|
<div class="text-xs text-white/60">{{ stat.sub | safe }}</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# ===== EXPORT FORMATS DEEP-DIVE ===== #}
|
{# ===== STICKY SUB-NAV ===== #}
|
||||||
<section class="bg-brand-bg py-20" aria-labelledby="exports-title">
|
<nav class="sticky top-[62px] z-40 bg-white/95 backdrop-blur-sm border-b border-brand-border" aria-label="Navigation des sections de la page"
|
||||||
|
x-data="{ active: 'fonctionnalites' }"
|
||||||
|
x-init="
|
||||||
|
const sections = ['fonctionnalites', 'integrations', 'architecture', 'conformite-resume'];
|
||||||
|
const io = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(e => {
|
||||||
|
if (e.isIntersecting && e.intersectionRatio > 0.15) active = e.target.id;
|
||||||
|
});
|
||||||
|
}, { rootMargin: '-120px 0px -55% 0px', threshold: [0, 0.15, 0.3] });
|
||||||
|
sections.forEach(id => { const el = document.getElementById(id); if (el) io.observe(el); });
|
||||||
|
">
|
||||||
<div class="max-w-[1200px] mx-auto px-6">
|
<div class="max-w-[1200px] mx-auto px-6">
|
||||||
<div class="text-center max-w-2xl mx-auto mb-12">
|
<ul class="flex flex-wrap gap-x-6 gap-y-1 py-3 text-sm font-semibold text-brand-navy/70" role="list">
|
||||||
<p class="eyebrow grad-text mb-4">FORMATS D'EXPORT</p>
|
<li><a href="#fonctionnalites" class="subnav-link inline-block py-1 hover:text-brand-b1 transition-colors focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||||
<h2 id="exports-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4 text-brand-navy">
|
:aria-current="active === 'fonctionnalites' ? 'true' : 'false'">Fonctionnalités</a></li>
|
||||||
|
<li><a href="#integrations" class="subnav-link inline-block py-1 hover:text-brand-b1 transition-colors focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||||
|
:aria-current="active === 'integrations' ? 'true' : 'false'">Intégrations</a></li>
|
||||||
|
<li><a href="#architecture" class="subnav-link inline-block py-1 hover:text-brand-b1 transition-colors focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||||
|
:aria-current="active === 'architecture' ? 'true' : 'false'">Architecture</a></li>
|
||||||
|
<li><a href="#conformite-resume" class="subnav-link inline-block py-1 hover:text-brand-b1 transition-colors focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||||
|
:aria-current="active === 'conformite-resume' ? 'true' : 'false'">Conformité</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{# ===== 6 FONCTIONNALITÉS PRINCIPALES =====
|
||||||
|
NOTE: bento card content is duplicated between landing.html and fonctionnalites.html.
|
||||||
|
When editing, sync both files. Future refactor: extract to _partials/_bento_features.html.
|
||||||
|
#}
|
||||||
|
<section id="fonctionnalites" class="bg-white py-20 scroll-mt-32" aria-labelledby="features-title">
|
||||||
|
<div class="max-w-[1200px] mx-auto px-6">
|
||||||
|
<div class="text-center max-w-3xl mx-auto mb-14">
|
||||||
|
<p class="eyebrow grad-text mb-4">SIX FONCTIONNALITÉS</p>
|
||||||
|
<h2 id="features-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black text-brand-navy">
|
||||||
|
<span class="ani-underline" data-ani-underline>Conçu pour les pros qui parlent et écrivent toute la journée.</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-brand-navy/70 mt-6">
|
||||||
|
Chaque module fonctionne hors-ligne sur votre matériel ou notre VPS Québec OVH. Aucun appel à OpenAI, Microsoft Copilot ou Google.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% from 'macros/bento.html' import bento_card %}
|
||||||
|
{%- set features = [
|
||||||
|
{
|
||||||
|
'n': '01',
|
||||||
|
'title': 'Transcription IA locale FR-CA',
|
||||||
|
'desc': 'WhisperX Large-v3 entraîné sur des millions d\'heures de québécois juridique, médical et gouvernemental. 95 %+ dès la première utilisation, sans aucun ajustement manuel.',
|
||||||
|
'icon': icon_microphone,
|
||||||
|
'chips': ['WhisperX Large-v3', 'GPU RTX 8 ou 16 Go', '1 h audio → ~5 min', '< 5 % taux d\'erreur', '100 % local · hors-ligne']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'n': '02',
|
||||||
|
'title': 'Identification des locuteurs (diarisation)',
|
||||||
|
'desc': 'Jusqu\'à 8 interlocuteurs distingués automatiquement. Chaque prise de parole est étiquetée et horodatée pour une lecture nette des comités, audiences et entrevues.',
|
||||||
|
'icon': icon_users,
|
||||||
|
'chips': ['pyannote-audio 3.x', '8 personnes max', 'Étiquettes auto', 'Horodatage word-level']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'n': '03',
|
||||||
|
'title': 'Résumés & points d\'action',
|
||||||
|
'desc': 'Résumé exécutif, décisions clés et liste d\'actions générés en français. Format avocat, notaire, CPA ou médecin selon votre profil. Récupérez ~2 h/jour de rédaction.',
|
||||||
|
'icon': icon_document,
|
||||||
|
'chips': ['Mistral 7B local (DictIA 16+)', 'Templates pro', 'Décisions + actions', '2 h/jour récupérées']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'n': '04',
|
||||||
|
'title': 'Chat IA sur enregistrement (Q&R)',
|
||||||
|
'desc': 'Posez vos questions directement sur l\'audio : « Quel montant a été mentionné ? » ou « Quels engagements ont été pris ? » — réponses instantanées en langage naturel.',
|
||||||
|
'icon': icon_chat,
|
||||||
|
'chips': ['Mistral 7B local', 'RAG local', 'sentence-transformers', 'Recherche contextuelle']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'n': '05',
|
||||||
|
'title': 'Synchronisation audio-texte',
|
||||||
|
'desc': 'Cliquez sur n\'importe quel mot pour sauter à ce moment dans l\'audio. Suivi automatique en lecture avec mot actif surligné — révision et référencement instantanés.',
|
||||||
|
'icon': icon_sync,
|
||||||
|
'chips': ['Timestamps word-level', 'Lecture guidée', 'Mot actif surligné', 'Navigation par mot clé']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'n': '06',
|
||||||
|
'title': 'Recherche sémantique & exports',
|
||||||
|
'desc': 'Recherchez par sens et non seulement par mot-clé. Exportez vers DOCX, PDF, SRT, VTT, TXT, JSON, MD — compatible Obsidian, Notion, Logseq via Markdown.',
|
||||||
|
'icon': icon_export,
|
||||||
|
'chips': ['DOCX, PDF, SRT, VTT', 'TXT, JSON, MD', 'Obsidian · Notion · Logseq', 'Format avocat / notaire / CPA']
|
||||||
|
}
|
||||||
|
] -%}
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-[1.5px] bg-brand-border rounded overflow-hidden">
|
||||||
|
{% for f in features %}
|
||||||
|
<article class="ani-fade ani-lift relative bg-brand-navy2 p-6 overflow-hidden border border-white/[0.045]"
|
||||||
|
style="--delay: {{ loop.index0 * 60 }}ms;"
|
||||||
|
data-ani-fade>
|
||||||
|
<div class="absolute top-2 right-4 text-[80px] font-black grad-text opacity-20 leading-none" aria-hidden="true">{{ f.n }}</div>
|
||||||
|
<div class="relative">
|
||||||
|
<div class="text-brand-b1 mb-4" aria-hidden="true">{{ f.icon | safe }}</div>
|
||||||
|
<h3 class="text-lg font-bold mb-2 text-white">{{ f.title | safe }}</h3>
|
||||||
|
<p class="text-sm text-white/70 leading-relaxed mb-4">{{ f.desc | safe }}</p>
|
||||||
|
<ul class="flex flex-wrap gap-1.5" role="list">
|
||||||
|
{% for chip in f.chips %}
|
||||||
|
<li class="text-[11px] font-mono font-medium text-white/80 bg-white/[0.06] border border-white/[0.08] px-2 py-1 rounded-full">{{ chip | safe }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Microcopy LPC art. 219 — méthodologie 95% #}
|
||||||
|
<p class="text-xs text-brand-navy/70 text-center mt-8 max-w-2xl mx-auto">
|
||||||
|
Précision mesurée sur un échantillon interne d'audio professionnel québécois (juridique, médical, municipal) — méthodologie disponible sur demande à <a href="mailto:info@dictia.ca" class="hover:text-brand-navy underline">info@dictia.ca</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# ===== INTÉGRATIONS ===== #}
|
||||||
|
<section id="integrations" class="bg-brand-bg py-20 scroll-mt-32" aria-labelledby="integrations-title">
|
||||||
|
<div class="max-w-[1200px] mx-auto px-6">
|
||||||
|
<div class="text-center max-w-3xl mx-auto mb-14">
|
||||||
|
<p class="eyebrow grad-text mb-4">INTÉGRATIONS</p>
|
||||||
|
<h2 id="integrations-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black text-brand-navy">
|
||||||
|
<span class="ani-underline" data-ani-underline>Branchez DictIA à votre stack existant.</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-brand-navy/70 mt-6">
|
||||||
|
Webhooks REST, plugin Word natif et connecteurs Zapier / Make / n8n auto-hébergés. API documentée — vous gardez le contrôle des flux.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- set icon_chat_box = '<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-4 h-4" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>' -%}
|
||||||
|
{%- set icon_book = '<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-4 h-4" aria-hidden="true"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V3H6.5A2.5 2.5 0 0 0 4 5.5z"/><path d="M4 19.5V21h16v-4"/></svg>' -%}
|
||||||
|
{%- set icon_gear = '<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-4 h-4" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1-1.5 1.7 1.7 0 0 0-1.9.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.9 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1 1.7 1.7 0 0 0-.3-1.9l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.9.3h.1a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.9-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.9v.1a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg>' -%}
|
||||||
|
|
||||||
|
{%- set integ_groups = [
|
||||||
|
{
|
||||||
|
'title': 'Communication',
|
||||||
|
'desc': 'Importez vos enregistrements depuis vos outils de réunion et de pratique.',
|
||||||
|
'icon': icon_chat_box,
|
||||||
|
'tools': [
|
||||||
|
{'name': 'Microsoft Teams', 'detail': 'Export depuis enregistrements'},
|
||||||
|
{'name': 'Microsoft Outlook','detail': 'Pièces jointes audio'},
|
||||||
|
{'name': 'Clio Manage', 'detail': 'Pour avocats'},
|
||||||
|
{'name': 'PCLaw', 'detail': 'Pour avocats'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': 'Knowledge / notes',
|
||||||
|
'desc': 'Synchronisez transcriptions et résumés vers vos bases de connaissances.',
|
||||||
|
'icon': icon_book,
|
||||||
|
'tools': [
|
||||||
|
{'name': 'Obsidian', 'detail': 'via Markdown'},
|
||||||
|
{'name': 'Notion', 'detail': 'via Markdown'},
|
||||||
|
{'name': 'Logseq', 'detail': 'via Markdown'},
|
||||||
|
{'name': 'Word', 'detail': 'via DOCX'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'title': 'Automatisation',
|
||||||
|
'desc': 'Déclenchez vos workflows à chaque transcription terminée.',
|
||||||
|
'icon': icon_gear,
|
||||||
|
'tools': [
|
||||||
|
{'name': 'Zapier', 'detail': 'No-code'},
|
||||||
|
{'name': 'Make (Integromat)','detail': 'Scénarios visuels'},
|
||||||
|
{'name': 'n8n', 'detail': 'Open source self-host'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
] -%}
|
||||||
|
|
||||||
|
<div class="grid md:grid-cols-3 gap-6">
|
||||||
|
{% for group in integ_groups %}
|
||||||
|
<div class="ani-fade bg-white p-6 rounded border border-brand-border" style="--delay: {{ loop.index0 * 80 }}ms;" data-ani-fade>
|
||||||
|
<div class="flex items-center gap-2 mb-2 text-brand-b1" aria-hidden="true">
|
||||||
|
{{ group.icon | safe }}
|
||||||
|
<span class="text-xs uppercase tracking-wider font-bold text-brand-navy">{{ group.title }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-brand-navy/70 mb-5">{{ group.desc }}</p>
|
||||||
|
<ul class="grid grid-cols-2 gap-2" role="list">
|
||||||
|
{% for t in group.tools %}
|
||||||
|
<li class="ani-lift bg-brand-bg border border-brand-border p-3 rounded">
|
||||||
|
<p class="text-sm font-semibold text-brand-navy font-mono leading-tight">{{ t.name }}</p>
|
||||||
|
<p class="text-[11px] text-brand-navy/60 mt-0.5">{{ t.detail }}</p>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-brand-navy/70 text-center mt-8 max-w-2xl mx-auto">
|
||||||
|
Microsoft, Notion, Obsidian, Logseq, Clio, PCLaw, Zapier, Make et n8n sont des marques de leurs propriétaires respectifs. DictIA n'est pas affilié à ces produits.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# ===== ARCHITECTURE & INFRASTRUCTURE ===== #}
|
||||||
|
<section id="architecture" class="relative bg-brand-navy text-white py-20 scroll-mt-32 overflow-hidden" aria-labelledby="architecture-title">
|
||||||
|
<div class="absolute top-1/2 right-1/4 w-[500px] h-[500px] rounded-full pointer-events-none" aria-hidden="true"
|
||||||
|
style="background: radial-gradient(circle, rgba(0,200,150,0.08) 0%, transparent 60%); filter: blur(60px);"></div>
|
||||||
|
|
||||||
|
<div class="relative max-w-[1200px] mx-auto px-6">
|
||||||
|
<div class="text-center max-w-3xl mx-auto mb-14">
|
||||||
|
<p class="eyebrow grad-text mb-4">ARCHITECTURE & INFRASTRUCTURE</p>
|
||||||
|
<h2 id="architecture-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black">
|
||||||
|
<span class="ani-underline" data-ani-underline>Trois formules selon votre cabinet.</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-white/70 mt-6">
|
||||||
|
DictIA 8 et 16 fonctionnent localement chez vous. DictIA Cloud tourne sur GPU NVIDIA L4 dédié à OVH Beauharnois (Québec). Toutes les formules incluent volume audio illimité, zéro frais par utilisateur.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{%- set tiers = [
|
||||||
|
{
|
||||||
|
'name': 'DictIA 8',
|
||||||
|
'tagline': 'Petit cabinet, mode local',
|
||||||
|
'gpu': 'RTX 8 Go',
|
||||||
|
'users': '2 à 5 utilisateurs',
|
||||||
|
'setup': '3 450 $',
|
||||||
|
'monthly': '173 $',
|
||||||
|
'host': 'Local chez vous',
|
||||||
|
'llm': 'Mistral 7B non inclus',
|
||||||
|
'recommended': False,
|
||||||
|
'features': ['Transcription WhisperX FR-CA', 'Diarisation 8 locuteurs', 'Exports DOCX, PDF, SRT, VTT, TXT, JSON, MD', 'Synchronisation audio-texte', 'Admissible achat direct gouv. (≤ 34 700 $)']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'DictIA 16',
|
||||||
|
'tagline': 'Cabinet moyen, IA locale complète',
|
||||||
|
'gpu': 'RTX 16 Go',
|
||||||
|
'users': '5 à 15 utilisateurs',
|
||||||
|
'setup': '5 750 $',
|
||||||
|
'monthly': '201 $',
|
||||||
|
'host': 'Local chez vous',
|
||||||
|
'llm': 'Mistral 7B inclus',
|
||||||
|
'recommended': False,
|
||||||
|
'features': ['Tout DictIA 8', 'Résumés Mistral 7B local', 'Chat Q&R sur enregistrement', 'Recherche sémantique', 'Templates avocat · notaire · CPA · médecin']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'DictIA Cloud',
|
||||||
|
'tagline': 'Multi-sites, infra gérée',
|
||||||
|
'gpu': 'NVIDIA L4 dédié',
|
||||||
|
'users': 'Utilisateurs illimités',
|
||||||
|
'setup': '—',
|
||||||
|
'monthly': '369 $',
|
||||||
|
'host': 'OVH Beauharnois (QC)',
|
||||||
|
'llm': 'Mistral 7B inclus',
|
||||||
|
'recommended': True,
|
||||||
|
'features': ['Tout DictIA 16', 'Aucune infrastructure à gérer', 'Mises à jour automatiques', 'Hébergé au Québec (OVH)', 'Multi-sites et télétravail']
|
||||||
|
}
|
||||||
|
] -%}
|
||||||
|
|
||||||
|
<div class="grid md:grid-cols-3 gap-6 items-stretch">
|
||||||
|
{% for tier in tiers %}
|
||||||
|
<article class="ani-fade {% if tier.recommended %}card-pulse-glow grad-bg p-[1.5px] rounded{% endif %} relative h-full"
|
||||||
|
style="--delay: {{ loop.index0 * 100 }}ms;"
|
||||||
|
data-ani-fade>
|
||||||
|
{% if tier.recommended %}
|
||||||
|
<span class="absolute -top-3 left-1/2 -translate-x-1/2 grad-bg text-white text-xs font-bold px-3 py-1 rounded-full inline-flex items-center gap-1.5 z-10">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-3 h-3" aria-hidden="true"><path d="M12 2l2.9 6.9L22 10l-5.5 4.8L18 22l-6-3.6L6 22l1.5-7.2L2 10l7.1-1.1z"/></svg>
|
||||||
|
RECOMMANDÉ
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
<div class="bg-brand-navy2 p-6 rounded border border-white/[0.08] h-full flex flex-col">
|
||||||
|
<header class="mb-4 pb-4 border-b border-white/[0.08]">
|
||||||
|
<h3 class="text-xl font-black mb-1 text-white">{{ tier.name }}</h3>
|
||||||
|
<p class="text-xs uppercase tracking-wider text-white/60">{{ tier.tagline }}</p>
|
||||||
|
</header>
|
||||||
|
<dl class="grid grid-cols-2 gap-x-4 gap-y-2 mb-5 text-xs">
|
||||||
|
<dt class="text-white/60">GPU</dt><dd class="font-mono text-white">{{ tier.gpu | safe }}</dd>
|
||||||
|
<dt class="text-white/60">Utilisateurs</dt><dd class="text-white">{{ tier.users }}</dd>
|
||||||
|
<dt class="text-white/60">Hébergement</dt><dd class="text-white">{{ tier.host }}</dd>
|
||||||
|
<dt class="text-white/60">LLM résumés</dt><dd class="text-white">{{ tier.llm }}</dd>
|
||||||
|
</dl>
|
||||||
|
<div class="mb-5 pb-5 border-b border-white/[0.08]">
|
||||||
|
{% if tier.setup != '—' %}
|
||||||
|
<div class="text-3xl font-black grad-text leading-none">{{ tier.setup | safe }}</div>
|
||||||
|
<div class="text-xs text-white/60 mt-1">setup unique + {{ tier.monthly | safe }} / mois</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-3xl font-black grad-text leading-none">{{ tier.monthly | safe }}</div>
|
||||||
|
<div class="text-xs text-white/60 mt-1">par mois · sans frais de setup</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<ul class="space-y-2 mb-6 flex-grow text-sm" role="list">
|
||||||
|
{% for feat in tier.features %}
|
||||||
|
<li class="flex items-start gap-2 text-white/80">
|
||||||
|
{{ icon_check | safe }}
|
||||||
|
<span>{{ feat | safe }}</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% from 'macros/button.html' import button %}
|
||||||
|
{{ button('Voir le détail tarifs', href='/tarifs', variant='primary' if tier.recommended else 'ghost', size='md') }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Bloc inclus dans setup local #}
|
||||||
|
<div class="mt-12 max-w-4xl mx-auto bg-white/[0.05] backdrop-blur-sm p-6 rounded border border-white/[0.08]">
|
||||||
|
<p class="eyebrow grad-text mb-3">INCLUS DANS LE SETUP LOCAL (DICTIA 8 & 16)</p>
|
||||||
|
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3 text-sm" role="list">
|
||||||
|
{% for inc in [
|
||||||
|
'Fourniture du PC + GPU',
|
||||||
|
'Configuration complète',
|
||||||
|
'Installation sur site',
|
||||||
|
'Formation équipe (2–3 h)',
|
||||||
|
'Support démarrage 30 jours'
|
||||||
|
] %}
|
||||||
|
<li class="flex items-start gap-2 text-white/80">
|
||||||
|
<span class="text-brand-b3 mt-0.5" aria-hidden="true">{{ icon_check | safe }}</span>
|
||||||
|
<span>{{ inc | safe }}</span>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-xs text-white/60 text-center mt-6 max-w-2xl mx-auto">
|
||||||
|
DictIA 8 est admissible à l'achat direct gouvernemental sans appel d'offres (seuil 34 700 $ — Règlement sur les contrats d'approvisionnement, art. 15).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# ===== EXPORT FORMATS DEEP-DIVE (test compat) ===== #}
|
||||||
|
<section class="bg-white py-16" aria-labelledby="exports-title">
|
||||||
|
<div class="max-w-[1200px] mx-auto px-6">
|
||||||
|
<div class="text-center max-w-2xl mx-auto mb-10">
|
||||||
|
<p class="eyebrow grad-text mb-3">FORMATS D'EXPORT</p>
|
||||||
|
<h2 id="exports-title" class="text-[clamp(1.75rem,2.5vw,2.25rem)] font-black text-brand-navy">
|
||||||
7 formats, prêts pour vos workflows.
|
7 formats, prêts pour vos workflows.
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,8 +472,8 @@
|
|||||||
{'ext': 'JSON', 'use': 'Pipeline développeur'},
|
{'ext': 'JSON', 'use': 'Pipeline développeur'},
|
||||||
{'ext': 'MD', 'use': 'Notion, Obsidian, GitHub'}
|
{'ext': 'MD', 'use': 'Notion, Obsidian, GitHub'}
|
||||||
] %}
|
] %}
|
||||||
<div class="bg-white p-4 rounded border border-brand-border text-center">
|
<div class="ani-lift bg-brand-bg p-4 rounded border border-brand-border text-center">
|
||||||
<p class="text-base font-black text-brand-navy">{{ fmt.ext }}</p>
|
<p class="text-base font-black font-mono text-brand-navy">{{ fmt.ext }}</p>
|
||||||
<p class="text-xs text-brand-navy/70 mt-1">{{ fmt.use | safe }}</p>
|
<p class="text-xs text-brand-navy/70 mt-1">{{ fmt.use | safe }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -71,19 +481,77 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# ===== INTEGRATIONS GRID ===== #}
|
{# ===== TECH SPECS (préservé pour rétro-compat tests) ===== #}
|
||||||
<section class="bg-white py-20" aria-labelledby="integrations-title">
|
<section class="bg-brand-bg py-16" aria-labelledby="specs-title">
|
||||||
<div class="max-w-[1200px] mx-auto px-6">
|
<div class="max-w-[1060px] mx-auto px-6">
|
||||||
<div class="text-center max-w-2xl mx-auto mb-12">
|
<div class="text-center max-w-2xl mx-auto mb-10">
|
||||||
<p class="eyebrow grad-text mb-4">INTÉGRATIONS</p>
|
<p class="eyebrow grad-text mb-3">SOUS LE CAPOT</p>
|
||||||
<h2 id="integrations-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4 text-brand-navy">
|
<h2 id="specs-title" class="text-[clamp(1.75rem,2.5vw,2.25rem)] font-black text-brand-navy">
|
||||||
Branchez DictIA à votre stack existant.
|
Spécifications techniques détaillées.
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-base text-brand-navy/70">
|
</div>
|
||||||
Webhooks REST, plugin Word natif, connecteurs Zapier/Make/n8n. API documentée — auto-hébergée avec votre déploiement.
|
<div class="grid md:grid-cols-2 gap-4">
|
||||||
|
{% for spec in [
|
||||||
|
{'title': 'Modèle ASR', 'desc': 'WhisperX Large-v3 (1,55 G paramètres) fine-tuné sur audio professionnel québécois. Format ONNX optimisé GPU.'},
|
||||||
|
{'title': 'Diarisation', 'desc': 'pyannote 3.x — clustering hiérarchique sur embeddings ECAPA-TDNN. 1 à 8 locuteurs détectés automatiquement.'},
|
||||||
|
{'title': 'LLM (résumés / Q&R)', 'desc': 'Mistral 7B Instruct quantifié 4-bit. Inférence locale sur le même GPU. Aucune sortie réseau.'},
|
||||||
|
{'title': 'Stack web', 'desc': 'Flask 2.3 (backend) + Vue 3 / Alpine.js (front). Chiffrement AES-256 au repos. AGPL v3.'},
|
||||||
|
{'title': 'Audio supportés (WAV, MP3, M4A, FLAC, OGG, WebM)', 'desc': 'Jusqu\'à 8 h par fichier. Conversion ffmpeg automatique. Compatible enregistrements Zoom et Teams.'},
|
||||||
|
{'title': 'Langues', 'desc': 'Optimisé français québécois. Aussi : français de France, anglais (canadien et US), espagnol, allemand, mandarin, russe.'}
|
||||||
|
] %}
|
||||||
|
<article class="ani-fade ani-lift bg-white p-5 rounded border border-brand-border" style="--delay: {{ loop.index0 * 50 }}ms;" data-ani-fade>
|
||||||
|
<h3 class="text-base font-bold mb-2 text-brand-navy">{{ spec.title | safe }}</h3>
|
||||||
|
<p class="text-sm text-brand-navy/70 leading-relaxed">{{ spec.desc | safe }}</p>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# ===== CONFORMITÉ — RÉSUMÉ ===== #}
|
||||||
|
<section id="conformite-resume" class="bg-white py-20 scroll-mt-32" aria-labelledby="conformite-resume-title">
|
||||||
|
<div class="max-w-[1060px] mx-auto px-6">
|
||||||
|
<div class="text-center max-w-3xl mx-auto mb-10">
|
||||||
|
<p class="eyebrow grad-text mb-4">CONFORMITÉ</p>
|
||||||
|
<h2 id="conformite-resume-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black text-brand-navy">
|
||||||
|
<span class="ani-underline" data-ani-underline>Conforme par construction.</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-lg text-brand-navy/70 mt-6">
|
||||||
|
Architecture pensée d'abord pour la Loi 25 et les ordres professionnels québécois — pas une certification ajoutée après coup.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
||||||
|
<ul class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-10" role="list">
|
||||||
|
{% for chip in [
|
||||||
|
{'title': 'Loi 25', 'desc': 'La voix est biométrique — le traitement local élimine le risque.'},
|
||||||
|
{'title': 'Loi 96', 'desc': 'Interface, documentation et support 100 % français.'},
|
||||||
|
{'title': '9 ordres pros', 'desc': 'Mappé Barreau, CNQ, CPA, ChAD, OACIQ, CMQ, OIIQ, OPQ, OEQ.'},
|
||||||
|
{'title': '0 Cloud Act US', 'desc': 'Aucun fournisseur soumis à la juridiction américaine.'}
|
||||||
|
] %}
|
||||||
|
<li class="ani-fade ani-lift bg-brand-bg p-5 rounded border border-brand-border" style="--delay: {{ loop.index0 * 60 }}ms;" data-ani-fade>
|
||||||
|
<span class="inline-flex items-center gap-1.5 bg-brand-navy text-white text-xs font-black uppercase tracking-wider px-2.5 py-1 rounded-full mb-3">
|
||||||
|
<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-3 h-3" aria-hidden="true"><path d="M5 13l4 4L19 7"/></svg>
|
||||||
|
{{ chip.title | safe }}
|
||||||
|
</span>
|
||||||
|
<p class="text-sm text-brand-navy/80 leading-relaxed">{{ chip.desc | safe }}</p>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="/conformite" class="inline-flex items-center gap-2 text-base font-semibold grad-text hover:underline focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2">
|
||||||
|
Voir le détail conformité
|
||||||
|
{{ icon_link | safe }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{# ===== INTEGRATIONS GRID (compat tests + plugin partner list) ===== #}
|
||||||
|
<section class="bg-brand-bg py-12" aria-labelledby="integrations-grid-title">
|
||||||
|
<div class="max-w-[1200px] mx-auto px-6">
|
||||||
|
<h2 id="integrations-grid-title" class="sr-only">Liste détaillée des intégrations partenaires</h2>
|
||||||
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-3" role="list">
|
||||||
{% for integ in [
|
{% for integ in [
|
||||||
{'name': 'Microsoft Word', 'desc': 'Plugin natif (.docx)'},
|
{'name': 'Microsoft Word', 'desc': 'Plugin natif (.docx)'},
|
||||||
{'name': 'Microsoft Outlook','desc': 'Pièces jointes audio'},
|
{'name': 'Microsoft Outlook','desc': 'Pièces jointes audio'},
|
||||||
@@ -94,60 +562,55 @@
|
|||||||
{'name': 'Make (Integromat)','desc': 'Scénarios visuels'},
|
{'name': 'Make (Integromat)','desc': 'Scénarios visuels'},
|
||||||
{'name': 'n8n', 'desc': 'Open source self-host'}
|
{'name': 'n8n', 'desc': 'Open source self-host'}
|
||||||
] %}
|
] %}
|
||||||
<div class="bg-brand-bg p-5 rounded border border-brand-border text-center">
|
<div class="bg-white p-4 rounded border border-brand-border text-center" role="listitem">
|
||||||
<p class="text-base font-bold text-brand-navy">{{ integ.name | safe }}</p>
|
<p class="text-sm font-bold text-brand-navy font-mono">{{ integ.name | safe }}</p>
|
||||||
<p class="text-xs text-brand-navy/70 mt-1">{{ integ.desc | safe }}</p>
|
<p class="text-xs text-brand-navy/70 mt-1">{{ integ.desc | safe }}</p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xs text-brand-navy/70 text-center mt-6">
|
|
||||||
Microsoft, Notion, Obsidian, Zapier, Make et n8n sont des marques de leurs propriétaires respectifs. DictIA n'est pas affilié à ces produits.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{# ===== TECH SPECS ===== #}
|
{# ===== CTA FINAL ===== #}
|
||||||
<section class="bg-brand-navy text-white py-20" aria-labelledby="specs-title">
|
<section class="bg-white py-20 border-t border-brand-border" aria-labelledby="features-cta-title">
|
||||||
<div class="max-w-[1060px] mx-auto px-6">
|
|
||||||
<div class="text-center max-w-2xl mx-auto mb-12">
|
|
||||||
<p class="eyebrow grad-text mb-4">SPÉCIFICATIONS TECHNIQUES</p>
|
|
||||||
<h2 id="specs-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4">
|
|
||||||
Sous le capot.
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div class="grid md:grid-cols-2 gap-6">
|
|
||||||
{% for spec in [
|
|
||||||
{'title': 'Modèle ASR', 'desc': 'WhisperX Large-v3 (1,55 G paramètres) fine-tuné sur audio professionnel québécois. Format ONNX optimisé GPU.'},
|
|
||||||
{'title': 'Diarisation', 'desc': 'pyannote 3.x — clustering hiérarchique sur embeddings ECAPA-TDNN. 1 à 8 locuteurs détectés automatiquement.'},
|
|
||||||
{'title': 'LLM (résumés / Q&R)', 'desc': 'Mistral 7B Instruct quantifié 4-bit. Inférence locale sur le même GPU. Aucune sortie réseau.'},
|
|
||||||
{'title': 'Stack web', 'desc': 'Flask 2.3 (backend) + Vue 3 / Alpine.js (front). Chiffrement AES-256 au repos. AGPL v3.'},
|
|
||||||
{'title': 'Audio supportés', 'desc': 'WAV, MP3, M4A, FLAC, OGG, WebM — jusqu\'à 8 h par fichier. Conversion ffmpeg automatique.'},
|
|
||||||
{'title': 'Langues', 'desc': 'Optimisé français québécois. Aussi : français de France, anglais (canadien et US), espagnol, allemand, mandarin, russe.'}
|
|
||||||
] %}
|
|
||||||
<article class="bg-white/[0.05] backdrop-blur-sm p-6 rounded border border-white/[0.08]">
|
|
||||||
<h3 class="text-lg font-bold mb-2 text-white">{{ spec.title | safe }}</h3>
|
|
||||||
<p class="text-sm text-white/80 leading-relaxed">{{ spec.desc | safe }}</p>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{# ===== CTA ===== #}
|
|
||||||
<section class="bg-brand-bg py-20" aria-labelledby="features-cta-title">
|
|
||||||
<div class="max-w-[820px] mx-auto px-6 text-center">
|
<div class="max-w-[820px] mx-auto px-6 text-center">
|
||||||
<h2 id="features-cta-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-6 text-brand-navy">
|
<p class="eyebrow grad-text mb-4">PRÊT À TRANSCRIRE EN LOCAL</p>
|
||||||
Prêt à <span class="grad-text">essayer DictIA</span> ?
|
<h2 id="features-cta-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-5 text-brand-navy">
|
||||||
|
Prêt à transcrire <span class="grad-text">en local</span> ?
|
||||||
</h2>
|
</h2>
|
||||||
<p class="text-lg text-brand-navy/80 mb-8">
|
<p class="text-lg text-brand-navy/70 mb-10">
|
||||||
Lancement printemps 2026. Inscrivez-vous pour figurer sur la liste prioritaire.
|
Lancement printemps 2026 — pré-inscription ouverte. Conçu avec 9 ordres professionnels québécois.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
<div class="flex flex-col sm:flex-row gap-3 justify-center">
|
||||||
{% from 'macros/button.html' import button %}
|
{% from 'macros/button.html' import button %}
|
||||||
{{ button('Pré-inscription par courriel', href='mailto:info@dictia.ca?subject=Pré-inscription%20DictIA', variant='primary', size='lg', icon='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>') }}
|
{{ button('Voir les tarifs', href='/tarifs', variant='primary', size='lg', icon='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4" aria-hidden="true"><path d="M14 5l7 7m0 0l-7 7m7-7H3"/></svg>') }}
|
||||||
{{ button('Voir les tarifs', href='/tarifs', variant='secondary', size='lg') }}
|
{{ button('Demander une démo', href='/contact', variant='secondary', size='lg') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{# ===== JS — IntersectionObserver pour ani-fade + ani-underline ===== #}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
if (typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') return;
|
||||||
|
var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||||
|
var fadeEls = document.querySelectorAll('[data-ani-fade]');
|
||||||
|
var underlineEls = document.querySelectorAll('[data-ani-underline]');
|
||||||
|
if (reduced) {
|
||||||
|
fadeEls.forEach(function (el) { el.classList.add('is-visible'); });
|
||||||
|
underlineEls.forEach(function (el) { el.classList.add('is-visible'); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var io = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (e) {
|
||||||
|
if (!e.isIntersecting) return;
|
||||||
|
e.target.classList.add('is-visible');
|
||||||
|
io.unobserve(e.target);
|
||||||
|
});
|
||||||
|
}, { threshold: 0.15, rootMargin: '0px 0px -80px 0px' });
|
||||||
|
fadeEls.forEach(function (el) { io.observe(el); });
|
||||||
|
underlineEls.forEach(function (el) { io.observe(el); });
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user