polish(marketing): refonte HYPER PRO 'Comment ça marche' — purge non-brand hex + uniformization typo/spacing

Refactor mécanique strict :
- Purge 100% des hex non-brand (#0891b2, #a21caf, #e879f9, #1d4ed8, #9333ea, #f5d0fe, #67e8f9, #1e40af, #93c5fd, #9CA3AF, #0e7490, #EF4444 capital) → mapping vers brand-b1/b2/b3
- Standardisation tailles : 0 inline font-size, text-[9px/10px/11px] uniquement (purge 5.5/6/6.5/7/7.5/8/8.5 arbitraires)
- 0 font-family inline (utilise font-sans/font-mono Tailwind)

Polish device :
- Inner screen seam (effet "écran encastré dans bezel")
- Notch : intègre speaker grille 3 dots + camera dot dans la dynamic island
- Status bar : vraie batterie 80% fill, vrai WiFi 3 arcs concentriques + dot, signal 4 bars croissantes
- Logo DictIA 92×28 plus grand (opacité 85%)

Polish modes :
- Mode 1 : header compact mic+filename+REC, waveform 16 bars symétriques, file card MP3 redesign avec corner fold
- Mode 2 : avatars empilés 18×18 avec bordure white/15, bubbles max-width 80%, timestamps text-[9px]
- Mode 3 : grille langues text-[10px] line-height 18px, padding 8px, palette stricte b1/b2/b3
- Mode 4 : grid 4×2 cards 42×50, drop staggered 90ms, palette stricte b1/b2/b3 + dc2626 PDF + 374151 TXT
- Mode 5 : header counter Inter font-black text-base, connecting lines opacité 0.18
- Mode 6 : breadcrumb compact, toolbar 4 icons, hover row highlight, palette b1/b2/b3
- Mode 0 : chat bubbles uniformisés text-[10px], footer shield emerald (sécurité)

Polish right panel IA :
- Brain 40×40 cercle gradient brand-b3 (déjà OK)
- Badges Mistral 7B (b3 bg) + LOCAL (emerald bg)
- 3 metrics : 0ms grad-text · 100% emerald · 24/7 grad-text font-black text-lg
- Sovereignty bullets : icon dans cercle 20×20 rounded-full bg-brand-b3/[0.15]
- Padding p-5 généreux

Polish feature info card sous phone :
- Background uniforme bg-white/[0.06] + border-white/[0.10]
- Border-left 3px accent activeColor (style tab indicator)
- Icon container 32×32 rounded-md
- Badge top-right text-[10px] tracking-wider

Polish bottom tab bar :
- Buttons 34×42, gap-1 serré
- Active : bottom border 2px + scale icon 1.15 + drop-shadow color
- Labels text-[9px] uppercase tracking-wider
- AUTO pill : px-2.5 py-0.5 rounded-full bg-emerald/12

Tests :
- +6 assertions polish (forbidden hex purge, screen seam, white/0.06, brand-b3/[0.15], grad-text)
- 9/9 fonctionnalites tests pass
- 29/29 marketing tests pass (2 conformite failures pré-existantes baseline)

Build : npm run build:css → static/css/marketing.css régénéré pour les nouvelles classes arbitraires

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Allison
2026-04-29 10:49:47 -04:00
parent d6ff71640a
commit 7d3348c3fd
3 changed files with 426 additions and 296 deletions

View File

@@ -363,6 +363,12 @@
.-inset-1 { .-inset-1 {
inset: calc(var(--spacing) * -1); inset: calc(var(--spacing) * -1);
} }
.-inset-2 {
inset: calc(var(--spacing) * -2);
}
.-inset-3 {
inset: calc(var(--spacing) * -3);
}
.inset-0 { .inset-0 {
inset: calc(var(--spacing) * 0); inset: calc(var(--spacing) * 0);
} }
@@ -525,6 +531,9 @@
.left-0\.5 { .left-0\.5 {
left: calc(var(--spacing) * 0.5); left: calc(var(--spacing) * 0.5);
} }
.left-1\.5 {
left: calc(var(--spacing) * 1.5);
}
.left-1\/2 { .left-1\/2 {
left: calc(1 / 2 * 100%); left: calc(1 / 2 * 100%);
} }
@@ -771,6 +780,9 @@
.ml-auto { .ml-auto {
margin-left: auto; margin-left: auto;
} }
.ml-px {
margin-left: 1px;
}
.block { .block {
display: block; display: block;
} }
@@ -984,9 +996,6 @@
.min-h-\[110px\] { .min-h-\[110px\] {
min-height: 110px; min-height: 110px;
} }
.min-h-\[480px\] {
min-height: 480px;
}
.min-h-\[calc\(100vh-62px\)\] { .min-h-\[calc\(100vh-62px\)\] {
min-height: calc(100vh - 62px); min-height: calc(100vh - 62px);
} }
@@ -1143,9 +1152,6 @@
.max-w-\[300px\] { .max-w-\[300px\] {
max-width: 300px; max-width: 300px;
} }
.max-w-\[320px\] {
max-width: 320px;
}
.max-w-\[820px\] { .max-w-\[820px\] {
max-width: 820px; max-width: 820px;
} }
@@ -1248,10 +1254,6 @@
--tw-translate-y: calc(var(--spacing) * 0); --tw-translate-y: calc(var(--spacing) * 0);
translate: var(--tw-translate-x) var(--tw-translate-y); translate: var(--tw-translate-x) var(--tw-translate-y);
} }
.translate-y-1 {
--tw-translate-y: calc(var(--spacing) * 1);
translate: var(--tw-translate-x) var(--tw-translate-y);
}
.translate-y-2 { .translate-y-2 {
--tw-translate-y: calc(var(--spacing) * 2); --tw-translate-y: calc(var(--spacing) * 2);
translate: var(--tw-translate-x) var(--tw-translate-y); translate: var(--tw-translate-x) var(--tw-translate-y);
@@ -1376,6 +1378,12 @@
.flex-wrap { .flex-wrap {
flex-wrap: wrap; flex-wrap: wrap;
} }
.content-center {
align-content: center;
}
.content-start {
align-content: flex-start;
}
.items-baseline { .items-baseline {
align-items: baseline; align-items: baseline;
} }
@@ -1403,6 +1411,12 @@
.justify-start { .justify-start {
justify-content: flex-start; justify-content: flex-start;
} }
.justify-items-center {
justify-items: center;
}
.gap-0 {
gap: calc(var(--spacing) * 0);
}
.gap-0\.5 { .gap-0\.5 {
gap: calc(var(--spacing) * 0.5); gap: calc(var(--spacing) * 0.5);
} }
@@ -1514,6 +1528,10 @@
-moz-column-gap: calc(var(--spacing) * 6); -moz-column-gap: calc(var(--spacing) * 6);
column-gap: calc(var(--spacing) * 6); column-gap: calc(var(--spacing) * 6);
} }
.gap-x-8 {
-moz-column-gap: calc(var(--spacing) * 8);
column-gap: calc(var(--spacing) * 8);
}
.space-x-1 { .space-x-1 {
:where(& > :not(:last-child)) { :where(& > :not(:last-child)) {
--tw-space-x-reverse: 0; --tw-space-x-reverse: 0;
@@ -1555,6 +1573,9 @@
.gap-y-2 { .gap-y-2 {
row-gap: calc(var(--spacing) * 2); row-gap: calc(var(--spacing) * 2);
} }
.gap-y-3 {
row-gap: calc(var(--spacing) * 3);
}
.divide-y { .divide-y {
:where(& > :not(:last-child)) { :where(& > :not(:last-child)) {
--tw-divide-y-reverse: 0; --tw-divide-y-reverse: 0;
@@ -1655,6 +1676,10 @@
border-style: var(--tw-border-style); border-style: var(--tw-border-style);
border-width: 2px; border-width: 2px;
} }
.border-\[1\.5px\] {
border-style: var(--tw-border-style);
border-width: 1.5px;
}
.border-\[3px\] { .border-\[3px\] {
border-style: var(--tw-border-style); border-style: var(--tw-border-style);
border-width: 3px; border-width: 3px;
@@ -1797,6 +1822,9 @@
.border-brand-b3\/20 { .border-brand-b3\/20 {
border-color: color-mix(in oklab, #c026d3 20%, transparent); border-color: color-mix(in oklab, #c026d3 20%, transparent);
} }
.border-brand-b3\/30 {
border-color: color-mix(in oklab, #c026d3 30%, transparent);
}
.border-brand-b3\/60 { .border-brand-b3\/60 {
border-color: color-mix(in oklab, #c026d3 60%, transparent); border-color: color-mix(in oklab, #c026d3 60%, transparent);
} }
@@ -2127,6 +2155,9 @@
.bg-brand-b3\/\[0\.08\] { .bg-brand-b3\/\[0\.08\] {
background-color: color-mix(in oklab, #c026d3 8%, transparent); background-color: color-mix(in oklab, #c026d3 8%, transparent);
} }
.bg-brand-b3\/\[0\.15\] {
background-color: color-mix(in oklab, #c026d3 15%, transparent);
}
.bg-brand-bg { .bg-brand-bg {
background-color: #f7f9fc; background-color: #f7f9fc;
} }
@@ -2753,6 +2784,9 @@
.pb-0 { .pb-0 {
padding-bottom: calc(var(--spacing) * 0); padding-bottom: calc(var(--spacing) * 0);
} }
.pb-1 {
padding-bottom: calc(var(--spacing) * 1);
}
.pb-2 { .pb-2 {
padding-bottom: calc(var(--spacing) * 2); padding-bottom: calc(var(--spacing) * 2);
} }
@@ -2859,12 +2893,21 @@
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-\[6\.5px\] {
font-size: 6.5px;
}
.text-\[6px\] { .text-\[6px\] {
font-size: 6px; font-size: 6px;
} }
.text-\[7\.5px\] {
font-size: 7.5px;
}
.text-\[7px\] { .text-\[7px\] {
font-size: 7px; font-size: 7px;
} }
.text-\[8\.5px\] {
font-size: 8.5px;
}
.text-\[8px\] { .text-\[8px\] {
font-size: 8px; font-size: 8px;
} }
@@ -2966,10 +3009,6 @@
--tw-tracking: 0.10em; --tw-tracking: 0.10em;
letter-spacing: 0.10em; letter-spacing: 0.10em;
} }
.tracking-\[0\.14em\] {
--tw-tracking: 0.14em;
letter-spacing: 0.14em;
}
.tracking-\[0\.16em\] { .tracking-\[0\.16em\] {
--tw-tracking: 0.16em; --tw-tracking: 0.16em;
letter-spacing: 0.16em; letter-spacing: 0.16em;
@@ -3019,6 +3058,9 @@
.whitespace-nowrap { .whitespace-nowrap {
white-space: nowrap; white-space: nowrap;
} }
.whitespace-pre-line {
white-space: pre-line;
}
.whitespace-pre-wrap { .whitespace-pre-wrap {
white-space: pre-wrap; white-space: pre-wrap;
} }
@@ -3118,6 +3160,9 @@
.text-brand-b1 { .text-brand-b1 {
color: #2563eb; color: #2563eb;
} }
.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);
} }
@@ -3373,6 +3418,12 @@
color: color-mix(in oklab, var(--color-white) 85%, transparent); color: color-mix(in oklab, var(--color-white) 85%, transparent);
} }
} }
.text-white\/90 {
color: color-mix(in srgb, #fff 90%, transparent);
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, var(--color-white) 90%, transparent);
}
}
.text-yellow-400 { .text-yellow-400 {
color: var(--color-yellow-400); color: var(--color-yellow-400);
} }
@@ -3641,6 +3692,10 @@
--tw-ease: var(--ease-out); --tw-ease: var(--ease-out);
transition-timing-function: var(--ease-out); transition-timing-function: var(--ease-out);
} }
.outline-none {
--tw-outline-style: none;
outline-style: none;
}
.select-all { .select-all {
-webkit-user-select: all; -webkit-user-select: all;
-moz-user-select: all; -moz-user-select: all;
@@ -4696,6 +4751,25 @@
outline-style: none; outline-style: none;
} }
} }
.focus-visible\:ring-2 {
&:focus-visible {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
}
.focus-visible\:ring-brand-b1 {
&:focus-visible {
--tw-ring-color: #2563eb;
}
}
.focus-visible\:ring-white\/40 {
&:focus-visible {
--tw-ring-color: color-mix(in srgb, #fff 40%, transparent);
@supports (color: color-mix(in lab, red, red)) {
--tw-ring-color: color-mix(in oklab, var(--color-white) 40%, transparent);
}
}
}
.focus-visible\:outline { .focus-visible\:outline {
&:focus-visible { &:focus-visible {
outline-style: var(--tw-outline-style); outline-style: var(--tw-outline-style);
@@ -5084,12 +5158,6 @@
text-align: right; text-align: right;
} }
} }
.sm\:text-6xl {
@media (width >= 40rem) {
font-size: var(--text-6xl);
line-height: var(--tw-leading, var(--text-6xl--line-height));
}
}
.sm\:text-base { .sm\:text-base {
@media (width >= 40rem) { @media (width >= 40rem) {
font-size: var(--text-base); font-size: var(--text-base);
@@ -5442,6 +5510,16 @@
width: calc(2 / 3 * 100%); width: calc(2 / 3 * 100%);
} }
} }
.lg\:w-\[280px\] {
@media (width >= 64rem) {
width: 280px;
}
}
.lg\:w-\[320px\] {
@media (width >= 64rem) {
width: 320px;
}
}
.lg\:w-auto { .lg\:w-auto {
@media (width >= 64rem) { @media (width >= 64rem) {
width: auto; width: auto;
@@ -5483,11 +5561,6 @@
grid-template-columns: 1fr 240px; grid-template-columns: 1fr 240px;
} }
} }
.lg\:grid-cols-\[1fr_minmax\(0\,360px\)\] {
@media (width >= 64rem) {
grid-template-columns: 1fr minmax(0,360px);
}
}
.lg\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,420px\)\] { .lg\:grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,420px\)\] {
@media (width >= 64rem) { @media (width >= 64rem) {
grid-template-columns: minmax(0,1fr) minmax(0,420px); grid-template-columns: minmax(0,1fr) minmax(0,420px);
@@ -5498,6 +5571,16 @@
flex-direction: row; flex-direction: row;
} }
} }
.lg\:items-start {
@media (width >= 64rem) {
align-items: flex-start;
}
}
.lg\:justify-center {
@media (width >= 64rem) {
justify-content: center;
}
}
.lg\:gap-10 { .lg\:gap-10 {
@media (width >= 64rem) { @media (width >= 64rem) {
gap: calc(var(--spacing) * 10); gap: calc(var(--spacing) * 10);

View File

@@ -260,11 +260,11 @@
/* ============ DECORATIVE BACKGROUND ============ */ /* ============ DECORATIVE BACKGROUND ============ */
.dictia-section-grid { .dictia-section-grid {
background-image: background-image:
linear-gradient(to right, rgba(15,23,42,0.04) 1px, transparent 1px), linear-gradient(to right, rgba(15,23,42,0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(15,23,42,0.04) 1px, transparent 1px); linear-gradient(to bottom, rgba(15,23,42,0.05) 1px, transparent 1px);
background-size: 60px 60px; background-size: 56px 56px;
mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 0%, transparent 70%); mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 0%, transparent 75%);
-webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 0%, transparent 70%); -webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 50%, black 0%, transparent 75%);
} }
.dictia-orb-float-1 { animation: dictia-orb-1 14s ease-in-out infinite; will-change: transform; } .dictia-orb-float-1 { animation: dictia-orb-1 14s ease-in-out infinite; will-change: transform; }
.dictia-orb-float-2 { animation: dictia-orb-2 18s ease-in-out infinite; will-change: transform; } .dictia-orb-float-2 { animation: dictia-orb-2 18s ease-in-out infinite; will-change: transform; }
@@ -277,16 +277,26 @@
position: relative; position: relative;
will-change: box-shadow, border-color; will-change: box-shadow, border-color;
} }
/* Inner screen border : effet "écran encastré" subtle entre bezel et écran */
.dictia-phone-shell::before { .dictia-phone-shell::before {
content: ''; content: '';
position: absolute; position: absolute;
inset: 2px; inset: 2px;
border-radius: 42px; border-radius: 42px;
border: 1px solid rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.05);
pointer-events: none; pointer-events: none;
background: linear-gradient(180deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0) 30%); background: linear-gradient(180deg, rgba(255,255,255,0.06) 0%, rgba(255,255,255,0) 28%);
z-index: 0; z-index: 0;
} }
/* Inner screen seam : ligne 1px entre bezel + écran (look device authentique) */
.dictia-phone-screen-seam {
position: absolute;
inset: 6px;
border-radius: 38px;
pointer-events: none;
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.04), inset 0 1px 0 0 rgba(255,255,255,0.06);
z-index: 1;
}
.dictia-phone-glow-ring { animation: dictia-glow-ring 3.6s ease-in-out infinite; will-change: opacity; } .dictia-phone-glow-ring { animation: dictia-glow-ring 3.6s ease-in-out infinite; will-change: opacity; }
@keyframes dictia-glow-ring { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.7; } } @keyframes dictia-glow-ring { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.7; } }
@@ -442,21 +452,19 @@
} }
</style> </style>
{# Decorative background : grid + floating orbs (desktop only) #} {# Decorative background : grid + floating orbs (desktop only) — brand-b1/b3 only #}
<div class="dictia-bg-grid absolute inset-0 dictia-section-grid pointer-events-none" aria-hidden="true"></div> <div class="dictia-bg-grid absolute inset-0 dictia-section-grid pointer-events-none" aria-hidden="true"></div>
<div class="dictia-bg-orbs absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true"> <div class="dictia-bg-orbs absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
<div class="dictia-orb-float-1 absolute" style="top:15%;left:8%;width:200px;height:200px;background:radial-gradient(circle, rgba(6,182,212,0.15) 0%, transparent 70%);filter:blur(60px);"></div> <div class="dictia-orb-float-1 absolute" style="top:12%;left:6%;width:240px;height:240px;background:radial-gradient(circle, rgba(37,99,235,0.10) 0%, transparent 70%);filter:blur(80px);"></div>
<div class="dictia-orb-float-2 absolute" style="bottom:10%;right:10%;width:240px;height:240px;background:radial-gradient(circle, rgba(192,38,211,0.18) 0%, transparent 70%);filter:blur(70px);"></div> <div class="dictia-orb-float-2 absolute" style="bottom:8%;right:8%;width:280px;height:280px;background:radial-gradient(circle, rgba(192,38,211,0.10) 0%, transparent 70%);filter:blur(90px);"></div>
</div> </div>
<div class="max-w-[1200px] mx-auto px-6 relative"> <div class="max-w-[1200px] mx-auto px-6 relative">
<div class="text-center max-w-2xl mx-auto mb-10"> <div class="text-center max-w-2xl mx-auto mb-10">
<p class="eyebrow grad-text mb-4 inline-flex items-center gap-2 justify-center px-3 py-1 rounded-full" {# Eyebrow : grad-text uppercase tracking-widest text-xs avec dot pulse brand-b3 #}
style="background:linear-gradient(135deg, rgba(6,182,212,0.10), rgba(192,38,211,0.10)); border:1px solid rgba(192,38,211,0.18);"> <p class="eyebrow grad-text mb-4 inline-flex items-center gap-2 justify-center px-3 py-1 rounded-full font-mono uppercase tracking-widest text-xs font-bold"
<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"> style="background:linear-gradient(135deg, rgba(6,182,212,0.10), rgba(192,38,211,0.10)); border:1px solid rgba(192,38,211,0.20);">
<circle cx="12" cy="12" r="3"/> <span class="dictia-dot-pulse inline-block w-1.5 h-1.5 rounded-full bg-brand-b3" aria-hidden="true"></span>
<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>
COMMENT ÇA MARCHE COMMENT ÇA MARCHE
</p> </p>
<h2 id="how-it-works-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black text-brand-navy mb-4 leading-tight"> <h2 id="how-it-works-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black text-brand-navy mb-4 leading-tight">
@@ -520,57 +528,60 @@
<div class="dictia-phone-shell flex flex-col overflow-hidden relative" <div class="dictia-phone-shell flex flex-col overflow-hidden relative"
style="width: 280px; height: 580px; border: 1.5px solid rgba(255,255,255,0.10); background: rgba(8,12,24,0.88); box-shadow: 0 30px 80px -20px rgba(0,0,0,0.6), 0 12px 32px -8px rgba(37,99,235,0.20), inset 0 0 32px rgba(255,255,255,0.04);"> style="width: 280px; height: 580px; border: 1.5px solid rgba(255,255,255,0.10); background: rgba(8,12,24,0.88); box-shadow: 0 30px 80px -20px rgba(0,0,0,0.6), 0 12px 32px -8px rgba(37,99,235,0.20), inset 0 0 32px rgba(255,255,255,0.04);">
{# Inner screen seam — effet "écran encastré dans le bezel" #}
<div class="dictia-phone-screen-seam" aria-hidden="true"></div>
{# Ambient overlay — STATIC subtle (pas de tint par mode) #} {# Ambient overlay — STATIC subtle (pas de tint par mode) #}
<div class="absolute inset-0 pointer-events-none" <div class="absolute inset-0 pointer-events-none"
style="border-radius: 44px; background-color: rgba(255,255,255,0.015);" style="border-radius: 44px; background-color: rgba(255,255,255,0.015);"
aria-hidden="true"></div> aria-hidden="true"></div>
{# Notch / Dynamic Island (desktop only via mobile media) #} {# Notch / Dynamic Island avec mini speaker grille (3 dots) #}
<div class="dictia-notch absolute left-1/2 -translate-x-1/2 z-30" <div class="dictia-notch absolute left-1/2 -translate-x-1/2 z-30 flex items-center justify-center gap-1"
style="top:8px;width:62px;height:6px;border-radius:6px;background:rgba(0,0,0,0.7);" style="top:8px;width:78px;height:18px;border-radius:12px;background:rgba(0,0,0,0.85);box-shadow:inset 0 1px 2px rgba(0,0,0,0.5);"
aria-hidden="true"></div>
{# Status bar mobile-style (9:41 + signals) #}
<div class="dictia-statusbar relative z-20 flex items-center justify-between px-5 pt-1 font-mono"
style="height:20px;color:rgba(255,255,255,0.55);font-size:9px;font-weight:600;"
aria-hidden="true"> aria-hidden="true">
<span>9:41</span> {# Speaker grille (3 dots) #}
<div class="flex items-center gap-1"> <span class="block rounded-full" style="width:3px;height:3px;background:rgba(255,255,255,0.10);"></span>
{# Signal #} <span class="block rounded-full" style="width:3px;height:3px;background:rgba(255,255,255,0.12);"></span>
<svg viewBox="0 0 14 10" width="11" height="8" fill="currentColor"> <span class="block rounded-full" style="width:3px;height:3px;background:rgba(255,255,255,0.10);"></span>
<rect x="0" y="7" width="2" height="3" rx="0.5"/> {# Camera dot #}
<rect x="3" y="5" width="2" height="5" rx="0.5"/> <span class="block rounded-full ml-1" style="width:5px;height:5px;background:rgba(255,255,255,0.18);box-shadow:inset 0 0 1px rgba(0,0,0,0.5);"></span>
<rect x="6" y="3" width="2" height="7" rx="0.5"/> </div>
<rect x="9" y="0" width="2" height="10" rx="0.5"/>
{# Status bar mobile-style (9:41 + signals) — vraies icônes SVG device-like #}
<div class="dictia-statusbar relative z-20 flex items-center justify-between px-6 font-mono text-[10px] font-semibold"
style="height:34px;padding-top:12px;color:rgba(255,255,255,0.65);"
aria-hidden="true">
<span class="font-bold">9:41</span>
<div class="flex items-center gap-1.5">
{# Signal — 4 bars croissantes, look device authentique #}
<svg viewBox="0 0 16 10" width="13" height="9" fill="currentColor">
<rect x="0" y="7" width="2.5" height="3" rx="0.5"/>
<rect x="3.5" y="5" width="2.5" height="5" rx="0.5"/>
<rect x="7" y="2.5" width="2.5" height="7.5" rx="0.5"/>
<rect x="10.5" y="0" width="2.5" height="10" rx="0.5"/>
</svg> </svg>
{# Wifi #} {# Wifi — 3 arcs concentriques + dot, look iOS authentique #}
<svg viewBox="0 0 14 10" width="11" height="8" fill="none" stroke="currentColor" stroke-width="1.4"> <svg viewBox="0 0 16 12" width="14" height="10" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round">
<path d="M1 4 Q7 -1 13 4"/> <path d="M1 4.5 Q8 -1.5 15 4.5"/>
<path d="M3 6 Q7 3 11 6"/> <path d="M3.2 7 Q8 3.2 12.8 7"/>
<circle cx="7" cy="9" r="0.8" fill="currentColor"/> <path d="M5.4 9.5 Q8 7.5 10.6 9.5"/>
<circle cx="8" cy="11" r="0.9" fill="currentColor"/>
</svg> </svg>
{# Battery #} {# Battery 80% — fill réel à 80% pour authenticité #}
<svg viewBox="0 0 18 8" width="14" height="7" fill="none" stroke="currentColor" stroke-width="0.8"> <svg viewBox="0 0 22 10" width="18" height="9" fill="none">
<rect x="0" y="0" width="14" height="8" rx="1.5"/> <rect x="0.5" y="0.5" width="18" height="9" rx="2" stroke="currentColor" stroke-opacity="0.6" stroke-width="0.8" fill="none"/>
<rect x="14.5" y="3" width="1" height="2" rx="0.4" fill="currentColor"/> <rect x="19.5" y="3.5" width="1.5" height="3" rx="0.5" fill="currentColor" fill-opacity="0.6"/>
<rect x="1.5" y="1.5" width="9" height="5" rx="0.5" fill="currentColor"/> <rect x="2" y="2" width="14" height="6" rx="1" fill="currentColor"/>
</svg> </svg>
</div> </div>
</div> </div>
{# Speaker grille + camera (top of screen, below notch) #}
<div class="dictia-speaker-grille absolute z-10 flex items-center justify-center gap-2"
style="top:32px;left:50%;transform:translateX(-50%);width:80px;height:8px;"
aria-hidden="true">
<div style="width:24px;height:2px;background:rgba(255,255,255,0.10);border-radius:2px;"></div>
<div class="dictia-camera-dot" style="width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,0.18);box-shadow:inset 0 0 1px rgba(0,0,0,0.5);"></div>
</div>
{# TOP : Logo + Mic pulsing (with sound waves) — hauteur fixe 96px #} {# TOP : Logo + Mic pulsing (with sound waves) — hauteur fixe 96px #}
<div class="flex flex-col items-center justify-center gap-2 relative z-10 flex-shrink-0" <div class="flex flex-col items-center justify-center gap-2 relative z-10 flex-shrink-0"
style="height: 96px; padding-top: 24px; border-bottom: 1px solid rgba(255,255,255,0.06);"> style="height: 96px; padding-top: 12px; border-bottom: 1px solid rgba(255,255,255,0.06);">
<img src="/static/images/dictia-logo-nom.png" alt="DictIA" <img src="/static/images/dictia-logo-nom.png" alt="DictIA"
style="width: 80px; height: 24px; object-fit: contain; opacity: 0.75;"> style="width: 92px; height: 28px; object-fit: contain; opacity: 0.85;">
<div class="relative" style="width:36px;height:36px;"> <div class="relative" style="width:36px;height:36px;">
{# 3 sound rings emanating #} {# 3 sound rings emanating #}
<span class="dictia-sound-ring r1" :style="`color: ${activeColor}; width:24px; height:24px;`" aria-hidden="true"></span> <span class="dictia-sound-ring r1" :style="`color: ${activeColor}; width:24px; height:24px;`" aria-hidden="true"></span>
@@ -594,66 +605,73 @@
{# Mode 1 : Transcription (header REC + waveform + upload bar + words) #} {# Mode 1 : Transcription (header REC + waveform + upload bar + words) #}
<template x-if="displayMode === 1"> <template x-if="displayMode === 1">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="trModeData()" x-init="init()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="trModeData()" x-init="init()">
{# Header bar (file + REC) #} {# Header bar (file + REC) — compact mic icon + filename + REC dot #}
<div class="flex items-center justify-between px-2.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-between px-3 py-2 flex-shrink-0"
style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);"> style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);">
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-1.5 min-w-0">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;color:rgba(6,182,212,0.80);" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-2.5 h-2.5 text-brand-b2 shrink-0" 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"/> <rect x="9" y="2" width="6" height="12" rx="3"/>
<polyline points="14 2 14 8 20 8"/> <path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
<line x1="12" y1="19" x2="12" y2="23"/>
</svg> </svg>
<span class="font-mono" style="font-size:6.5px;color:rgba(255,255,255,0.55);">reunion-jan14.mp3</span> <span class="font-mono text-[10px] text-white/60 truncate">reunion-jan14.mp3</span>
</div> </div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1 shrink-0">
<span class="dictia-rec-dot" style="width:5px;height:5px;border-radius:50%;background:#EF4444;"></span> <span class="dictia-rec-dot block rounded-full" style="width:5px;height:5px;background:#ef4444;"></span>
<span class="font-mono" style="font-size:6px;color:rgba(239,68,68,0.85);letter-spacing:0.08em;font-weight:700;">REC</span> <span class="font-mono text-[9px] font-bold tracking-widest" style="color:rgba(239,68,68,0.90);">REC</span>
</div> </div>
</div> </div>
{# Waveform animée (12 bars) #} {# Waveform animée (16 bars régulières — pattern symétrique) #}
<div class="flex items-end justify-center gap-0.5 px-3 py-2 flex-shrink-0" style="height:24px;" aria-hidden="true"> <div class="flex items-end justify-center gap-0.5 px-3 py-2 flex-shrink-0" style="height:28px;" aria-hidden="true">
<div class="dictia-wave-bar" style="width:2px;height:14px;background:#06b6d4;animation-delay:0s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:8px;animation-delay:0s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:18px;background:#06b6d4;animation-delay:0.1s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:12px;animation-delay:0.08s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:10px;background:#06b6d4;animation-delay:0.2s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:18px;animation-delay:0.16s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:20px;background:#06b6d4;animation-delay:0.05s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:14px;animation-delay:0.24s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:12px;background:#06b6d4;animation-delay:0.25s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:20px;animation-delay:0.32s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:16px;background:#06b6d4;animation-delay:0.15s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:16px;animation-delay:0.4s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:8px;background:#06b6d4;animation-delay:0.3s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:22px;animation-delay:0.48s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:14px;background:#06b6d4;animation-delay:0.08s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:18px;animation-delay:0.56s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:18px;background:#06b6d4;animation-delay:0.22s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:22px;animation-delay:0.48s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:10px;background:#06b6d4;animation-delay:0.18s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:16px;animation-delay:0.4s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:14px;background:#06b6d4;animation-delay:0s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:20px;animation-delay:0.32s;"></div>
<div class="dictia-wave-bar" style="width:2px;height:6px;background:#06b6d4;animation-delay:0.12s;"></div> <div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:14px;animation-delay:0.24s;"></div>
<div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:18px;animation-delay:0.16s;"></div>
<div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:12px;animation-delay:0.08s;"></div>
<div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:8px;animation-delay:0s;"></div>
<div class="dictia-wave-bar bg-brand-b2" style="width:2px;height:6px;animation-delay:0.04s;"></div>
</div> </div>
<div x-show="phase === 'upload'" class="flex-1 flex flex-col items-center justify-center gap-3 px-4 overflow-hidden"> <div x-show="phase === 'upload'" class="flex-1 flex flex-col items-center justify-center gap-3 px-4 overflow-hidden">
<div class="flex flex-col items-center gap-1.5"> <div class="flex flex-col items-center gap-2">
<div class="w-10 h-12 rounded-md flex flex-col items-center justify-center relative" {# File card MP3 — design device pro avec corner fold #}
style="background-color: rgba(6,182,212,0.12); border: 1.5px solid rgba(6,182,212,0.40);"> <div class="flex flex-col items-center justify-center relative"
<div class="absolute top-0 right-0" style="width:0;height:0;border-style:solid;border-width:0 7px 7px 0;border-color:transparent rgba(0,0,0,0.40) transparent transparent;"></div> style="width:44px;height:54px;background-color:rgba(6,182,212,0.12);border:1.5px solid rgba(6,182,212,0.45);border-radius:6px;">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:13px;height:13px;color:#06b6d4;" aria-hidden="true"> <div class="absolute top-0 right-0" style="width:0;height:0;border-style:solid;border-width:0 8px 8px 0;border-color:transparent rgba(0,0,0,0.45) transparent transparent;"></div>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b2" style="width:14px;height:14px;" aria-hidden="true">
<rect x="9" y="2" width="6" height="12" rx="3"/> <rect x="9" y="2" width="6" height="12" rx="3"/>
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/> <path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
<line x1="12" y1="19" x2="12" y2="23"/> <line x1="12" y1="19" x2="12" y2="23"/>
</svg> </svg>
<span class="font-mono" style="font-size:5.5px;color:rgba(6,182,212,0.70);letter-spacing:0.06em;">MP3</span> <span class="font-mono text-[9px] font-bold tracking-wider mt-1" style="color:rgba(6,182,212,0.80);">MP3</span>
</div> </div>
</div> </div>
<div class="w-full flex flex-col gap-1"> <div class="w-full flex flex-col gap-1.5">
<div class="flex justify-between"> <div class="flex justify-between items-center">
<span class="font-mono" style="font-size:6.5px;color:rgba(6,182,212,0.65);" x-text="progress < 100 ? 'Envoi en cours…' : 'Prêt ✓'"></span> <span class="font-mono text-[10px]" style="color:rgba(6,182,212,0.75);" x-text="progress < 100 ? 'Envoi en cours…' : 'Prêt ✓'"></span>
<span class="font-mono" style="font-size:6.5px;color:rgba(6,182,212,0.50);"><span x-text="progress"></span>%</span> <span class="font-mono text-[10px] font-semibold" style="color:rgba(6,182,212,0.65);"><span x-text="progress"></span>%</span>
</div> </div>
{# Double progress bar (track + active with glow) #} {# Track gris fin + fill brand-b2 glow #}
<div class="w-full rounded-full overflow-hidden relative" style="height:4px;background-color:rgba(6,182,212,0.10);box-shadow:inset 0 0 2px rgba(0,0,0,0.4);"> <div class="w-full rounded-full overflow-hidden relative" style="height:4px;background-color:rgba(255,255,255,0.06);box-shadow:inset 0 0 2px rgba(0,0,0,0.4);">
<div class="h-full rounded-full" :style="`width: ${progress}%; background: linear-gradient(90deg, #06b6d4, #0891b2); box-shadow: 0 0 6px rgba(6,182,212,0.6); transition: width 60ms linear;`"></div> <div class="h-full rounded-full bg-brand-b2" :style="`width: ${progress}%; box-shadow: 0 0 8px rgba(6,182,212,0.7); transition: width 60ms linear;`"></div>
</div> </div>
</div> </div>
</div> </div>
{# Transcript zone — scroll interne avec fade bottom #} {# Transcript zone — scroll interne avec fade bottom #}
<div x-show="phase === 'transcribing'" class="flex-1 p-3 dictia-mode-scroll dictia-fade-bottom flex flex-col justify-start" x-ref="transcriptBox"> <div x-show="phase === 'transcribing'" class="flex-1 p-3 dictia-mode-scroll dictia-fade-bottom flex flex-col justify-start" x-ref="transcriptBox">
<p class="font-mono leading-relaxed break-words" style="font-size:9px;color:rgba(6,182,212,0.92);background:rgba(6,182,212,0.04);padding:4px 6px;border-radius:6px;border-left:2px solid rgba(6,182,212,0.4);"> <p class="font-mono leading-relaxed break-words text-[10px] rounded"
<span x-text="words.slice(0, n + 1).join(' ')"></span><span class="dictia-blink ml-px" style="color:#06b6d4;display:inline-block;width:3px;background:#06b6d4;height:9px;vertical-align:middle;">&nbsp;</span> style="color:rgba(6,182,212,0.92);background:rgba(6,182,212,0.04);padding:6px 8px;border-left:2px solid rgba(6,182,212,0.4);">
<span x-text="words.slice(0, n + 1).join(' ')"></span><span class="dictia-blink ml-px inline-block align-middle bg-brand-b2" style="width:3px;height:10px;">&nbsp;</span>
</p> </p>
</div> </div>
</div> </div>
@@ -662,21 +680,21 @@
{# Mode 2 : Diarisation (conversation Sophie/Marc/Julie) #} {# Mode 2 : Diarisation (conversation Sophie/Marc/Julie) #}
<template x-if="displayMode === 2"> <template x-if="displayMode === 2">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="diaModeData()" x-init="init()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="diaModeData()" x-init="init()">
{# Conversation header with stacked avatars #} {# Conversation header — 3 avatars empilés 24×24 avec bordure white/15 #}
<div class="flex items-center justify-between px-2.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-between px-3 py-2 flex-shrink-0"
style="background:rgba(37,99,235,0.06);border-bottom:1px solid rgba(37,99,235,0.12);"> style="background:rgba(37,99,235,0.06);border-bottom:1px solid rgba(37,99,235,0.12);">
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-2">
<div class="flex" style="margin-right:2px;"> <div class="flex">
<div class="rounded-full flex items-center justify-center text-[7px] font-bold" <div class="rounded-full flex items-center justify-center text-[10px] font-bold text-white"
style="width:14px;height:14px;background:linear-gradient(135deg,#06b6d4,#0891b2);border:1.5px solid rgba(8,12,24,0.9);color:#fff;">S</div> style="width:18px;height:18px;background:linear-gradient(135deg,#06b6d4,#2563eb);border:1.5px solid rgba(8,12,24,0.9);">S</div>
<div class="rounded-full flex items-center justify-center text-[7px] font-bold" <div class="rounded-full flex items-center justify-center text-[10px] font-bold text-white"
style="width:14px;height:14px;background:linear-gradient(135deg,#2563eb,#1d4ed8);border:1.5px solid rgba(8,12,24,0.9);color:#fff;margin-left:-5px;">M</div> style="width:18px;height:18px;background:linear-gradient(135deg,#2563eb,#06b6d4);border:1.5px solid rgba(8,12,24,0.9);margin-left:-6px;">M</div>
<div class="rounded-full flex items-center justify-center text-[7px] font-bold" <div class="rounded-full flex items-center justify-center text-[10px] font-bold text-white"
style="width:14px;height:14px;background:linear-gradient(135deg,#c026d3,#a21caf);border:1.5px solid rgba(8,12,24,0.9);color:#fff;margin-left:-5px;">J</div> style="width:18px;height:18px;background:linear-gradient(135deg,#c026d3,#2563eb);border:1.5px solid rgba(8,12,24,0.9);margin-left:-6px;">J</div>
</div> </div>
<span class="font-mono" style="font-size:6.5px;color:rgba(255,255,255,0.65);">Réunion · 3 participants</span> <span class="font-mono text-[10px] text-white/65">Réunion · 3 participants</span>
</div> </div>
<span class="dictia-rec-dot" style="width:5px;height:5px;border-radius:50%;background:#10b981;"></span> <span class="dictia-rec-dot block rounded-full" style="width:5px;height:5px;background:#10b981;"></span>
</div> </div>
<div class="flex-1 flex flex-col justify-end gap-1.5 p-2 dictia-mode-scroll dictia-fade-bottom"> <div class="flex-1 flex flex-col justify-end gap-1.5 p-2 dictia-mode-scroll dictia-fade-bottom">
<template x-for="(msg, i) in visible" :key="`${cycle}-${startIdx + i}`"> <template x-for="(msg, i) in visible" :key="`${cycle}-${startIdx + i}`">
@@ -685,24 +703,25 @@
style="width:24px;height:24px;" style="width:24px;height:24px;"
:style="`background:linear-gradient(135deg, ${msg.c}33, ${msg.c}22); border: 1.5px solid ${msg.c}66; color: ${msg.c};`" :style="`background:linear-gradient(135deg, ${msg.c}33, ${msg.c}22); border: 1.5px solid ${msg.c}66; color: ${msg.c};`"
x-text="msg.s.charAt(0)"></div> x-text="msg.s.charAt(0)"></div>
<div class="rounded-lg px-2 py-1.5 flex-1 relative" <div class="rounded px-2 py-1.5 flex-1 relative"
style="max-width:80%;"
:style="`background-color: ${msg.c}10; border: 1px solid ${msg.c}28; box-shadow: 0 1px 4px rgba(0,0,0,0.15);`"> :style="`background-color: ${msg.c}10; border: 1px solid ${msg.c}28; box-shadow: 0 1px 4px rgba(0,0,0,0.15);`">
<div class="flex items-baseline justify-between gap-2 mb-0.5"> <div class="flex items-baseline justify-between gap-2 mb-0.5">
<p class="text-[8.5px] font-bold leading-none" :style="`color: ${msg.c};`" x-text="msg.s"></p> <p class="text-[10px] font-bold leading-none" :style="`color: ${msg.c};`" x-text="msg.s"></p>
<span class="text-[6.5px] font-mono" style="color:rgba(255,255,255,0.30);" x-text="`09:0${i+1}`"></span> <span class="text-[9px] font-mono" style="color:rgba(255,255,255,0.30);" x-text="`09:0${i+1}`"></span>
</div> </div>
<p class="text-[8.5px] font-mono leading-snug" style="color:rgba(255,255,255,0.78);" x-text="msg.t"></p> <p class="text-[10px] font-mono leading-snug" style="color:rgba(255,255,255,0.80);" x-text="msg.t"></p>
</div> </div>
</div> </div>
</template> </template>
{# Typing indicator #} {# Typing indicator (3 dots pulse en boucle) #}
<div class="flex items-center gap-1.5 px-1" x-show="shownCount < CONVO.length" aria-hidden="true"> <div class="flex items-center gap-1.5 px-1" x-show="shownCount < CONVO.length" aria-hidden="true">
<div class="rounded-full" style="width:24px;height:24px;background:rgba(255,255,255,0.05);border:1px dashed rgba(255,255,255,0.15);"></div> <div class="rounded-full" style="width:24px;height:24px;background:rgba(255,255,255,0.05);border:1px dashed rgba(255,255,255,0.15);"></div>
<div class="flex items-center gap-1 rounded-lg px-2 py-1.5" <div class="flex items-center gap-1 rounded px-2 py-1.5"
style="background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);"> style="background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.08);">
<span class="dictia-typing-dot" style="width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,0.5);animation-delay:0s;"></span> <span class="dictia-typing-dot block rounded-full" style="width:4px;height:4px;background:rgba(255,255,255,0.5);animation-delay:0s;"></span>
<span class="dictia-typing-dot" style="width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,0.5);animation-delay:0.2s;"></span> <span class="dictia-typing-dot block rounded-full" style="width:4px;height:4px;background:rgba(255,255,255,0.5);animation-delay:0.2s;"></span>
<span class="dictia-typing-dot" style="width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,0.5);animation-delay:0.4s;"></span> <span class="dictia-typing-dot block rounded-full" style="width:4px;height:4px;background:rgba(255,255,255,0.5);animation-delay:0.4s;"></span>
</div> </div>
</div> </div>
</div> </div>
@@ -713,29 +732,29 @@
<template x-if="displayMode === 3"> <template x-if="displayMode === 3">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="langModeData()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="langModeData()">
{# Header DÉTECTION AUTOMATIQUE #} {# Header DÉTECTION AUTOMATIQUE #}
<div class="flex items-center justify-center gap-1.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-center gap-2 py-2 flex-shrink-0"
style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);"> style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);">
<span class="dictia-dot-pulse" style="width:5px;height:5px;border-radius:50%;background:#06b6d4;"></span> <span class="dictia-dot-pulse block rounded-full bg-brand-b2" style="width:5px;height:5px;"></span>
<span class="font-mono" style="font-size:7px;color:rgba(6,182,212,0.85);letter-spacing:0.16em;font-weight:700;">DÉTECTION AUTOMATIQUE</span> <span class="font-mono text-[10px] font-bold tracking-widest" style="color:rgba(6,182,212,0.90);">DÉTECTION AUTOMATIQUE</span>
</div> </div>
{# Scroll interne pour les 100 codes — fade bottom suggère continuation #} {# Scroll interne pour les 100 codes — fade bottom suggère continuation #}
<div class="flex-1 dictia-mode-scroll dictia-fade-bottom" style="padding:6px 5px;"> <div class="flex-1 dictia-mode-scroll dictia-fade-bottom" style="padding:8px 6px;">
<div class="grid content-start" style="grid-template-columns: repeat(7, 1fr); gap: 3px;"> <div class="grid content-start" style="grid-template-columns: repeat(7, 1fr); gap: 4px;">
<template x-for="(lang, i) in LANGS" :key="lang"> <template x-for="(lang, i) in LANGS" :key="lang">
<span class="font-mono font-bold text-center rounded dictia-spring" <span class="font-mono font-bold text-center rounded dictia-spring text-[10px]"
:class="HIGHLIGHTS.includes(i) ? 'dictia-lang-highlight' : ''" :class="HIGHLIGHTS.includes(i) ? 'dictia-lang-highlight' : ''"
:style="`font-size:6.5px;line-height:16px;background-color:${LANG_COLORS[i % LANG_COLORS.length]}14;border:1px solid ${LANG_COLORS[i % LANG_COLORS.length]}30;color:${LANG_COLORS[i % LANG_COLORS.length]};animation-delay:${rippleDelay(i)}ms;`" :style="`line-height:18px;background-color:${LANG_COLORS[i % LANG_COLORS.length]}14;border:1px solid ${LANG_COLORS[i % LANG_COLORS.length]}30;color:${LANG_COLORS[i % LANG_COLORS.length]};animation-delay:${rippleDelay(i)}ms;`"
x-text="lang"></span> x-text="lang"></span>
</template> </template>
</div> </div>
</div> </div>
{# Counter live en bas #} {# Counter live en bas #}
<div class="flex items-center justify-between px-2.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-between px-3 py-2 flex-shrink-0"
style="background:rgba(6,182,212,0.04);border-top:1px solid rgba(6,182,212,0.10);"> style="background:rgba(6,182,212,0.04);border-top:1px solid rgba(6,182,212,0.10);">
<span class="font-mono dictia-fade-y" style="font-size:6.5px;color:rgba(6,182,212,0.75);letter-spacing:0.06em;animation-delay:1.4s;"> <span class="font-mono dictia-fade-y text-[9px] tracking-wide" style="color:rgba(6,182,212,0.75);animation-delay:1.4s;">
FR · EN · ES · DE · ZH · JA · AR · ... FR · EN · ES · DE · ZH · JA · AR
</span> </span>
<span class="font-mono font-bold dictia-fade-y" style="font-size:7.5px;color:#06b6d4;letter-spacing:0.1em;animation-delay:1.4s;"> <span class="font-mono font-bold dictia-fade-y text-[10px] tracking-wider text-brand-b2" style="animation-delay:1.4s;">
99+ langues détectées 99+ langues détectées
</span> </span>
</div> </div>
@@ -746,41 +765,42 @@
<template x-if="displayMode === 4"> <template x-if="displayMode === 4">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="expModeData()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="expModeData()">
{# Header subtle #} {# Header subtle #}
<div class="flex items-center justify-between px-2.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-between px-3 py-2 flex-shrink-0"
style="background:rgba(37,99,235,0.06);border-bottom:1px solid rgba(37,99,235,0.12);"> style="background:rgba(37,99,235,0.06);border-bottom:1px solid rgba(37,99,235,0.12);">
<span class="font-mono" style="font-size:7px;color:rgba(37,99,235,0.85);letter-spacing:0.14em;font-weight:700;">EXPORTS DISPONIBLES</span> <span class="font-mono text-[10px] font-bold tracking-widest" style="color:rgba(37,99,235,0.90);">EXPORTS DISPONIBLES</span>
<span class="font-mono text-[9px] text-brand-b1/60">7 formats</span>
</div> </div>
{# Grid 4×2 #} {# Grid 4×2 — staggered drop animation #}
<div class="grid grid-cols-4 gap-2 p-3 flex-1 content-center justify-items-center overflow-hidden"> <div class="grid grid-cols-4 gap-2 p-3 flex-1 content-center justify-items-center overflow-hidden">
<template x-for="(f, i) in FILE_TYPES" :key="f.ext"> <template x-for="(f, i) in FILE_TYPES" :key="f.ext">
<div class="dictia-spring-y" :style="`animation-delay:${i * 110}ms;`"> <div class="dictia-spring-y" :style="`animation-delay:${i * 90}ms;`">
<div class="rounded-md flex flex-col items-center justify-end gap-0.5 relative" <div class="flex flex-col items-center justify-end gap-0.5 relative"
style="width:38px;height:46px;" style="width:42px;height:50px;border-radius:4px;"
:style="`background-color:${f.bg}CC;border:1.5px solid ${f.bg};box-shadow:0 4px 12px ${f.bg}40;`"> :style="`background-color:${f.bg}CC;border:1.5px solid ${f.bg};box-shadow:0 4px 12px ${f.bg}40;`">
<div class="absolute top-0 right-0" style="width:0;height:0;border-style:solid;border-width:0 8px 8px 0;border-color:transparent rgba(0,0,0,0.40) transparent transparent;"></div> <div class="absolute top-0 right-0" style="width:0;height:0;border-style:solid;border-width:0 9px 9px 0;border-color:transparent rgba(0,0,0,0.45) transparent transparent;"></div>
{# Mini "page" lines #} {# Mini "page" lines #}
<div class="absolute top-2 left-1.5 right-3 flex flex-col gap-0.5" aria-hidden="true"> <div class="absolute top-2 left-1.5 right-3 flex flex-col gap-0.5" aria-hidden="true">
<div :style="`height:1px;background:${f.fg}55;width:80%;`"></div> <div :style="`height:1px;background:${f.fg}55;width:80%;`"></div>
<div :style="`height:1px;background:${f.fg}40;width:65%;`"></div> <div :style="`height:1px;background:${f.fg}40;width:65%;`"></div>
<div :style="`height:1px;background:${f.fg}40;width:75%;`"></div> <div :style="`height:1px;background:${f.fg}40;width:75%;`"></div>
</div> </div>
<span class="text-[10px] font-black leading-none mb-0.5" :style="`color:${f.fg};margin-bottom:8px;`" x-text="f.sym"></span> <span class="text-[11px] font-black leading-none" :style="`color:${f.fg};margin-bottom:6px;`" x-text="f.sym"></span>
<span class="text-[7px] font-mono font-bold leading-none mb-1" :style="`color:${f.fg}BB;`" x-text="f.ext"></span> <span class="text-[9px] font-mono font-bold leading-none mb-1.5" :style="`color:${f.fg}BB;`" x-text="f.ext"></span>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
{# Subtitle dynamique avec checkmark — vert sémantique conservé pour status "ready" #} {# Subtitle dynamique avec checkmark — vert sémantique conservé pour status "ready" #}
<div class="flex items-center justify-center gap-1.5 px-2.5 py-1.5 dictia-fade-y flex-shrink-0" <div class="flex items-center justify-center gap-2 px-3 py-2 dictia-fade-y flex-shrink-0"
style="background:rgba(16,185,129,0.06);border-top:1px solid rgba(16,185,129,0.14);animation-delay:0.9s;"> style="background:rgba(16,185,129,0.06);border-top:1px solid rgba(16,185,129,0.14);animation-delay:0.9s;">
<span style="width:11px;height:11px;border-radius:50%;background:#10b981;display:inline-flex;align-items:center;justify-content:center;"> <span class="inline-flex items-center justify-center rounded-full" style="width:13px;height:13px;background:#10b981;">
<svg viewBox="0 0 24 24" fill="none" stroke="rgba(8,12,24,0.9)" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" style="width:7px;height:7px;" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="rgba(8,12,24,0.9)" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;" aria-hidden="true">
<polyline points="20 6 9 17 4 12"/> <polyline points="20 6 9 17 4 12"/>
</svg> </svg>
</span> </span>
<span class="font-mono" style="font-size:7px;color:#10b981;letter-spacing:0.08em;font-weight:700;">7 FORMATS PRÊTS</span> <span class="font-mono text-[10px] font-bold tracking-widest" style="color:#10b981;">7 FORMATS PRÊTS</span>
</div> </div>
</div> </div>
</template> </template>
@@ -788,28 +808,28 @@
{# Mode 5 : Users (counter centré + avatars colors variés + connecting lines) #} {# Mode 5 : Users (counter centré + avatars colors variés + connecting lines) #}
<template x-if="displayMode === 5"> <template x-if="displayMode === 5">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="usersModeData()" x-init="init()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="usersModeData()" x-init="init()">
{# Header counter #} {# Header counter — gros chiffre Inter font-black #}
<div class="flex items-center justify-center gap-1.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-center gap-2 py-2 flex-shrink-0"
style="background:rgba(192,38,211,0.06);border-bottom:1px solid rgba(192,38,211,0.12);"> style="background:rgba(192,38,211,0.06);border-bottom:1px solid rgba(192,38,211,0.12);">
<span class="font-mono" style="font-size:7px;color:rgba(192,38,211,0.75);letter-spacing:0.14em;font-weight:700;">UTILISATEURS</span> <span class="font-mono text-[10px] font-bold tracking-widest" style="color:rgba(192,38,211,0.85);">UTILISATEURS</span>
<span class="font-mono font-black" style="font-size:11px;color:#c026d3;letter-spacing:0.05em;" x-text="count.toString().padStart(2, '0')"></span> <span class="font-black text-base text-brand-b3 leading-none" x-text="count.toString().padStart(2, '0')"></span>
<span class="font-mono" style="font-size:7px;color:rgba(192,38,211,0.45);">/</span> <span class="font-mono text-[10px]" style="color:rgba(192,38,211,0.50);"></span>
</div> </div>
{# Avatar grid with connecting lines SVG #} {# Avatar grid with connecting lines SVG #}
<div class="flex-1 relative p-2 flex flex-wrap gap-1.5 items-center justify-center content-center overflow-hidden"> <div class="flex-1 relative p-3 flex flex-wrap gap-2 items-center justify-center content-center overflow-hidden">
{# SVG connecting lines (brand declinaisons only) #} {# SVG connecting lines (brand b1/b2/b3 only) — opacité subtle #}
<svg class="absolute inset-0 pointer-events-none" width="100%" height="100%" aria-hidden="true" style="opacity:0.4;"> <svg class="absolute inset-0 pointer-events-none" width="100%" height="100%" aria-hidden="true" style="opacity:0.18;">
<line x1="20%" y1="30%" x2="50%" y2="50%" stroke="#c026d3" stroke-width="0.5" stroke-dasharray="2 2"/> <line x1="20%" y1="30%" x2="50%" y2="50%" stroke="#c026d3" stroke-width="0.5" stroke-dasharray="2 2"/>
<line x1="80%" y1="30%" x2="50%" y2="50%" stroke="#06b6d4" stroke-width="0.5" stroke-dasharray="2 2"/> <line x1="80%" y1="30%" x2="50%" y2="50%" stroke="#06b6d4" stroke-width="0.5" stroke-dasharray="2 2"/>
<line x1="20%" y1="70%" x2="50%" y2="50%" stroke="#a21caf" stroke-width="0.5" stroke-dasharray="2 2"/> <line x1="20%" y1="70%" x2="50%" y2="50%" stroke="#c026d3" stroke-width="0.5" stroke-dasharray="2 2"/>
<line x1="80%" y1="70%" x2="50%" y2="50%" stroke="#2563eb" stroke-width="0.5" stroke-dasharray="2 2"/> <line x1="80%" y1="70%" x2="50%" y2="50%" stroke="#2563eb" stroke-width="0.5" stroke-dasharray="2 2"/>
</svg> </svg>
<template x-for="i in count" :key="`${cycle}-${i}`"> <template x-for="i in count" :key="`${cycle}-${i}`">
<div class="rounded-full flex items-center justify-center relative z-10" <div class="rounded-full flex items-center justify-center relative z-10"
:class="i === count ? 'dictia-spring' : ''" :class="i === count ? 'dictia-spring' : ''"
:style="`width:24px;height:24px;background-color:${USER_COLORS[(i-1) % USER_COLORS.length]}22;border:1.5px solid ${USER_COLORS[(i-1) % USER_COLORS.length]}77;`"> :style="`width:24px;height:24px;background-color:${USER_COLORS[(i-1) % USER_COLORS.length]}22;border:1.5px solid ${USER_COLORS[(i-1) % USER_COLORS.length]}77;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:10px;height:10px;" :style="`color:${USER_COLORS[(i-1) % USER_COLORS.length]};`" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:11px;height:11px;" :style="`color:${USER_COLORS[(i-1) % USER_COLORS.length]};`" aria-hidden="true">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/>
<circle cx="12" cy="7" r="4"/> <circle cx="12" cy="7" r="4"/>
</svg> </svg>
@@ -822,70 +842,73 @@
{# Mode 6 : Share (breadcrumb + toolbar + rows structurées) #} {# Mode 6 : Share (breadcrumb + toolbar + rows structurées) #}
<template x-if="displayMode === 6"> <template x-if="displayMode === 6">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden">
{# Breadcrumb #} {# Breadcrumb compact 12px max + toolbar 4 icons #}
<div class="flex items-center gap-1 px-2.5 py-1.5 flex-shrink-0" <div class="flex items-center gap-1.5 px-3 py-2 flex-shrink-0"
style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);"> style="background:rgba(6,182,212,0.06);border-bottom:1px solid rgba(6,182,212,0.12);">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:7px;height:7px;color:#06b6d4;" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b2 shrink-0" style="width:9px;height:9px;" aria-hidden="true">
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/> <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
</svg> </svg>
<span class="font-mono" style="font-size:6.5px;color:rgba(255,255,255,0.55);">Mes&nbsp;dossiers</span> <span class="font-mono text-[10px] text-white/55">Mes&nbsp;dossiers</span>
<span style="font-size:6px;color:rgba(255,255,255,0.30);"></span> <span class="text-[9px] text-white/30"></span>
<span class="font-mono" style="font-size:6.5px;color:#06b6d4;font-weight:700;">Réunions</span> <span class="font-mono text-[10px] font-bold text-brand-b2">Réunions</span>
{# Toolbar mini #} {# Toolbar mini 4 icons #}
<div class="flex items-center gap-1.5 ml-auto" aria-hidden="true"> <div class="flex items-center gap-1.5 ml-auto" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;color:rgba(255,255,255,0.40);"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-white/40" style="width:10px;height:10px;">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/> <circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg> </svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;color:rgba(255,255,255,0.40);"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-white/40" style="width:10px;height:10px;">
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/> <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>
</svg> </svg>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;color:rgba(255,255,255,0.40);"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-white/40" style="width:10px;height:10px;">
<path d="M3 6h18M3 12h18M3 18h18"/> <path d="M3 6h18M3 12h18M3 18h18"/>
</svg> </svg>
<svg viewBox="0 0 24 24" fill="currentColor" class="text-white/40" style="width:10px;height:10px;">
<circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/>
</svg>
</div> </div>
</div> </div>
<div class="flex-1 flex flex-col gap-1.5 dictia-mode-scroll dictia-fade-bottom" style="padding:6px 7px;"> <div class="flex-1 flex flex-col gap-2 dictia-mode-scroll dictia-fade-bottom" style="padding:8px;">
{# Folders #} {# Folders #}
<div class="flex gap-1 flex-wrap"> <div class="flex gap-1 flex-wrap">
<template x-for="(f, fi) in [{name:'Réunions',color:'#06b6d4',count:12},{name:'Entretiens',color:'#2563eb',count:7},{name:'Formations',color:'#c026d3',count:24}]" :key="f.name"> <template x-for="(f, fi) in [{name:'Réunions',color:'#06b6d4',count:12},{name:'Entretiens',color:'#2563eb',count:7},{name:'Formations',color:'#c026d3',count:24}]" :key="f.name">
<div class="flex items-center gap-1 rounded-md dictia-fade-y" <div class="flex items-center gap-1 rounded dictia-fade-y"
:style="`background-color:${f.color}18;border:1px solid ${f.color}35;padding:3px 6px;animation-delay:${fi * 100}ms;`"> :style="`background-color:${f.color}18;border:1px solid ${f.color}35;padding:3px 6px;animation-delay:${fi * 100}ms;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:7px;height:7px;" :style="`color:${f.color};`" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:9px;height:9px;" :style="`color:${f.color};`" aria-hidden="true">
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/> <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
</svg> </svg>
<span class="font-mono" style="font-size:6.5px;" :style="`color:${f.color};`" x-text="f.name"></span> <span class="font-mono text-[9px] font-semibold" :style="`color:${f.color};`" x-text="f.name"></span>
<span class="font-mono" style="font-size:6px;" :style="`color:${f.color}88;`" x-text="f.count"></span> <span class="font-mono text-[9px]" :style="`color:${f.color}88;`" x-text="f.count"></span>
</div> </div>
</template> </template>
</div> </div>
{# Tags #} {# Tags pills #}
<div class="flex flex-wrap gap-1"> <div class="flex flex-wrap gap-1">
<template x-for="(tag, ti) in ['#RH','#Direction','#Urgent','#Archivé','#Suivi','#Confidentiel','#2024']" :key="tag"> <template x-for="(tag, ti) in ['#RH','#Direction','#Urgent','#Archivé','#Suivi','#Confidentiel','#2024']" :key="tag">
<span class="rounded dictia-spring font-mono" <span class="rounded-full dictia-spring font-mono text-[9px] text-brand-b2"
style="font-size:5.5px;padding:2px 4px;background-color:rgba(6,182,212,0.10);border:1px solid rgba(6,182,212,0.25);color:#06b6d4;" style="padding:2px 6px;background-color:rgba(6,182,212,0.10);border:1px solid rgba(6,182,212,0.25);"
:style="`animation-delay:${350 + ti * 70}ms;`" :style="`animation-delay:${350 + ti * 70}ms;`"
x-text="tag"></span> x-text="tag"></span>
</template> </template>
</div> </div>
{# File rows structurées #} {# File rows structurées — hover highlight #}
<div class="flex flex-col gap-1 mt-0.5"> <div class="flex flex-col gap-1">
<template x-for="(file, fi2) in [{name:'CR-Réunion-Jan14',folder:'Réunions',color:'#06b6d4'},{name:'Entretien-Sophie',folder:'Entretiens',color:'#2563eb'},{name:'Formation-RGPD',folder:'Formations',color:'#c026d3'}]" :key="file.name"> <template x-for="(file, fi2) in [{name:'CR-Réunion-Jan14',folder:'Réunions',color:'#06b6d4'},{name:'Entretien-Sophie',folder:'Entretiens',color:'#2563eb'},{name:'Formation-RGPD',folder:'Formations',color:'#c026d3'}]" :key="file.name">
<div class="dictia-share-row group flex items-center gap-1.5 rounded-lg dictia-fade-x cursor-pointer" <div class="dictia-share-row group flex items-center gap-2 rounded dictia-fade-x cursor-pointer"
:style="`background-color:${file.color}0C;border:1px solid ${file.color}22;padding:4px 6px;animation-delay:${650 + fi2 * 120}ms;transition:background-color 0.2s;`"> :style="`background-color:${file.color}0C;border:1px solid ${file.color}22;padding:5px 8px;animation-delay:${650 + fi2 * 120}ms;transition:background-color 0.2s;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:8px;height:8px;flex-shrink:0;" :style="`color:${file.color};`" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0" style="width:10px;height:10px;" :style="`color:${file.color};`" 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"/> <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"/> <polyline points="14 2 14 8 20 8"/>
</svg> </svg>
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<p class="truncate font-mono" style="font-size:7px;color:rgba(255,255,255,0.78);" x-text="file.name"></p> <p class="truncate font-mono text-[10px] text-white/80" x-text="file.name"></p>
</div> </div>
<span class="rounded font-mono shrink-0" <span class="rounded font-mono shrink-0 text-[9px]"
style="font-size:5.5px;padding:1px 4px;" style="padding:2px 5px;"
:style="`background:${file.color}18;color:${file.color};border:1px solid ${file.color}33;`" :style="`background:${file.color}18;color:${file.color};border:1px solid ${file.color}33;`"
x-text="file.folder"></span> x-text="file.folder"></span>
<span class="dictia-share-action shrink-0" aria-hidden="true"> <span class="shrink-0" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" style="width:8px;height:8px;" :style="`color:${file.color}77;`"> <svg viewBox="0 0 24 24" fill="currentColor" style="width:10px;height:10px;" :style="`color:${file.color}77;`">
<circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/> <circle cx="5" cy="12" r="1.6"/><circle cx="12" cy="12" r="1.6"/><circle cx="19" cy="12" r="1.6"/>
</svg> </svg>
</span> </span>
@@ -893,8 +916,8 @@
</template> </template>
</div> </div>
</div> </div>
<p class="text-center font-mono dictia-fade-y px-2 py-1 flex-shrink-0" <p class="text-center font-mono dictia-fade-y px-3 py-2 flex-shrink-0 text-[9px] tracking-wide"
style="font-size:6.5px;color:rgba(6,182,212,0.65);letter-spacing:0.08em;background:rgba(6,182,212,0.04);border-top:1px solid rgba(6,182,212,0.10);animation-delay:1.2s;"> style="color:rgba(6,182,212,0.70);background:rgba(6,182,212,0.04);border-top:1px solid rgba(6,182,212,0.10);animation-delay:1.2s;">
partage sécurisé · recherche plein texte partage sécurisé · recherche plein texte
</p> </p>
</div> </div>
@@ -903,67 +926,70 @@
{# Mode 0 : IA chat (Mistral 7B local Q&R typing) — visible si user clique sur IA dans grid #} {# Mode 0 : IA chat (Mistral 7B local Q&R typing) — visible si user clique sur IA dans grid #}
<template x-if="displayMode === 0"> <template x-if="displayMode === 0">
<div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="iaModeData()" x-init="init()"> <div class="dictia-mode-fade w-full h-full flex flex-col overflow-hidden" x-data="iaModeData()" x-init="init()">
<div class="flex items-center justify-center gap-1.5 py-1.5 flex-shrink-0" <div class="flex items-center justify-center gap-2 py-2 flex-shrink-0"
style="border-bottom: 1px solid rgba(192,38,211,0.14); background-color: rgba(192,38,211,0.05);"> style="border-bottom: 1px solid rgba(192,38,211,0.14); background-color: rgba(192,38,211,0.05);">
<div class="rounded-full flex-shrink-0 dictia-dot-pulse" style="width:6px;height:6px;background-color:#10b981;"></div> <span class="rounded-full flex-shrink-0 dictia-dot-pulse block" style="width:6px;height:6px;background-color:#10b981;"></span>
<span class="font-mono" style="font-size:6px;color:rgba(192,38,211,0.85);letter-spacing:0.14em;">MISTRAL 7B · LOCAL</span> <span class="font-mono text-[10px] font-bold tracking-widest" style="color:rgba(192,38,211,0.90);">MISTRAL 7B · LOCAL</span>
</div> </div>
<div class="flex-1 flex flex-col justify-end gap-1.5 p-2 dictia-mode-scroll dictia-fade-bottom"> <div class="flex-1 flex flex-col justify-end gap-2 p-2 dictia-mode-scroll dictia-fade-bottom">
<template x-for="(msg, mi) in msgs" :key="mi"> <template x-for="(msg, mi) in msgs" :key="mi">
<div class="dictia-fade-y" :class="msg.role === 'user' ? 'flex justify-end' : 'flex justify-start'"> <div class="dictia-fade-y" :class="msg.role === 'user' ? 'flex justify-end' : 'flex justify-start'">
<div class="rounded-lg px-2 py-1.5" style="max-width:92%;" <div class="rounded px-2 py-1.5" style="max-width:88%;"
:style="msg.role === 'user' ? 'background-color:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.12);' : 'background-color:rgba(192,38,211,0.12);border:1px solid rgba(192,38,211,0.30);'"> :style="msg.role === 'user' ? 'background-color:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.12);' : 'background-color:rgba(192,38,211,0.12);border:1px solid rgba(192,38,211,0.30);'">
<p class="font-mono leading-relaxed whitespace-pre-line" style="font-size:7.5px;" <p class="font-mono leading-relaxed whitespace-pre-line text-[10px]"
:style="msg.role === 'user' ? 'color:rgba(255,255,255,0.65);' : 'color:#e879f9;'"> :style="msg.role === 'user' ? 'color:rgba(255,255,255,0.70);' : 'color:rgba(192,38,211,0.95);'">
<span x-text="msg.text"></span><span x-show="msg.role === 'bot' && mi === msgs.length - 1" class="dictia-blink ml-px" style="color:#c026d3;"></span> <span x-text="msg.text"></span><span x-show="msg.role === 'bot' && mi === msgs.length - 1" class="dictia-blink ml-px text-brand-b3"></span>
</p> </p>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
<div class="flex items-center justify-center gap-1 py-1.5 flex-shrink-0" style="border-top:1px solid rgba(192,38,211,0.08);"> <div class="flex items-center justify-center gap-1.5 py-2 flex-shrink-0" style="border-top:1px solid rgba(192,38,211,0.10);background:rgba(192,38,211,0.03);">
<span class="font-mono" style="font-size:5.5px;color:rgba(239,68,68,0.55);letter-spacing:0.06em;">0 donnée envoyée au cloud</span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="shrink-0" style="width:9px;height:9px;color:rgba(16,185,129,0.85);" aria-hidden="true">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
<span class="font-mono text-[9px] tracking-wide" style="color:rgba(16,185,129,0.85);">0 donnée envoyée au cloud</span>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
{# BOTTOM : 6 feature icons + label + tab indicator + Auto pill — hauteur fixe 90px (cadre stable) #} {# BOTTOM : 6 feature icons + label + tab indicator + Auto pill — hauteur fixe 90px (cadre stable) #}
<div class="relative flex flex-col items-center justify-center gap-1 z-10 flex-shrink-0" <div class="relative flex flex-col items-center justify-center gap-1.5 z-10 flex-shrink-0"
style="height: 90px; border-top: 1px solid rgba(255,255,255,0.06); background: linear-gradient(180deg, transparent, rgba(0,0,0,0.30));"> style="height: 90px; border-top: 1px solid rgba(255,255,255,0.06); background: linear-gradient(180deg, transparent, rgba(0,0,0,0.32));">
<div class="flex items-end gap-1.5"> <div class="flex items-end gap-1">
<template x-for="i in [1,2,3,4,5,6]" :key="i"> <template x-for="i in [1,2,3,4,5,6]" :key="i">
<button type="button" @click="handleManualSelect(i)" <button type="button" @click="handleManualSelect(i)"
class="dictia-feat-btn outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-white/40 rounded-md flex flex-col items-center justify-end relative" class="dictia-feat-btn outline-none cursor-pointer focus-visible:ring-2 focus-visible:ring-white/40 flex flex-col items-center justify-end relative"
:style="`background-color: ${selectedFeature === i ? FEATURES[i].color + '14' : 'transparent'}; border:none; padding: 4px 5px 6px; opacity: ${selectedFeature === i ? 1 : 0.55}; min-width: 30px;`" style="width:34px;height:42px;border:none;padding:4px 0 6px;background:transparent;"
:aria-pressed="selectedFeature === i ? 'true' : 'false'" :aria-pressed="selectedFeature === i ? 'true' : 'false'"
:aria-label="`Voir : ${FEATURES[i].title}`"> :aria-label="`Voir : ${FEATURES[i].title}`">
<span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.42)'}; transition: color 0.2s, transform 0.15s, filter 0.2s; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'CC)' : 'none'}; transform: scale(${selectedFeature === i ? 1.18 : 1}); display: inline-block;`"> <span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.30)'}; transition: color 0.2s, transform 0.15s, filter 0.2s; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'CC)' : 'none'}; transform: scale(${selectedFeature === i ? 1.15 : 1}); display: inline-block;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" aria-hidden="true" x-html="featureIconPath(i)"></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" aria-hidden="true" x-html="featureIconPath(i)"></svg>
</span> </span>
<span class="text-[7px] font-mono font-medium mt-0.5 leading-none uppercase tracking-wide" <span class="text-[9px] font-mono font-semibold mt-0.5 leading-none uppercase tracking-wider"
:style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.30)'};`" :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.40)'};`"
x-text="featureShortLabel(i)"></span> x-text="featureShortLabel(i)"></span>
{# Tab indicator bottom border #} {# Tab indicator bottom border 2px (style tab bar) #}
<span x-show="selectedFeature === i" class="absolute" aria-hidden="true" <span x-show="selectedFeature === i" class="absolute" aria-hidden="true"
:style="`bottom: 0; left: 4px; right: 4px; height: 2px; background: ${FEATURES[i].color}; border-radius: 1px; box-shadow: 0 0 6px ${FEATURES[i].color};`"></span> :style="`bottom: 0; left: 4px; right: 4px; height: 2px; background: ${FEATURES[i].color}; border-radius: 1px; box-shadow: 0 0 8px ${FEATURES[i].color};`"></span>
</button> </button>
</template> </template>
</div> </div>
{# Auto pill / Manuel countdown #} {# Auto pill / Manuel countdown — style premium pill #}
<div class="flex items-center justify-center gap-1.5" style="min-height:14px;"> <div class="flex items-center justify-center gap-1.5" style="min-height:14px;">
<template x-if="!isManual"> <template x-if="!isManual">
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full" <span class="inline-flex items-center gap-1.5 px-2.5 py-0.5 rounded-full"
style="background:rgba(16,185,129,0.10);border:1px solid rgba(16,185,129,0.25);"> style="background:rgba(16,185,129,0.12);border:1px solid rgba(16,185,129,0.30);">
<span class="dictia-auto-pulse" style="width:5px;height:5px;border-radius:50%;background:#10b981;"></span> <span class="dictia-auto-pulse block rounded-full" style="width:5px;height:5px;background:#10b981;"></span>
<span class="font-mono" style="font-size:7px;color:#10b981;letter-spacing:0.12em;font-weight:700;">AUTO</span> <span class="font-mono text-[9px] font-bold tracking-widest uppercase" style="color:#10b981;">Auto</span>
</span> </span>
</template> </template>
<template x-if="isManual"> <template x-if="isManual">
<span class="inline-flex flex-col items-center gap-0.5"> <span class="inline-flex flex-col items-center gap-0.5">
<span class="font-mono" style="font-size:7.5px;color:rgba(255,255,255,0.55);" x-text="'Auto reprend bientôt'"></span> <span class="font-mono text-[9px] text-white/60">Auto reprend bientôt</span>
<span class="rounded-full overflow-hidden" style="width:50px;height:2px;background:rgba(255,255,255,0.10);"> <span class="rounded-full overflow-hidden" style="width:56px;height:2px;background:rgba(255,255,255,0.12);">
<span class="block dictia-countdown-fill h-full" :key="selectedFeature" style="background:linear-gradient(90deg,#06b6d4,#c026d3);"></span> <span class="block dictia-countdown-fill h-full" :key="selectedFeature" style="background:linear-gradient(90deg,#06b6d4,#c026d3);"></span>
</span> </span>
</span> </span>
@@ -973,22 +999,25 @@
</div>{# /dictia-phone-shell #} </div>{# /dictia-phone-shell #}
</div>{# /phone wrapper (glow ring) #} </div>{# /phone wrapper (glow ring) #}
{# Feature info card sous le phone — premium look avec icon container + hover lift #} {# Feature info card sous le phone — uniform bg-white/[0.06] + accent border-left tab indicator #}
<div style="min-height:64px;width:280px;max-width:100%;" class="mt-3 mx-auto"> <div style="min-height:64px;width:280px;max-width:100%;" class="mt-3 mx-auto">
<div class="dictia-feature-card rounded-xl px-4 py-3 relative" <div class="dictia-feature-card rounded-xl px-4 py-3 relative bg-white/[0.06] border border-white/[0.10] overflow-hidden"
:style="`background-color: ${activeColor}10; border: 1px solid ${activeColor}38; box-shadow: 0 6px 24px ${activeColor}1F;`"> :style="`box-shadow: 0 6px 24px rgba(0,0,0,0.20);`">
{# Border-left 3px accent — style tab indicator #}
<span class="absolute left-0 top-0 bottom-0" aria-hidden="true"
:style="`width:3px;background:${activeColor};box-shadow:0 0 8px ${activeColor}80;`"></span>
{# Badge top-right #} {# Badge top-right #}
<template x-if="FEATURES[displayMode].badge"> <template x-if="FEATURES[displayMode].badge">
<span class="absolute text-[7.5px] px-1.5 py-0.5 rounded font-mono font-bold" <span class="absolute text-[10px] px-1.5 py-0.5 rounded font-mono font-bold tracking-wider"
style="top:8px;right:8px;letter-spacing:0.08em;" style="top:8px;right:8px;"
:style="`background-color: ${activeColor}22; color: ${activeColor}; border: 1px solid ${activeColor}55;`" :style="`background-color: ${activeColor}22; color: ${activeColor}; border: 1px solid ${activeColor}55;`"
x-text="FEATURES[displayMode].badge"></span> x-text="FEATURES[displayMode].badge"></span>
</template> </template>
<div class="flex items-start gap-2.5"> <div class="flex items-start gap-2.5">
{# Icon container 32×32 #} {# Icon container 32×32 #}
<span class="rounded-lg flex items-center justify-center flex-shrink-0" <span class="rounded flex items-center justify-center flex-shrink-0"
style="width:32px;height:32px;" style="width:32px;height:32px;"
:style="`background-color: ${activeColor}18; border: 1px solid ${activeColor}33;`" :style="`background-color: ${activeColor}26; border: 1px solid ${activeColor}40;`"
aria-hidden="true"> aria-hidden="true">
<span :style="`color: ${activeColor};`"> <span :style="`color: ${activeColor};`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" x-html="featureIconPath(displayMode)"></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" x-html="featureIconPath(displayMode)"></svg>
@@ -996,7 +1025,7 @@
</span> </span>
<div class="flex-1 min-w-0 pr-12"> <div class="flex-1 min-w-0 pr-12">
<p class="text-sm font-bold text-white leading-tight mb-0.5" x-text="FEATURES[displayMode].title"></p> <p class="text-sm font-bold text-white leading-tight mb-0.5" x-text="FEATURES[displayMode].title"></p>
<p class="text-[11px] leading-snug" style="color:rgba(255,255,255,0.62);" x-text="FEATURES[displayMode].subtitle"></p> <p class="text-[11px] leading-snug text-white/65" x-text="FEATURES[displayMode].subtitle"></p>
</div> </div>
</div> </div>
</div> </div>
@@ -1024,105 +1053,104 @@
{# ─────────── ZONE RIGHT : IA Mistral premium card + grid 6 features ─────────── #} {# ─────────── ZONE RIGHT : IA Mistral premium card + grid 6 features ─────────── #}
<div class="flex flex-col gap-3 w-full lg:w-[320px] flex-shrink-0 relative z-10"> <div class="flex flex-col gap-3 w-full lg:w-[320px] flex-shrink-0 relative z-10">
{# Eyebrow + title — alignés sur le système typo #}
<div class="mb-1 flex items-center gap-2"> <div class="mb-1 flex items-center gap-2">
<span class="block w-1 h-5 rounded-full" style="background:linear-gradient(180deg,#06b6d4,#c026d3);" aria-hidden="true"></span> <span class="block w-1 h-6 rounded-full" style="background:linear-gradient(180deg,#06b6d4,#c026d3);" aria-hidden="true"></span>
<div> <div>
<p class="text-[9px] font-medium uppercase tracking-[0.22em]" style="color:rgba(192,38,211,0.95);">Fonctions clés</p> <p class="text-xs font-mono font-bold uppercase tracking-widest text-brand-b3">Fonctions clés</p>
<p class="font-bold text-base leading-snug text-brand-navy">Le moteur IA local</p> <p class="font-bold text-lg leading-snug text-brand-navy">Le moteur IA local</p>
</div> </div>
</div> </div>
{# IA Mistral 7B premium card — couleurs brand-b3 (fuchsia officiel) #} {# IA Mistral 7B premium card — couleurs brand-b3 (fuchsia officiel) #}
<div class="relative rounded-xl overflow-hidden" <div class="relative rounded-xl overflow-hidden border-brand-b3/30 border-[1.5px]"
style="border:1.5px solid rgba(192,38,211,0.32);background-color:rgba(8,12,24,0.92);box-shadow:0 0 32px rgba(192,38,211,0.18), 0 12px 40px -10px rgba(0,0,0,0.5);"> style="background-color:rgba(8,12,24,0.92);box-shadow:0 0 28px rgba(192,38,211,0.18), 0 12px 40px -10px rgba(0,0,0,0.5);">
{# Ambient fuchsia glow #} {# Ambient fuchsia glow #}
<div class="absolute inset-0 pointer-events-none ia-ambient-glow" <div class="absolute inset-0 pointer-events-none ia-ambient-glow"
style="border-radius:inherit;background:radial-gradient(ellipse 120% 60% at 15% 50%, rgba(192,38,211,0.22) 0%, transparent 70%);" style="border-radius:inherit;background:radial-gradient(ellipse 120% 60% at 15% 50%, rgba(192,38,211,0.22) 0%, transparent 70%);"
aria-hidden="true"></div> aria-hidden="true"></div>
{# Header — Brain in 40x40 circle #} {# Header — Brain in 40x40 circle (premium feel) #}
<div class="relative px-4 pt-4 pb-3 flex items-start gap-3"> <div class="relative p-5 flex items-start gap-3">
<div class="relative flex-shrink-0"> <div class="relative flex-shrink-0">
<div class="absolute -inset-3 rounded-full pointer-events-none ia-brain-glow" <div class="absolute -inset-3 rounded-full pointer-events-none ia-brain-glow"
style="background:radial-gradient(circle, rgba(192,38,211,0.55) 0%, transparent 70%);" style="background:radial-gradient(circle, rgba(192,38,211,0.55) 0%, transparent 70%);"
aria-hidden="true"></div> aria-hidden="true"></div>
<div class="rounded-full flex items-center justify-center relative" <div class="rounded-full flex items-center justify-center relative"
style="width:40px;height:40px;background:linear-gradient(135deg, rgba(192,38,211,0.30), rgba(192,38,211,0.12));border:1.5px solid rgba(192,38,211,0.50);box-shadow:0 4px 12px rgba(192,38,211,0.20);"> style="width:40px;height:40px;background:linear-gradient(135deg, rgba(192,38,211,0.30), rgba(192,38,211,0.12));border:1.5px solid rgba(192,38,211,0.50);box-shadow:0 4px 12px rgba(192,38,211,0.20);">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3" style="width:20px;height:20px;position:relative;z-index:1;" aria-hidden="true"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3 relative" style="width:20px;height:20px;z-index:1;" aria-hidden="true">
<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/> <path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/>
<path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/> <path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>
</svg> </svg>
</div> </div>
</div> </div>
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<div class="flex items-center gap-1.5 flex-wrap"> <span class="font-bold text-lg text-white block">IA intégrée</span>
<span class="font-bold text-base text-white">IA intégrée</span> <div class="flex items-center gap-1.5 flex-wrap mt-1.5">
</div> <span class="text-[10px] px-2 py-0.5 rounded font-mono font-bold tracking-wider text-brand-b3"
<div class="flex items-center gap-1.5 flex-wrap mt-1"> style="background-color:rgba(192,38,211,0.22);border:1px solid rgba(192,38,211,0.45);">MISTRAL 7B</span>
<span class="text-[9px] px-2 py-0.5 rounded-md font-mono font-bold" <span class="text-[10px] px-2 py-0.5 rounded font-mono font-bold ia-local-badge inline-flex items-center gap-1 tracking-widest"
style="background-color:rgba(192,38,211,0.22);color:#e879f9;border:1px solid rgba(192,38,211,0.45);letter-spacing:0.08em;">MISTRAL 7B</span> style="background-color:rgba(16,185,129,0.14);color:#10b981;border:1px solid rgba(16,185,129,0.40);">
<span class="text-[8px] px-2 py-0.5 rounded font-mono font-bold ia-local-badge inline-flex items-center gap-1" <span class="dictia-dot-pulse block rounded-full" style="width:4px;height:4px;background:#10b981;"></span>
style="background-color:rgba(16,185,129,0.14);color:#10b981;border:1px solid rgba(16,185,129,0.40);letter-spacing:0.12em;">
<span class="dictia-dot-pulse" style="width:4px;height:4px;border-radius:50%;background:#10b981;"></span>
LOCAL LOCAL
</span> </span>
</div> </div>
<p class="text-[11px] mt-1.5" style="color:rgba(255,255,255,0.62);">Résumé · Points d'action · Q&amp;R</p> <p class="text-xs mt-2 text-white/65">Résumé · Points d'action · Q&amp;R</p>
</div> </div>
</div> </div>
{# Divider #} {# Divider #}
<div style="height:1px;background:linear-gradient(90deg, transparent, rgba(192,38,211,0.30), transparent);" aria-hidden="true"></div> <div style="height:1px;background:linear-gradient(90deg, transparent, rgba(192,38,211,0.30), transparent);" aria-hidden="true"></div>
{# Performance metrics 3 cells #} {# Performance metrics 3 cells — chiffres en grad-text font-bold #}
<div class="relative grid grid-cols-3 gap-0"> <div class="relative grid grid-cols-3 gap-0">
<div class="text-center py-2.5 px-1" style="border-right:1px solid rgba(192,38,211,0.10);"> <div class="text-center py-3 px-1" style="border-right:1px solid rgba(192,38,211,0.10);">
<p class="font-mono font-black text-base text-white leading-none">0&thinsp;ms</p> <p class="font-mono font-black text-lg leading-none grad-text">0&thinsp;ms</p>
<p class="text-[8px] mt-1 uppercase tracking-wider" style="color:rgba(192,38,211,0.65);">latence</p> <p class="text-[10px] mt-1 uppercase tracking-wider font-semibold" style="color:rgba(192,38,211,0.70);">latence</p>
</div> </div>
<div class="text-center py-2.5 px-1" style="border-right:1px solid rgba(192,38,211,0.10);"> <div class="text-center py-3 px-1" style="border-right:1px solid rgba(192,38,211,0.10);">
<p class="font-mono font-black text-base leading-none" style="color:#10b981;">100&thinsp;%</p> <p class="font-mono font-black text-lg leading-none" style="color:#10b981;">100&thinsp;%</p>
<p class="text-[8px] mt-1 uppercase tracking-wider" style="color:rgba(192,38,211,0.65);">privé</p> <p class="text-[10px] mt-1 uppercase tracking-wider font-semibold" style="color:rgba(192,38,211,0.70);">privé</p>
</div> </div>
<div class="text-center py-2.5 px-1"> <div class="text-center py-3 px-1">
<p class="font-mono font-black text-base leading-none" style="color:#e879f9;">24/7</p> <p class="font-mono font-black text-lg leading-none grad-text">24/7</p>
<p class="text-[8px] mt-1 uppercase tracking-wider" style="color:rgba(192,38,211,0.65);">dispo</p> <p class="text-[10px] mt-1 uppercase tracking-wider font-semibold" style="color:rgba(192,38,211,0.70);">dispo</p>
</div> </div>
</div> </div>
{# Divider #} {# Divider #}
<div style="height:1px;background:linear-gradient(90deg, transparent, rgba(192,38,211,0.22), transparent);" aria-hidden="true"></div> <div style="height:1px;background:linear-gradient(90deg, transparent, rgba(192,38,211,0.22), transparent);" aria-hidden="true"></div>
{# Sovereignty bullets — chacun avec icon dans cercle #} {# Sovereignty bullets — chacun avec icon dans cercle 20×20 brand-b3/[0.15] #}
<div class="relative px-4 py-3 flex flex-col gap-2.5"> <div class="relative p-5 flex flex-col gap-3">
<div class="flex items-start gap-2.5"> <div class="flex items-start gap-2.5">
<span class="rounded-md flex items-center justify-center flex-shrink-0 mt-0.5" <span class="rounded-full flex items-center justify-center flex-shrink-0 mt-0.5 bg-brand-b3/[0.15] border border-brand-b3/30"
style="width:18px;height:18px;background:rgba(192,38,211,0.14);border:1px solid rgba(192,38,211,0.30);" style="width:20px;height:20px;"
aria-hidden="true"> aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3" style="width:10px;height:10px;opacity:0.85;"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3" style="width:11px;height:11px;">
<rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/> <rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/>
<line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/> <line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/>
</svg> </svg>
</span> </span>
<span class="text-[11px] leading-snug" style="color:rgba(255,255,255,0.88);"><strong>Données hébergées sur VOS serveurs</strong> · jamais partagées</span> <span class="text-[11px] leading-snug text-white/90"><strong class="font-bold">Données hébergées sur VOS serveurs</strong> · jamais partagées</span>
</div> </div>
<div class="flex items-start gap-2.5"> <div class="flex items-start gap-2.5">
<span class="rounded-md flex items-center justify-center flex-shrink-0 mt-0.5" <span class="rounded-full flex items-center justify-center flex-shrink-0 mt-0.5 bg-brand-b3/[0.15] border border-brand-b3/30"
style="width:18px;height:18px;background:rgba(192,38,211,0.14);border:1px solid rgba(192,38,211,0.30);" style="width:20px;height:20px;"
aria-hidden="true"> aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3" style="width:10px;height:10px;opacity:0.85;"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-brand-b3" style="width:11px;height:11px;">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/> <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="M9 12l2 2 4-4"/>
</svg> </svg>
</span> </span>
<span class="text-[11px] leading-snug" style="color:rgba(255,255,255,0.72);">Zéro connexion OpenAI · Google · Microsoft</span> <span class="text-[11px] leading-snug text-white/75">Zéro connexion OpenAI · Google · Microsoft</span>
</div> </div>
<div class="flex items-start gap-2.5"> <div class="flex items-start gap-2.5">
<span class="rounded-md flex items-center justify-center flex-shrink-0 mt-0.5" <span class="rounded-full flex items-center justify-center flex-shrink-0 mt-0.5 bg-brand-b3/[0.15] border border-brand-b3/30"
style="width:18px;height:18px;background:rgba(192,38,211,0.14);border:1px solid rgba(192,38,211,0.30);" style="width:20px;height:20px;"
aria-hidden="true"> aria-hidden="true">
<svg viewBox="0 0 24 24" fill="currentColor" stroke="none" class="text-brand-b3" style="width:10px;height:10px;opacity:0.85;"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg> <svg viewBox="0 0 24 24" fill="currentColor" stroke="none" class="text-brand-b3" style="width:11px;height:11px;"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
</span> </span>
<span class="text-[11px] leading-snug" style="color:rgba(255,255,255,0.72);">Inférence hors-ligne · résultats en secondes</span> <span class="text-[11px] leading-snug text-white/75">Inférence hors-ligne · résultats en secondes</span>
</div> </div>
</div> </div>
</div> </div>
@@ -1131,15 +1159,15 @@
<div class="grid grid-cols-3 gap-2"> <div class="grid grid-cols-3 gap-2">
<template x-for="i in [1,2,3,4,5,6]" :key="i"> <template x-for="i in [1,2,3,4,5,6]" :key="i">
<button type="button" @click="handleManualSelect(i)" <button type="button" @click="handleManualSelect(i)"
class="flex flex-col items-center gap-1 rounded-xl py-3 px-1 outline-none transition-all focus-visible:ring-2 focus-visible:ring-white/40" class="flex flex-col items-center gap-1.5 rounded-xl py-3 px-2 outline-none transition-all focus-visible:ring-2 focus-visible:ring-white/40"
:style="`border: 1px solid ${selectedFeature === i ? FEATURES[i].color + '60' : 'rgba(255,255,255,0.08)'}; background-color: ${selectedFeature === i ? FEATURES[i].color + '14' : 'rgba(8,12,24,0.85)'}; box-shadow: ${selectedFeature === i ? '0 0 16px ' + FEATURES[i].color + '30, inset 0 0 12px ' + FEATURES[i].color + '10' : 'none'}; cursor: pointer;`" :style="`border: 1px solid ${selectedFeature === i ? FEATURES[i].color + '60' : 'rgba(255,255,255,0.10)'}; background-color: ${selectedFeature === i ? FEATURES[i].color + '14' : 'rgba(8,12,24,0.85)'}; box-shadow: ${selectedFeature === i ? '0 0 16px ' + FEATURES[i].color + '30, inset 0 0 12px ' + FEATURES[i].color + '10' : 'none'}; cursor: pointer;`"
:aria-pressed="selectedFeature === i ? 'true' : 'false'" :aria-pressed="selectedFeature === i ? 'true' : 'false'"
:aria-label="`Sélectionner : ${FEATURES[i].title}`"> :aria-label="`Sélectionner : ${FEATURES[i].title}`">
<span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.50)'}; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'BB)' : 'none'}; transform: scale(${selectedFeature === i ? 1.25 : 1}) translateY(${selectedFeature === i ? -1 : 0}px); transition: all 0.2s; display:inline-block;`"> <span :style="`color: ${selectedFeature === i ? FEATURES[i].color : 'rgba(255,255,255,0.55)'}; filter: ${selectedFeature === i ? 'drop-shadow(0 0 6px ' + FEATURES[i].color + 'BB)' : 'none'}; transform: scale(${selectedFeature === i ? 1.20 : 1}) translateY(${selectedFeature === i ? -1 : 0}px); transition: all 0.2s; display:inline-block;`">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px;" aria-hidden="true" x-html="featureIconPath(i)"></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px;" aria-hidden="true" x-html="featureIconPath(i)"></svg>
</span> </span>
<span class="text-[8px] font-medium text-center leading-tight" <span class="text-[10px] font-semibold text-center leading-tight"
:style="`color: ${selectedFeature === i ? 'rgba(255,255,255,0.95)' : 'rgba(255,255,255,0.60)'}; transition: color 0.2s;`" :style="`color: ${selectedFeature === i ? 'rgba(255,255,255,0.95)' : 'rgba(255,255,255,0.65)'}; transition: color 0.2s;`"
x-text="FEATURES[i].title"></span> x-text="FEATURES[i].title"></span>
</button> </button>
</template> </template>
@@ -1271,8 +1299,8 @@
/* Mode 3 — Langues : grille 100 codes (ripple depuis centre + highlight aléatoire) */ /* Mode 3 — Langues : grille 100 codes (ripple depuis centre + highlight aléatoire) */
function langModeData() { function langModeData() {
return { return {
/* Cycle uniquement entre brand-b1 / brand-b2 / brand-b3 + déclinaisons */ /* Cycle EXCLUSIVEMENT entre brand-b1 / brand-b2 / brand-b3 (palette canonique stricte) */
LANG_COLORS: ['#06b6d4','#2563eb','#c026d3','#0891b2','#1d4ed8','#a21caf','#06b6d4','#2563eb'], LANG_COLORS: ['#2563eb','#06b6d4','#c026d3','#06b6d4','#2563eb','#c026d3','#2563eb','#06b6d4'],
LANGS: [ LANGS: [
'FR','EN','ES','DE','PT','IT','NL','PL','ZH','JA', 'FR','EN','ES','DE','PT','IT','NL','PL','ZH','JA',
'KO','AR','RU','HI','TR','VI','TH','SV','DA','NO', 'KO','AR','RU','HI','TR','VI','TH','SV','DA','NO',
@@ -1301,17 +1329,17 @@
}; };
} }
/* Mode 4 — Exports : 7 file types staggered 90ms (CSS-only) */ /* Mode 4 — Exports : 7 file types staggered 90ms (CSS-only) — palette brand stricte */
function expModeData() { function expModeData() {
return { return {
FILE_TYPES: [ FILE_TYPES: [
{ ext: 'DOCX', bg: '#2563eb', fg: '#fff', sym: 'W' }, /* brand-b1 blue */ { ext: 'DOCX', bg: '#2563eb', fg: '#ffffff', sym: 'W' }, /* brand-b1 blue */
{ ext: 'PDF', bg: '#dc2626', fg: '#fff', sym: 'PDF' }, /* red sémantique conservé pour fichier PDF */ { ext: 'PDF', bg: '#dc2626', fg: '#ffffff', sym: 'PDF' }, /* red sémantique conservé pour fichier PDF */
{ ext: 'SRT', bg: '#c026d3', fg: '#fff', sym: 'CC' }, /* brand-b3 fuchsia */ { ext: 'SRT', bg: '#c026d3', fg: '#ffffff', sym: 'CC' }, /* brand-b3 fuchsia */
{ ext: 'VTT', bg: '#9333ea', fg: '#f5d0fe', sym: 'CC' }, /* purple-600 (déclinaison b3) */ { ext: 'VTT', bg: '#c026d3', fg: '#ffffff', sym: 'CC' }, /* brand-b3 fuchsia */
{ ext: 'TXT', bg: '#374151', fg: '#9CA3AF', sym: '≡' }, /* gray-700 neutre */ { ext: 'TXT', bg: '#374151', fg: '#d1d5db', sym: '≡' }, /* gray-700 neutre (sémantique TXT raw) */
{ ext: 'JSON', bg: '#0e7490', fg: '#67e8f9', sym: '{}' }, /* cyan-700 (déclinaison b2) */ { ext: 'JSON', bg: '#06b6d4', fg: '#ffffff', sym: '{}' }, /* brand-b2 aqua */
{ ext: 'MD', bg: '#1e40af', fg: '#93c5fd', sym: '#' } /* blue-700 (déclinaison b1) */ { ext: 'MD', bg: '#2563eb', fg: '#ffffff', sym: '#' } /* brand-b1 blue */
] ]
}; };
} }
@@ -1320,8 +1348,8 @@
function usersModeData() { function usersModeData() {
return { return {
MAX: 20, count: 1, cycle: 0, _iv: null, MAX: 20, count: 1, cycle: 0, _iv: null,
/* Uniquement brand-b1 / brand-b2 / brand-b3 + déclinaisons */ /* EXCLUSIVEMENT brand-b1 / brand-b2 / brand-b3 (palette canonique stricte) */
USER_COLORS: ['#c026d3', '#06b6d4', '#2563eb', '#a21caf', '#0891b2'], USER_COLORS: ['#c026d3', '#06b6d4', '#2563eb'],
init() { init() {
if (this._iv) clearInterval(this._iv); if (this._iv) clearInterval(this._iv);
this.count = 1; this.count = 1;

View File

@@ -254,6 +254,25 @@ def test_fonctionnalites_how_it_works_reactor_section():
assert 'cloud' in body, "Missing stats row 'cloud'" assert 'cloud' in body, "Missing stats row 'cloud'"
assert 'Voir une démo' in body, "Missing demo CTA link" assert 'Voir une démo' in body, "Missing demo CTA link"
# ── HYPER PRO polish 2026-04-29 (audit purge non-brand hex + uniformization) ──
# Brand canonical palette ONLY in JS color tables (no purple-600/cyan-700/blue-700/...)
js_section = body[body.find("function dictiaDashboard()"):body.find("</script>", body.find("function dictiaDashboard()"))]
forbidden_hex = ['#9333ea', '#1d4ed8', '#a21caf', '#0e7490', '#0891b2',
'#1e40af', '#67e8f9', '#93c5fd', '#f5d0fe', '#e879f9',
'#A78BFA', '#22D3EE', '#6B9FFF', '#34D399', '#F59E0B',
'#7C3AED', '#5B21B6', '#065F46', '#1C3A5E']
for hx in forbidden_hex:
assert hx not in body, f"Forbidden non-brand hex {hx} found in fonctionnalites — must purge"
# Inner screen seam (effet "écran encastré")
assert 'dictia-phone-screen-seam' in body, "Missing inner screen seam (encastré effect)"
# Uniform feature info card — bg-white/[0.06] + accent border-left
assert 'bg-white/[0.06]' in body, "Missing uniform white/0.06 bg on feature card"
# Sovereignty bullets : icon dans cercle 20×20 brand-b3/[0.15]
assert 'bg-brand-b3/[0.15]' in body, "Missing brand-b3 circle bg on sovereignty bullets"
# Performance metrics : 3 cells with grad-text for 0ms / 24/7
assert 'grad-text' in body, "Missing grad-text on metrics"
def test_fonctionnalites_export_formats_section(): def test_fonctionnalites_export_formats_section():
client = app.test_client() client = app.test_client()