verify / verifier-module.html
YassmineNouisser
Replace deepfake video with AI-generated video detection (GPT-4o multi-frame)
e8ad705
Raw
History Blame Contribute Delete
247 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Module verifier — Verify</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;800&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="assets/css/styles.css?v=32" />
<style>
/* ════════════════════════════════════════════════════════════════════
Coherence module — premium editorial design
════════════════════════════════════════════════════════════════════ */
/* ─── Inputs (tabs + drop-zone + textarea + buttons) ─────────────── */
.coh-tabs { display:flex; gap:4px; border-bottom:1px solid var(--line); margin-bottom:24px; }
.coh-tab { padding:12px 22px; cursor:pointer; font-weight:600; color:var(--ink-soft); border-bottom:2px solid transparent; user-select:none; transition:color .15s ease, border-color .15s ease; }
.coh-tab:hover { color:var(--navy); }
.coh-tab.active { color:var(--navy); border-bottom-color:var(--navy); }
.coh-pane { display:none; }
.coh-pane.active { display:block; }
.coh-form { display:grid; grid-template-columns:1fr; gap:20px; }
.coh-drop { border:2px dashed var(--line); padding:32px; text-align:center; cursor:pointer; transition:background .2s ease, border-color .2s ease; }
.coh-drop:hover, .coh-drop.hover { background:#f8fafc; border-color:var(--navy); }
.coh-drop.has-file { border-style:solid; padding:16px; text-align:left; background:#fff; }
.coh-preview { max-width:100%; max-height:280px; border:1px solid var(--line); }
.coh-textarea { width:100%; padding:12px 14px; border:1px solid var(--line); font-family:inherit; font-size:15px; line-height:1.5; resize:vertical; min-height:90px; outline:none; transition:border-color .15s ease; }
.coh-textarea:focus { border-color:var(--navy); }
.coh-cta { display:flex; gap:14px; align-items:center; flex-wrap:wrap; }
.coh-status { font-size:14px; color:var(--ink-soft); }
.coh-error { padding:14px; background:#fef2f2; border-left:3px solid var(--red); color:#991b1b; font-size:14px; }
.api-banner { background:#fff8b3; border-left:3px solid var(--navy); padding:10px 14px; font-size:13px; margin-bottom:16px; }
.api-banner.ok { background:#dcfce7; border-left-color:#16a34a; }
.api-banner.err { background:#fee2e2; border-left-color:#dc2626; }
.spinner { width:18px; height:18px; border:2.5px solid #e2e8f0; border-top-color:var(--navy); border-radius:50%; animation:spin 0.7s linear infinite; display:inline-block; vertical-align:middle; }
@keyframes spin { to { transform: rotate(360deg); } }
/* ─── Result list animation ──────────────────────────────────────── */
@keyframes fadeUp { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:none; } }
.coh-results > * { animation: fadeUp .55s cubic-bezier(.16,1,.3,1) both; }
.coh-results > *:nth-child(1) { animation-delay:0s; }
.coh-results > *:nth-child(2) { animation-delay:.07s; }
.coh-results > *:nth-child(3) { animation-delay:.14s; }
.coh-results > *:nth-child(4) { animation-delay:.21s; }
.coh-results > *:nth-child(5) { animation-delay:.28s; }
.coh-results > *:nth-child(6) { animation-delay:.35s; }
.coh-results > *:nth-child(7) { animation-delay:.42s; }
.coh-results > *:nth-child(8) { animation-delay:.49s; }
/* ════════════════════════════════════════════════════════════════════
HERO — Verdict + circular SVG gauge
════════════════════════════════════════════════════════════════════ */
.verdict-hero {
position:relative; overflow:hidden;
padding:38px 44px;
background:
radial-gradient(circle at top right, var(--vh-glow, rgba(22,163,74,.10)) 0%, transparent 60%),
linear-gradient(135deg, var(--vh-bg1, #f0fdf4) 0%, #ffffff 70%);
border:1px solid var(--line);
border-left:6px solid var(--vh-bd);
display:grid;
grid-template-columns: 1fr auto;
align-items:center;
gap:48px;
}
.verdict-hero::before {
content:""; position:absolute; right:-80px; top:-80px;
width:280px; height:280px; border-radius:50%;
background:var(--vh-glow); opacity:.5;
pointer-events:none;
}
.verdict-hero[data-v="COHERENT"] { --vh-bg1:#ecfdf5; --vh-bd:#16a34a; --vh-ink:#14532d; --vh-glow:rgba(22,163,74,.13); --vh-arc:#16a34a; --vh-icon-bg:#dcfce7; }
.verdict-hero[data-v="SUSPECT"] { --vh-bg1:#fffbeb; --vh-bd:#f59e0b; --vh-ink:#78350f; --vh-glow:rgba(245,158,11,.16); --vh-arc:#f59e0b; --vh-icon-bg:#fef3c7; }
.verdict-hero[data-v="INCOHERENT"] { --vh-bg1:#fef2f2; --vh-bd:#dc2626; --vh-ink:#7f1d1d; --vh-glow:rgba(220,38,38,.13); --vh-arc:#dc2626; --vh-icon-bg:#fee2e2; }
.vh-left { position:relative; z-index:1; }
.vh-status { display:inline-flex; align-items:center; gap:10px; margin-bottom:18px; }
.vh-status-icon {
width:42px; height:42px; border-radius:50%;
background:var(--vh-icon-bg); color:var(--vh-bd);
display:flex; align-items:center; justify-content:center;
font-size:22px; font-weight:700;
}
.vh-status-label {
font-size:11px; text-transform:uppercase; letter-spacing:1.6px;
color:var(--ink-soft); font-weight:600;
}
.vh-status-label strong { display:block; font-size:13px; color:var(--ink); margin-top:2px; letter-spacing:.6px; text-transform:none; font-weight:700; }
.vh-verdict { font-family:'Playfair Display',serif; font-size:62px; font-weight:800; line-height:.95; color:var(--vh-ink); letter-spacing:-1.5px; }
.vh-sub { margin-top:14px; font-size:15px; color:var(--ink-soft); max-width:480px; line-height:1.55; }
.vh-meta { margin-top:22px; display:flex; gap:24px; flex-wrap:wrap; font-size:12px; color:var(--ink-soft); }
.vh-meta > div { display:flex; flex-direction:column; }
.vh-meta .k { font-size:10px; text-transform:uppercase; letter-spacing:1.2px; }
.vh-meta .v { font-weight:700; color:var(--ink); margin-top:3px; font-size:13px; }
/* SVG gauge */
.vh-gauge { position:relative; width:200px; height:200px; flex-shrink:0; z-index:1; }
.vh-gauge svg { width:100%; height:100%; transform:rotate(-90deg); }
.vh-gauge .gauge-bg { fill:none; stroke:#f1f5f9; stroke-width:14; }
.vh-gauge .gauge-arc {
fill:none; stroke:var(--vh-arc); stroke-width:14;
stroke-linecap:round;
stroke-dasharray:0 1000;
transition:stroke-dasharray 1.4s cubic-bezier(.16,1,.3,1);
}
.vh-gauge .gauge-thresh-good { fill:none; stroke:#16a34a; stroke-width:2; stroke-dasharray:3 4; opacity:.5; }
.vh-gauge .gauge-center { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; }
.vh-gauge .gauge-num { font-family:'Playfair Display',serif; font-weight:800; font-size:42px; line-height:1; color:var(--ink); font-variant-numeric:tabular-nums; }
.vh-gauge .gauge-label { font-size:10px; text-transform:uppercase; letter-spacing:1.5px; color:var(--ink-soft); margin-top:6px; }
.vh-gauge .gauge-thresh-line {
position:absolute; inset:0; pointer-events:none;
font-size:9px; text-transform:uppercase; letter-spacing:1px; color:var(--ink-faint);
}
@media (max-width: 760px) {
.verdict-hero { grid-template-columns:1fr; gap:24px; padding:28px 24px; }
.vh-verdict { font-size:42px; }
.vh-gauge { width:160px; height:160px; margin:0 auto; }
}
/* ════════════════════════════════════════════════════════════════════
PIPELINE FLOW (mini diagram)
════════════════════════════════════════════════════════════════════ */
.pipeline-flow {
display:flex; align-items:stretch; gap:0;
border:1px solid var(--line); background:#fff;
overflow:hidden;
}
.pipeline-step {
flex:1; padding:14px 12px; text-align:center;
border-right:1px solid var(--line);
position:relative;
transition:background .2s ease;
}
.pipeline-step:last-child { border-right:0; }
.pipeline-step:hover { background:#fafbff; }
.pipeline-step .pf-icon { font-size:18px; margin-bottom:4px; display:block; }
.pipeline-step .pf-name { font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.8px; }
.pipeline-step .pf-weight { font-size:10px; color:var(--ink-soft); margin-top:2px; font-variant-numeric:tabular-nums; }
.pipeline-step .pf-bar {
position:absolute; bottom:0; left:0; height:3px;
background:var(--pf-color, var(--navy));
width:0; transition:width 1.1s cubic-bezier(.16,1,.3,1);
}
/* ════════════════════════════════════════════════════════════════════
SECTION CARDS — editorial, numbered
════════════════════════════════════════════════════════════════════ */
.coh-card {
padding:28px 30px;
border:1px solid var(--line);
background:#fff;
transition:border-color .2s ease, box-shadow .25s var(--ease-out), transform .25s var(--ease-out);
}
.coh-card:hover { border-color:#cfd8e3; box-shadow:0 12px 32px -16px rgba(15,23,42,.12); }
.coh-card + .coh-card { margin-top:14px; }
.coh-card-head {
display:flex; align-items:flex-start; justify-content:space-between;
gap:16px; margin-bottom:6px;
}
.coh-card-head-left { display:flex; align-items:flex-start; gap:14px; }
.coh-card-num {
font-family:'Playfair Display',serif; font-style:italic;
font-size:13px; font-weight:600; color:var(--ink-faint);
letter-spacing:.5px;
padding-top:6px;
flex-shrink:0;
min-width:28px;
}
.coh-card-head h3 {
font-family:'Playfair Display',serif;
font-size:26px; margin:0; line-height:1.15;
letter-spacing:-.3px;
}
.coh-card-sub { font-size:13px; color:var(--ink-soft); line-height:1.55; margin:4px 0 22px 42px; max-width:680px; }
.coh-grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:22px; }
@media (max-width: 800px) { .coh-grid-2 { grid-template-columns:1fr; } }
/* ─── Info pill (ⓘ) ───────────────────────────────────────────────── */
.info-pill {
display:inline-flex; align-items:center; justify-content:center;
width:30px; height:30px;
border:1px solid var(--line);
background:#fff;
color:var(--navy);
font-family:'Playfair Display',serif;
font-size:15px; font-weight:700; font-style:italic;
cursor:pointer;
border-radius:50%;
transition:all .18s ease;
flex-shrink:0;
position:relative;
}
.info-pill::after {
content:""; position:absolute; inset:-3px; border-radius:50%;
border:1px solid var(--navy); opacity:0;
transition:opacity .18s ease, transform .25s var(--ease-out);
}
.info-pill:hover { background:var(--navy); color:#fff; border-color:var(--navy); transform:scale(1.06); }
.info-pill:hover::after { opacity:.3; transform:scale(1.15); }
.info-pill:focus { outline:2px solid var(--yellow); outline-offset:2px; }
/* ════════════════════════════════════════════════════════════════════
SCORE BARS — with threshold markers + weight badges
════════════════════════════════════════════════════════════════════ */
.score-row {
display:grid;
grid-template-columns:200px 1fr 90px;
gap:16px; align-items:center; padding:11px 0;
border-bottom:1px solid var(--line-soft);
}
.score-row:last-child { border-bottom:0; }
.score-row .lbl { display:flex; align-items:center; gap:8px; font-size:14px; font-weight:600; }
.score-row .lbl-icon { font-size:16px; }
.score-row .lbl-weight {
font-size:10px; font-weight:700; padding:2px 7px;
background:#f1f5f9; color:var(--ink-soft);
letter-spacing:.4px; font-variant-numeric:tabular-nums;
margin-left:auto;
}
.score-row .val { font-size:14px; font-weight:700; color:var(--ink); text-align:right; font-variant-numeric:tabular-nums; }
.score-bar {
position:relative;
height:14px; background:#f1f5f9;
border-radius:2px;
}
.score-bar > .fill {
height:100%; width:0;
border-radius:2px;
transition:width 1s cubic-bezier(.16,1,.3,1);
}
/* Threshold markers (only on image-mode rows) */
.score-bar > .thresh {
position:absolute; top:-4px; bottom:-4px; width:1px;
background:rgba(15,23,42,.25);
pointer-events:none;
}
.score-bar > .thresh::after {
content:attr(data-l);
position:absolute; bottom:-15px; left:50%; transform:translateX(-50%);
font-size:9px; color:var(--ink-faint); white-space:nowrap;
letter-spacing:.3px;
}
.bar-good { background:linear-gradient(90deg, #16a34a, #22c55e); }
.bar-warn { background:linear-gradient(90deg, #f59e0b, #fbbf24); }
.bar-bad { background:linear-gradient(90deg, #dc2626, #ef4444); }
/* Threshold legend strip below the score table */
.thresh-legend {
display:flex; gap:20px; align-items:center; flex-wrap:wrap;
margin-top:18px; padding-top:14px;
border-top:1px dashed var(--line);
font-size:11px; color:var(--ink-soft);
}
.thresh-legend .swatch {
display:inline-block; width:12px; height:12px; border-radius:2px;
margin-right:6px; vertical-align:middle;
}
/* ════════════════════════════════════════════════════════════════════
DETECTIONS — chips & quote blocks
════════════════════════════════════════════════════════════════════ */
.chips-row { display:flex; flex-wrap:wrap; gap:6px; }
.chip {
display:inline-flex; align-items:center; gap:5px;
padding:5px 11px; background:#eef2ff; color:#3730a3;
font-size:12px; font-weight:600; border-radius:2px;
border:1px solid #e0e7ff;
}
.chip-num { background:#f1f5f9; color:#1e3a8a; border-color:#e2e8f0; font-variant-numeric:tabular-nums; }
.chip-mute { background:#f8fafc; color:var(--ink-soft); border-color:var(--line); }
.chip-good { background:#dcfce7; color:#166534; border-color:#bbf7d0; }
.quote-block {
background:linear-gradient(180deg, #f8fafc 0%, #ffffff 100%);
border-left:3px solid var(--navy);
padding:14px 18px;
font-size:14px; line-height:1.6;
font-style:italic; color:var(--ink);
position:relative;
}
.quote-block::before {
content:"\201C"; position:absolute; left:8px; top:-6px;
font-family:'Playfair Display',serif; font-size:38px;
color:var(--line); line-height:1;
}
.empty-note { color:var(--ink-faint); font-style:italic; font-size:13px; }
/* ════════════════════════════════════════════════════════════════════
XAI image — hover zoom indicator
════════════════════════════════════════════════════════════════════ */
.xai-img-wrap {
position:relative; cursor:zoom-in; overflow:hidden;
background:#0b1220;
margin-left:42px; /* align with card sub-text */
}
.xai-img-wrap img { width:100%; display:block; transition:transform .4s var(--ease-out); }
.xai-img-wrap:hover img { transform:scale(1.02); }
.xai-img-wrap::after {
content:"⤢ Cliquer pour agrandir";
position:absolute; right:12px; top:12px;
padding:6px 12px;
background:rgba(15,23,42,.85); color:#fff;
font-size:11px; font-weight:600; letter-spacing:.4px;
opacity:0; transform:translateY(-4px);
transition:opacity .25s ease, transform .25s ease;
backdrop-filter:blur(6px);
}
.xai-img-wrap:hover::after { opacity:1; transform:none; }
/* ════════════════════════════════════════════════════════════════════
MODAL (info popups + lightbox)
════════════════════════════════════════════════════════════════════ */
.modal-backdrop {
position:fixed; inset:0; z-index:999;
background:rgba(15,23,42,.72);
backdrop-filter:blur(4px);
display:flex; align-items:center; justify-content:center;
padding:32px;
opacity:0; pointer-events:none;
transition:opacity .3s ease;
}
.modal-backdrop.open { opacity:1; pointer-events:auto; }
.modal-box {
background:#fff;
max-width:780px; width:100%; max-height:90vh; overflow:auto;
padding:42px 48px;
transform:translateY(16px) scale(.97);
transition:transform .3s var(--ease-out);
position:relative;
box-shadow:0 50px 100px -20px rgba(0,0,0,.5);
}
.modal-backdrop.open .modal-box { transform:none; }
.modal-box h2 { font-family:'Playfair Display',serif; font-size:36px; margin:0 0 8px; line-height:1.1; letter-spacing:-.5px; }
.modal-box .modal-kicker {
font-size:11px; text-transform:uppercase; letter-spacing:1.6px;
color:var(--navy); margin-bottom:14px; font-weight:700;
}
.modal-box p { font-size:15px; line-height:1.7; color:var(--ink); margin:14px 0; }
.modal-box ul { font-size:14px; line-height:1.75; color:var(--ink); padding-left:22px; }
.modal-box ul li { margin-bottom:6px; }
.modal-box code { background:#f1f5f9; padding:2px 6px; font-family:ui-monospace, Menlo, monospace; font-size:13px; }
.modal-box .modal-tip {
background:linear-gradient(90deg, #fff8b3, #fffce0);
border-left:3px solid var(--navy); padding:14px 18px;
font-size:14px; margin-top:22px; line-height:1.55;
}
.modal-close {
position:absolute; top:18px; right:18px;
width:38px; height:38px; border:0; background:#f1f5f9;
font-size:20px; line-height:1; cursor:pointer; color:var(--ink-soft);
border-radius:50%;
transition:background .15s ease, color .15s ease;
}
.modal-close:hover { background:var(--ink); color:#fff; }
.lightbox-box { background:transparent; max-width:96vw; max-height:96vh; padding:0; box-shadow:none; }
.lightbox-box img { display:block; max-width:96vw; max-height:90vh; box-shadow:0 30px 80px rgba(0,0,0,.5); }
.lightbox-box .modal-close { background:rgba(0,0,0,.6); color:#fff; top:-44px; right:0; }
.lightbox-box .modal-close:hover { background:#fff; color:#000; }
.lightbox-caption { color:#fff; text-align:center; font-size:13px; margin-top:12px; opacity:.85; letter-spacing:.5px; }
/* ════════════════════════════════════════════════════════════════════
INTRO STRIP — "what this analysis looks at", redesigned
════════════════════════════════════════════════════════════════════ */
.coh-intro {
display:grid; grid-template-columns:1.05fr 0.95fr; gap:0;
border:1px solid var(--line); border-radius:18px;
background:linear-gradient(135deg, #fffdf2 0%, #ffffff 58%);
margin-bottom:32px; overflow:hidden;
box-shadow:0 2px 6px rgba(15,23,42,0.05);
}
@media (max-width: 840px) { .coh-intro { grid-template-columns:1fr; } }
.coh-intro-text { padding:38px 42px; display:flex; flex-direction:column; justify-content:center; }
.coh-intro-kicker {
align-self:flex-start; font-size:10.5px; text-transform:uppercase; letter-spacing:1.6px;
color:var(--navy); font-weight:800; background:var(--yellow-soft);
padding:5px 11px; border-radius:2px; margin-bottom:16px;
}
.coh-intro h2 { font-family:'Playfair Display',serif; font-size:clamp(24px,2.6vw,32px); line-height:1.13; margin:0 0 14px; letter-spacing:-.4px; }
.coh-intro p { font-size:14.5px; line-height:1.65; color:var(--ink-soft); margin:0; max-width:48ch; }
.coh-intro-modules {
padding:24px; background:linear-gradient(180deg,#f8fafc,#f3f6f9);
border-left:1px solid var(--line);
display:flex; flex-direction:column; gap:8px; justify-content:center;
counter-reset:introm;
}
@media (max-width: 840px) { .coh-intro-modules { border-left:0; border-top:1px solid var(--line); } }
.coh-intro-modules::before {
content:"Ce que l'analyse passe en revue";
font-size:10px; text-transform:uppercase; letter-spacing:1.4px; color:var(--ink-faint);
font-weight:800; margin-bottom:5px; padding-left:3px;
}
.intro-mod {
display:flex; align-items:center; gap:13px;
background:#fff; border:1px solid var(--line-soft); border-radius:11px;
padding:11px 13px; font-size:13.5px;
counter-increment:introm;
transition:transform .25s cubic-bezier(.16,1,.3,1), box-shadow .25s, border-color .25s;
}
.intro-mod:hover { transform:translateX(5px); box-shadow:0 6px 16px -8px rgba(15,23,42,.18); border-color:var(--line); }
.intro-mod .mono { width:27px; height:27px; border-radius:8px; font-size:0; flex:0 0 auto; }
.intro-mod .mono::after { content:counter(introm); font-size:12.5px; font-weight:800; font-family:'Playfair Display',serif; color:#fff; }
.intro-mod .ico { display:none; }
.intro-mod .nm { flex:1 1 auto; font-weight:600; color:var(--ink); line-height:1.3; }
.intro-mod .nm small { display:block; color:var(--ink-faint); font-weight:400; font-size:11.5px; margin-top:2px; line-height:1.4; }
.intro-mod .pct {
flex:0 0 auto; width:19px; height:19px; border-radius:50%;
background:rgba(22,163,74,.13); color:#16a34a;
display:inline-flex; align-items:center; justify-content:center; font-size:0;
}
.intro-mod .pct::after { content:"✓"; font-size:10px; font-weight:800; }
/* ════════════════════════════════════════════════════════════════════
UPLOAD — animated drop zone
════════════════════════════════════════════════════════════════════ */
.coh-drop {
position:relative;
border:2px dashed var(--line);
padding:42px 32px;
text-align:center; cursor:pointer;
transition:background .25s ease, border-color .25s ease;
background:linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
}
.coh-drop::before {
content:""; position:absolute; inset:8px;
border:1px dashed transparent;
pointer-events:none;
transition:border-color .25s ease;
}
.coh-drop:hover::before, .coh-drop.hover::before { border-color:rgba(5,41,98,.25); }
.coh-drop:hover, .coh-drop.hover { background:linear-gradient(180deg, #f1f5f9 0%, #ffffff 100%); border-color:var(--navy); }
.coh-drop.has-file { border-style:solid; padding:18px 22px; text-align:left; background:#fff; }
.coh-drop.has-file::before { display:none; }
/* Pulsing icon */
.drop-icon-ring {
width:64px; height:64px; margin:0 auto 14px;
border-radius:50%;
background:#fff;
display:flex; align-items:center; justify-content:center;
font-size:28px; color:var(--navy);
box-shadow:0 0 0 0 rgba(5,41,98,.25);
animation:pulseRing 2.4s ease-out infinite;
position:relative;
}
@keyframes pulseRing {
0% { box-shadow:0 0 0 0 rgba(5,41,98,.25); }
70% { box-shadow:0 0 0 18px rgba(5,41,98,0); }
100% { box-shadow:0 0 0 0 rgba(5,41,98,0); }
}
.drop-title { font-family:'Playfair Display',serif; font-size:22px; font-weight:700; line-height:1.2; margin-bottom:6px; }
.drop-sub { font-size:13px; color:var(--ink-soft); }
.drop-hint {
display:inline-flex; align-items:center; gap:6px;
margin-top:14px; padding:5px 11px;
background:#fff; border:1px solid var(--line);
font-size:11px; color:var(--ink-soft);
letter-spacing:.4px;
}
.drop-hint kbd {
background:#f1f5f9; border:1px solid var(--line);
padding:1px 6px; font-family:ui-monospace,Menlo,monospace;
font-size:10px; font-weight:600; color:var(--ink);
}
/* ─── Caption block ─────────────────────────────────────────────── */
.caption-wrap { position:relative; }
.caption-counter {
position:absolute; right:12px; bottom:10px;
font-size:11px; color:var(--ink-faint);
font-variant-numeric:tabular-nums; letter-spacing:.3px;
pointer-events:none;
}
.caption-counter.warn { color:var(--orange); }
.caption-suggestions {
display:flex; flex-wrap:wrap; gap:6px; margin-top:10px;
}
.caption-suggestions .sg-label {
font-size:11px; text-transform:uppercase; letter-spacing:1px;
color:var(--ink-soft); margin-right:4px; align-self:center; font-weight:600;
}
.sg-pill {
padding:5px 11px; background:#fff; border:1px solid var(--line);
font-size:12px; cursor:pointer; color:var(--ink);
transition:all .15s ease;
font-family:inherit;
}
.sg-pill:hover { background:var(--navy); color:#fff; border-color:var(--navy); }
/* Form labels — numbered editorial */
.field-label {
display:flex; align-items:baseline; gap:10px;
font-weight:600; font-size:14px; margin-bottom:10px;
}
.field-label .num {
font-family:'Playfair Display',serif; font-style:italic;
color:var(--ink-faint); font-size:13px; font-weight:600;
}
/* Big CTA */
.coh-cta-btn {
font-size:16px; padding:14px 28px;
letter-spacing:.4px;
transition:transform .15s ease, box-shadow .15s ease;
}
.coh-cta-btn:not(:disabled):hover { transform:translateY(-1px); box-shadow:0 8px 20px -8px rgba(5,41,98,.35); }
/* ════════════════════════════════════════════════════════════════════
PROCESS INDICATOR — animated steps during analysis
════════════════════════════════════════════════════════════════════ */
.process-card {
border:1px solid var(--line); background:#fff;
padding:24px 28px;
margin-top:22px;
animation: fadeUp .45s cubic-bezier(.16,1,.3,1) both;
}
.process-head {
display:flex; align-items:center; justify-content:space-between;
gap:12px; margin-bottom:18px;
}
.process-head .ph-title {
font-family:'Playfair Display',serif; font-size:20px; line-height:1.15;
display:flex; align-items:center; gap:10px;
}
.process-head .ph-status {
font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums; letter-spacing:.4px;
}
.process-track {
height:4px; background:#f1f5f9;
position:relative; overflow:hidden; margin-bottom:24px;
}
.process-track > div {
height:100%;
background:linear-gradient(90deg, var(--navy) 0%, #1e3a8a 100%);
width:0; transition:width .6s var(--ease-out);
}
.process-steps { display:flex; flex-direction:column; gap:0; }
.pstep {
display:grid; grid-template-columns:36px 1fr auto;
gap:16px; align-items:center;
padding:11px 0;
border-bottom:1px solid var(--line-soft);
transition:opacity .25s ease;
}
.pstep:last-child { border-bottom:0; }
.pstep[data-state="pending"] { opacity:.45; }
.pstep .ps-icon {
width:32px; height:32px; border-radius:50%;
display:flex; align-items:center; justify-content:center;
background:#f1f5f9; color:var(--ink-soft);
font-size:14px; font-weight:700;
transition:all .25s ease;
}
.pstep[data-state="active"] .ps-icon {
background:var(--navy); color:#fff;
box-shadow:0 0 0 0 rgba(5,41,98,.4);
animation:pulseRing 1.4s ease-out infinite;
}
.pstep[data-state="done"] .ps-icon {
background:#dcfce7; color:#166534;
}
.pstep .ps-label { font-weight:600; font-size:14px; }
.pstep .ps-detail { font-size:12px; color:var(--ink-soft); margin-top:2px; }
.pstep .ps-time {
font-size:11px; color:var(--ink-faint); font-variant-numeric:tabular-nums;
letter-spacing:.4px;
}
.pstep[data-state="active"] .ps-time { color:var(--navy); font-weight:700; }
.pstep[data-state="done"] .ps-time { color:#166534; }
/* ════════════════════════════════════════════════════════════════════
NEW XAI — per-module verdicts
════════════════════════════════════════════════════════════════════ */
.pmv-grid {
display:grid; grid-template-columns:repeat(auto-fit, minmax(180px, 1fr));
gap:14px;
margin-left:42px;
}
.pmv-cell {
padding:16px 18px;
border:1px solid var(--line);
background:linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
position:relative;
transition:all .2s ease;
}
.pmv-cell:hover { border-color:var(--navy); transform:translateY(-2px); box-shadow:0 6px 16px -8px rgba(5,41,98,.2); }
.pmv-cell .pmv-mod {
display:flex; align-items:center; gap:8px;
font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.6px;
color:var(--ink-soft); margin-bottom:8px;
}
.pmv-cell .pmv-score {
font-family:'Playfair Display',serif; font-size:26px; font-weight:700;
line-height:1; font-variant-numeric:tabular-nums;
}
.pmv-cell .pmv-mini {
display:inline-block; margin-top:6px;
font-size:10px; padding:3px 8px; font-weight:700;
letter-spacing:.6px; text-transform:uppercase;
}
.pmv-cell[data-v="COHERENT"] .pmv-mini { background:#dcfce7; color:#166534; }
.pmv-cell[data-v="SUSPECT"] .pmv-mini { background:#fef3c7; color:#92400e; }
.pmv-cell[data-v="INCOHERENT"] .pmv-mini { background:#fee2e2; color:#991b1b; }
.pmv-cell[data-v="COHERENT"] { border-top:3px solid #16a34a; }
.pmv-cell[data-v="SUSPECT"] { border-top:3px solid #f59e0b; }
.pmv-cell[data-v="INCOHERENT"] { border-top:3px solid #dc2626; }
/* ════════════════════════════════════════════════════════════════════
NEW XAI — radar chart
════════════════════════════════════════════════════════════════════ */
.radar-wrap {
margin-left:42px;
display:grid; grid-template-columns:1fr 280px; gap:24px;
align-items:start;
}
@media (max-width: 800px) { .radar-wrap { grid-template-columns:1fr; } }
.radar-svg-wrap {
display:flex; align-items:center; justify-content:center;
padding:14px;
background:linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
border:1px solid var(--line);
}
.radar-svg-wrap svg { width:100%; max-width:380px; height:auto; }
.radar-grid-line { fill:none; stroke:#e2e8f0; stroke-width:1; }
.radar-axis-line { stroke:#cbd5e1; stroke-width:1; stroke-dasharray:2 3; }
.radar-axis-label { font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.6px; fill:var(--ink-soft); }
.radar-poly-thresh { fill:rgba(22,163,74,.08); stroke:#16a34a; stroke-width:1; stroke-dasharray:3 3; }
.radar-poly-actual {
fill:var(--radar-fill);
stroke:var(--radar-stroke);
stroke-width:2;
stroke-linejoin:round;
transition:opacity .8s ease;
}
.radar-point { fill:#fff; stroke:var(--radar-stroke); stroke-width:2; }
.radar-legend { display:flex; flex-direction:column; gap:10px; }
.radar-legend .rl-item { display:flex; align-items:center; gap:10px; font-size:13px; }
.radar-legend .rl-swatch {
width:14px; height:14px; flex-shrink:0; border-radius:2px;
}
.radar-legend .rl-text { line-height:1.4; }
.radar-legend .rl-text small { color:var(--ink-soft); display:block; margin-top:1px; font-size:11px; }
/* ════════════════════════════════════════════════════════════════════
NEW XAI — counterfactual list
════════════════════════════════════════════════════════════════════ */
.cf-list { margin-left:42px; }
.cf-row {
display:grid; grid-template-columns:170px 1fr 100px 130px;
gap:16px; align-items:center;
padding:14px 0;
border-bottom:1px solid var(--line-soft);
}
.cf-row:last-child { border-bottom:0; }
@media (max-width: 800px) { .cf-row { grid-template-columns:1fr 1fr; } }
.cf-mod { display:flex; align-items:center; gap:8px; font-weight:600; font-size:14px; }
.cf-arrow { font-family:'Playfair Display',serif; font-style:italic; color:var(--ink-faint); font-size:13px; }
.cf-arrow strong { color:var(--ink); font-weight:700; font-style:normal; font-variant-numeric:tabular-nums; }
.cf-delta {
font-size:13px; font-weight:700; text-align:right;
font-variant-numeric:tabular-nums;
}
.cf-delta.neg { color:#dc2626; }
.cf-delta.pos { color:#16a34a; }
.cf-mini-verdict {
display:inline-block; padding:4px 10px;
font-size:10px; font-weight:700; letter-spacing:.6px;
text-transform:uppercase; text-align:center;
}
/* ════════════════════════════════════════════════════════════════════
NEW XAI — plain-language explanation
════════════════════════════════════════════════════════════════════ */
.explain-card {
margin-left:42px;
padding:28px 32px 28px 56px;
background:#fff;
border:1px solid var(--line);
font-size:16px; line-height:1.75;
font-family:'Playfair Display', Georgia, serif;
font-weight:400;
position:relative;
}
.explain-card::before {
content:"\201C"; position:absolute; left:18px; top:8px;
font-family:'Playfair Display',serif; font-size:84px; line-height:1;
color:#cbd5e1;
}
.explain-card .verdict-mark {
font-weight:700; padding:1px 8px;
font-family: 'Inter', sans-serif;
font-size:.78em;
letter-spacing:.6px;
text-transform:uppercase;
}
.explain-card .verdict-mark.COHERENT { background:#dcfce7; color:#166534; }
.explain-card .verdict-mark.SUSPECT { background:#fef3c7; color:#92400e; }
.explain-card .verdict-mark.INCOHERENT { background:#fee2e2; color:#991b1b; }
.explain-card strong { font-family:'Inter', sans-serif; font-weight:700; font-size:.92em; }
.explain-card em { font-style:italic; }
/* ════════════════════════════════════════════════════════════════════
ICON SYSTEM — replaces emojis throughout
════════════════════════════════════════════════════════════════════ */
.icon { display:inline-block; vertical-align:middle; flex-shrink:0; }
.icon svg { display:block; width:100%; height:100%; }
.icon-12 { width:12px; height:12px; }
.icon-14 { width:14px; height:14px; }
.icon-16 { width:16px; height:16px; }
.icon-18 { width:18px; height:18px; }
.icon-22 { width:22px; height:22px; }
.icon-28 { width:28px; height:28px; }
.icon-stroke { stroke:currentColor; fill:none; }
/* Module monogram circle — single-letter token used everywhere */
.mono {
display:inline-flex; align-items:center; justify-content:center;
width:26px; height:26px; border-radius:50%;
font-family:'Playfair Display',serif;
font-weight:700; font-size:13px; color:#fff;
flex-shrink:0; letter-spacing:.5px;
}
.mono-lg { width:34px; height:34px; font-size:16px; }
.mono-sm { width:22px; height:22px; font-size:11px; }
.mono.clip { background:#5b21b6; }
.mono.sam { background:#be185d; }
.mono.whisper { background:#b45309; }
.mono.yolo { background:#1d4ed8; }
.mono.ocr { background:#c2410c; }
/* Video-mode monograms (composite metrics) */
.mono.text_image { background:#5b21b6; }
.mono.text_audio { background:#b45309; }
.mono.audio_image { background:#0e7490; }
.mono.temporal { background:#0f766e; }
.mono.objects { background:#1d4ed8; }
.mono.composite { background:#334155; }
/* Status icons (verdict hero, chips, etc.) */
.status-ico {
display:inline-flex; align-items:center; justify-content:center;
width:42px; height:42px; border-radius:50%;
flex-shrink:0;
}
.status-ico svg { width:22px; height:22px; }
.status-ico.coh { background:#dcfce7; color:#166534; }
.status-ico.sus { background:#fef3c7; color:#92400e; }
.status-ico.inc { background:#fee2e2; color:#991b1b; }
/* Refined chips — neutral palette, no emoji prefix */
.chip {
display:inline-flex; align-items:center; gap:6px;
padding:6px 12px; background:#fff; color:var(--ink);
font-size:12px; font-weight:600; border-radius:0;
border:1px solid var(--line);
letter-spacing:.2px;
transition:all .15s ease;
}
.chip:hover { border-color:var(--ink-soft); }
.chip-num { background:#fafbff; color:var(--navy); border-color:#e0e7ff; font-variant-numeric:tabular-nums; font-family:ui-monospace,Menlo,monospace; font-size:11px; }
.chip-mute { background:#f8fafc; color:var(--ink-soft); }
.chip-good { background:#f0fdf4; color:#166534; border-color:#bbf7d0; }
.chip-warn { background:#fffbeb; color:#92400e; border-color:#fde68a; }
.chip-tag {
position:relative; padding-left:20px;
}
.chip-tag::before {
content:""; position:absolute; left:9px; top:50%;
width:6px; height:6px; border-radius:50%;
background:var(--navy); transform:translateY(-50%);
}
/* Tab icon style */
.coh-tab .tab-ico { display:inline-flex; align-items:center; gap:8px; }
/* CTA arrow */
.cta-arrow { display:inline-block; margin-left:6px; transition:transform .2s ease; }
.coh-cta-btn:hover .cta-arrow { transform:translateX(4px); }
/* Editorial section kicker (replaces old uppercase divs with emojis) */
.kicker-tag {
display:flex; align-items:center; gap:8px;
font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:1.4px;
color:var(--ink-soft); margin-bottom:10px;
}
/* Pipeline flow — mono badge container */
.pf-mono { margin:0 auto 6px; display:flex; justify-content:center; }
/* Counterfactual flag */
.cf-flag {
font-size:10px; font-weight:700; margin-top:4px;
text-transform:uppercase; letter-spacing:.8px;
display:inline-flex; align-items:center; gap:4px;
}
.cf-flag.flipped { color:var(--red); }
.cf-flag.stable { color:var(--ink-faint); font-weight:500; }
/* Banner icon alignment */
.api-banner { display:flex; align-items:center; gap:8px; }
.api-banner .icon { flex-shrink:0; }
/* Verdict hero — refined editorial spacing */
.verdict-hero { padding:42px 48px; }
.verdict-hero .vh-status { margin-bottom:22px; }
.verdict-hero .vh-status-label { letter-spacing:1.8px; font-size:10px; }
.verdict-hero .vh-verdict { font-size:68px; }
/* Tab refinement */
.coh-tab { padding:14px 22px 12px; }
.coh-tab .tab-ico { display:inline-flex; align-items:center; gap:9px; }
/* Suggestion pills — more refined */
.sg-pill { padding:6px 14px; font-size:13px; font-family:'Playfair Display', Georgia, serif; font-style:italic; }
.sg-pill:hover { background:var(--ink); color:#fff; border-color:var(--ink); }
.sg-label { font-size:10px !important; letter-spacing:1.6px !important; font-weight:700 !important; }
/* Drop hint — minimal */
.drop-hint { background:transparent; }
/* Process steps — keep monochrome */
.pstep .ps-icon svg { width:14px; height:14px; }
/* Field label — bigger numerals */
.field-label { font-size:15px; }
.field-label .num { font-size:15px; padding-right:4px; }
/* ════════════════════════════════════════════════════════════════════
IO6 — Cosmetic Ads specific styles
════════════════════════════════════════════════════════════════════ */
/* Hero global verdict mapping for io6 (RELIABLE/TO_VERIFY/MISLEADING) */
.verdict-hero[data-v="RELIABLE"] { --vh-bg1:#ecfdf5; --vh-bd:#16a34a; --vh-ink:#14532d; --vh-glow:rgba(22,163,74,.13); --vh-arc:#16a34a; --vh-icon-bg:#dcfce7; }
.verdict-hero[data-v="MISLEADING"] { --vh-bg1:#fef2f2; --vh-bd:#dc2626; --vh-ink:#7f1d1d; --vh-glow:rgba(220,38,38,.13); --vh-arc:#dc2626; --vh-icon-bg:#fee2e2; }
/* TO_VERIFY uses SUSPECT colors which are already defined */
.verdict-hero[data-v="TO_VERIFY"] { --vh-bg1:#fffbeb; --vh-bd:#f59e0b; --vh-ink:#78350f; --vh-glow:rgba(245,158,11,.16); --vh-arc:#f59e0b; --vh-icon-bg:#fef3c7; }
/* Stats donut */
.io6-stats-grid {
display:grid;
grid-template-columns: 200px 1fr;
gap:32px; align-items:center;
margin-left:42px;
}
@media (max-width: 700px) { .io6-stats-grid { grid-template-columns:1fr; } }
.io6-donut svg { width:100%; max-width:180px; height:auto; }
.io6-donut .donut-ring { fill:none; stroke-width:14; }
.io6-donut-center { text-align:center; margin-top:-110px; pointer-events:none; }
.io6-donut-center .num { font-family:'Playfair Display',serif; font-weight:800; font-size:36px; line-height:1; }
.io6-donut-center .lbl { font-size:10px; text-transform:uppercase; letter-spacing:1.4px; color:var(--ink-soft); margin-top:6px; }
.io6-stats-list { display:flex; flex-direction:column; gap:14px; }
.io6-stats-list .row {
display:grid; grid-template-columns:18px 100px 1fr 50px; gap:14px;
align-items:center; font-size:14px;
}
.io6-stats-list .row .swatch { width:14px; height:14px; }
.io6-stats-list .row .lbl { font-weight:600; }
.io6-stats-list .row .bar { height:8px; background:#f1f5f9; }
.io6-stats-list .row .bar > div { height:100%; transition:width .9s var(--ease-out); }
.io6-stats-list .row .num { text-align:right; font-variant-numeric:tabular-nums; font-weight:700; }
.io6-stats-list .row.row-true { --row-c:#16a34a; }
.io6-stats-list .row.row-false { --row-c:#dc2626; }
.io6-stats-list .row.row-tov { --row-c:#f59e0b; }
.io6-stats-list .row .swatch { background:var(--row-c); }
.io6-stats-list .row .bar > div { background:var(--row-c); }
/* Claim cards — list */
.claim-list { display:flex; flex-direction:column; gap:12px; margin-left:42px; }
.claim-row {
display:grid;
grid-template-columns: 130px 1fr;
gap:18px;
padding:16px 20px;
border:1px solid var(--line);
background:#fff;
transition:all .2s ease;
}
.claim-row:hover { border-color:var(--ink-soft); box-shadow:0 8px 20px -10px rgba(15,23,42,.15); }
.claim-row[data-v="TRUE"] { border-left:3px solid #16a34a; }
.claim-row[data-v="FALSE"] { border-left:3px solid #dc2626; }
.claim-row[data-v="TO_VERIFY"] { border-left:3px solid #f59e0b; }
.claim-verdict-side {
display:flex; flex-direction:column; gap:8px; align-items:flex-start;
}
.claim-verdict-pill {
display:inline-block;
padding:5px 12px; font-size:11px; font-weight:700;
letter-spacing:1px; text-transform:uppercase;
}
.claim-verdict-pill[data-v="TRUE"] { background:#dcfce7; color:#166534; }
.claim-verdict-pill[data-v="FALSE"] { background:#fee2e2; color:#991b1b; }
.claim-verdict-pill[data-v="TO_VERIFY"] { background:#fef3c7; color:#92400e; }
.claim-meta { font-size:11px; color:var(--ink-soft); letter-spacing:.4px; font-variant-numeric:tabular-nums; }
.claim-source {
font-size:10px; padding:2px 7px; background:#f1f5f9;
color:var(--ink-soft); text-transform:uppercase; letter-spacing:.6px; font-weight:600;
}
.claim-text {
font-family:'Playfair Display', serif; font-size:18px; line-height:1.3;
color:var(--ink); font-weight:500; letter-spacing:-.2px;
}
.claim-text-original { font-size:13px; color:var(--ink-soft); margin-top:4px; font-style:italic; }
.claim-evidence-list {
margin-top:10px; padding:0; list-style:none;
font-size:13px; line-height:1.55; color:var(--ink-soft);
}
.claim-evidence-list li {
padding:4px 0; padding-left:14px; position:relative;
}
.claim-evidence-list li::before {
content:""; position:absolute; left:0; top:11px;
width:6px; height:1px; background:var(--ink-soft);
}
.claim-eu {
display:flex; flex-wrap:wrap; gap:5px; margin-top:8px;
}
.claim-eu .eu-pill {
padding:3px 9px; background:#fef9c3; border:1px solid #fde68a;
color:#713f12; font-size:11px; font-weight:600; font-family:ui-monospace,Menlo,monospace;
}
/* Severity badges */
.sev-badge {
display:inline-block; padding:2px 8px; font-size:10px;
font-weight:700; text-transform:uppercase; letter-spacing:.5px;
}
.sev-info { background:#e0e7ff; color:#3730a3; }
.sev-medium { background:#fed7aa; color:#9a3412; }
.sev-high { background:#fecaca; color:#991b1b; }
.sev-critical { background:#1f2937; color:#fff; }
/* Pipeline timing list */
.timing-grid {
display:grid; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));
gap:10px; margin-left:42px;
}
.timing-cell {
padding:12px 14px;
border:1px solid var(--line);
background:#fafbff;
}
.timing-cell .k { font-size:10px; text-transform:uppercase; letter-spacing:1px; color:var(--ink-soft); margin-bottom:4px; font-weight:600; }
.timing-cell .v { font-family:'Playfair Display',serif; font-weight:700; font-size:24px; color:var(--ink); }
.timing-cell .v small { font-size:13px; color:var(--ink-soft); margin-left:2px; }
/* EU articles strip */
.eu-articles-strip {
margin-left:42px;
display:flex; flex-wrap:wrap; gap:8px;
}
.eu-articles-strip .eu-card {
flex:1; min-width:240px;
padding:14px 18px;
border:1px solid var(--line);
background:#fef9c3;
border-left:3px solid #f59e0b;
}
.eu-articles-strip .eu-card .ref { font-family:ui-monospace,Menlo,monospace; font-size:12px; font-weight:700; color:#713f12; }
.eu-articles-strip .eu-card .desc { font-size:13px; color:var(--ink); margin-top:4px; }
/* ════════════════════════════════════════════════════════════════════
IO6 v2 — EDITORIAL MAGAZINE LAYOUT (12-col grid)
════════════════════════════════════════════════════════════════════ */
.io6-grid {
display:grid;
grid-template-columns: repeat(12, 1fr);
gap:18px;
margin-top:8px;
}
.io6-grid > * {
animation: fadeUp .55s cubic-bezier(.16,1,.3,1) both;
}
.io6-grid > *:nth-child(1) { animation-delay: 0s; }
.io6-grid > *:nth-child(2) { animation-delay: .07s; }
.io6-grid > *:nth-child(3) { animation-delay: .14s; }
.io6-grid > *:nth-child(4) { animation-delay: .21s; }
.io6-grid > *:nth-child(5) { animation-delay: .28s; }
.io6-grid > *:nth-child(6) { animation-delay: .35s; }
.io6-grid > *:nth-child(7) { animation-delay: .42s; }
.io6-grid > *:nth-child(8) { animation-delay: .49s; }
.io6-grid > *:nth-child(9) { animation-delay: .56s; }
.col-12 { grid-column: span 12; }
.col-8 { grid-column: span 8; }
.col-7 { grid-column: span 7; }
.col-6 { grid-column: span 6; }
.col-5 { grid-column: span 5; }
.col-4 { grid-column: span 4; }
@media (max-width: 900px) {
.col-8, .col-7, .col-6, .col-5, .col-4 { grid-column: span 12; }
}
/* ─── Editorial section header (replaces coh-card-head when in grid) ─── */
.ed-card {
padding:24px 26px;
background:#fff;
border:1px solid var(--line);
transition:border-color .2s ease, box-shadow .25s var(--ease-out);
}
.ed-card:hover { border-color:#cfd8e3; box-shadow:0 12px 32px -16px rgba(15,23,42,.12); }
.ed-section-head {
display:flex; align-items:baseline; gap:14px;
padding-bottom:14px; margin-bottom:18px;
border-bottom:1px solid var(--line);
}
.ed-section-num {
font-family:'Playfair Display',serif; font-style:italic;
font-size:13px; color:var(--ink-faint);
letter-spacing:.5px; flex-shrink:0;
}
.ed-section-title {
font-family:'Playfair Display',serif;
font-size:21px; font-weight:700; line-height:1.1;
letter-spacing:-.3px; flex:1;
}
.ed-section-action {
font-size:11px; text-transform:uppercase; letter-spacing:1.4px;
color:var(--ink-soft); font-weight:700; cursor:pointer;
border:0; background:transparent;
transition:color .15s ease;
}
.ed-section-action:hover { color:var(--navy); }
/* ─── Hero refined for io6 ─── */
.io6-hero {
padding:36px 38px;
background:#fff;
border:1px solid var(--line);
border-left:6px solid var(--vh-bd);
position:relative; overflow:hidden;
}
.io6-hero[data-v="RELIABLE"] { --vh-bd:#16a34a; }
.io6-hero[data-v="MISLEADING"] { --vh-bd:#dc2626; }
.io6-hero[data-v="TO_VERIFY"] { --vh-bd:#f59e0b; }
.io6-hero-grid {
display:grid; grid-template-columns: 1fr 220px; gap:36px;
align-items:center;
}
@media (max-width: 760px) { .io6-hero-grid { grid-template-columns:1fr; } }
.io6-hero-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; text-transform:uppercase; letter-spacing:2px;
color:var(--ink-soft); margin-bottom:14px;
display:flex; gap:14px; align-items:center;
}
.io6-hero-kicker .dot { width:8px; height:8px; border-radius:50%; background:var(--vh-bd); }
.io6-hero-headline {
font-family:'Playfair Display',serif;
font-size:54px; font-weight:800; line-height:1; color:var(--ink);
letter-spacing:-1.4px; margin:0 0 18px;
}
.io6-hero-headline .verdict-word {
color:var(--vh-bd);
}
.io6-hero-deck {
font-size:16px; line-height:1.5; color:var(--ink-soft);
max-width:560px;
}
.io6-hero-tags {
display:flex; gap:8px; flex-wrap:wrap; margin-top:18px;
}
.io6-hero-tag {
font-size:11px; padding:4px 10px;
background:#f1f5f9; color:var(--ink);
letter-spacing:.4px; font-weight:600;
}
.io6-hero-tag.flag {
background:#fef2f2; color:#991b1b;
}
.io6-hero-gauge {
display:flex; flex-direction:column; align-items:center; gap:6px;
}
/* ─── Filmstrip (mock keyframe tape) ─── */
.filmstrip {
display:flex; gap:0;
background:#0b1220;
padding:14px;
overflow-x:auto;
position:relative;
}
.filmstrip::before, .filmstrip::after {
content:""; flex-shrink:0;
width:24px; height:auto;
background-image: repeating-linear-gradient(180deg, #0b1220 0 8px, #f1f5f9 8px 18px);
}
.filmstrip-frame {
flex-shrink:0; width:120px; height:80px; margin:0 6px;
background:linear-gradient(135deg, #475569, #334155);
display:flex; align-items:center; justify-content:center;
color:#cbd5e1; font-size:11px; font-weight:600;
letter-spacing:.6px; text-transform:uppercase;
position:relative;
}
.filmstrip-frame .ts {
position:absolute; bottom:4px; right:6px;
font-family:ui-monospace,Menlo,monospace; font-size:9px;
color:#94a3b8; letter-spacing:.5px;
}
.filmstrip-overlay {
position:absolute; left:6px; right:6px; top:4px;
background:rgba(255,229,0,.15); padding:1px 4px;
color:#fef08a; font-size:9px;
border-left:2px solid #facc15;
max-height:50px; overflow:hidden;
}
/* ─── Claim ribbon ─── */
.claim-ribbon-wrap {
overflow:visible;
}
.claim-ribbon {
display:grid; gap:8px;
}
.claim-tape {
display:grid;
grid-template-columns: 36px 1fr 90px 120px;
gap:14px; align-items:center;
padding:12px 16px;
background:#fff; border:1px solid var(--line);
cursor:pointer;
transition:all .2s ease;
position:relative;
}
.claim-tape::before {
content:""; position:absolute; left:0; top:0; bottom:0; width:4px;
background:var(--ct-accent, #cbd5e1);
}
.claim-tape:hover {
border-color:var(--ct-accent);
transform:translateX(2px);
box-shadow:0 4px 14px -4px rgba(15,23,42,.12);
}
.claim-tape[data-v="TRUE"] { --ct-accent:#16a34a; }
.claim-tape[data-v="FALSE"] { --ct-accent:#dc2626; }
.claim-tape[data-v="TO_VERIFY"] { --ct-accent:#f59e0b; }
.ct-num {
font-family:'Playfair Display',serif; font-style:italic;
font-size:18px; font-weight:700; color:var(--ink-faint);
text-align:center;
}
.ct-text {
font-family:'Playfair Display', serif; font-size:17px; line-height:1.25;
font-weight:500; letter-spacing:-.2px;
}
.ct-meta {
display:flex; gap:10px; align-items:center; font-size:11px; color:var(--ink-faint);
letter-spacing:.4px; margin-top:4px;
}
.ct-source-pill {
font-size:10px; padding:1px 6px; background:#f1f5f9;
color:var(--ink-soft); text-transform:uppercase; letter-spacing:.6px; font-weight:600;
}
.ct-conf {
text-align:center;
font-family:'Playfair Display',serif; font-weight:700; font-size:24px;
color:var(--ct-accent); font-variant-numeric:tabular-nums; line-height:1;
}
.ct-conf small { font-size:10px; color:var(--ink-faint); display:block; margin-top:4px; letter-spacing:.5px; }
.ct-verdict-pill {
font-size:10px; padding:5px 12px;
background:var(--ct-accent); color:#fff;
font-weight:700; letter-spacing:1px; text-transform:uppercase;
text-align:center;
}
.ct-cta {
display:flex; align-items:center; gap:6px;
font-size:10px; color:var(--ink-soft); margin-top:5px;
text-transform:uppercase; letter-spacing:.6px;
transition:color .15s ease;
}
.claim-tape:hover .ct-cta { color:var(--ct-accent); }
/* ─── Severity heatmap ─── */
.sev-heatmap {
display:grid; grid-template-columns:120px repeat(4, 1fr);
gap:0;
border:1px solid var(--line);
}
.sev-heatmap > div {
padding:10px 12px;
font-size:11px;
border-right:1px solid var(--line);
border-bottom:1px solid var(--line);
}
.sev-heatmap > div:last-child,
.sev-heatmap > div:nth-last-child(-n+5) { /* nope, fix */
}
.sev-heatmap .hh-corner { background:#0b1220; color:#cbd5e1; font-weight:700; text-transform:uppercase; letter-spacing:.6px; }
.sev-heatmap .hh-col {
background:#0b1220; color:#cbd5e1; font-weight:700;
text-transform:uppercase; letter-spacing:.6px;
text-align:center;
}
.sev-heatmap .hh-row {
background:#f8fafc; font-weight:700;
text-transform:uppercase; letter-spacing:.6px; color:var(--ink);
}
.sev-heatmap .hh-cell {
text-align:center;
font-family:ui-monospace,Menlo,monospace; font-size:13px;
font-weight:600; color:var(--ink);
transition:transform .15s ease;
}
.sev-heatmap .hh-cell:hover { transform:scale(1.05); cursor:default; }
.sev-heatmap .hh-cell[data-w="0"] { background:#f8fafc; color:var(--ink-faint); }
.sev-heatmap .hh-cell[data-w="1"] { background:#fef9c3; }
.sev-heatmap .hh-cell[data-w="2"] { background:#fed7aa; color:#9a3412; }
.sev-heatmap .hh-cell[data-w="3"] { background:#fecaca; color:#991b1b; }
.sev-heatmap .hh-cell[data-w="4"] { background:#1f2937; color:#fff; }
/* ─── Decision flow SVG ─── */
.decision-flow svg {
width:100%; height:auto;
max-height:340px;
}
.df-node {
font-family:'Inter', sans-serif;
font-size:11px; font-weight:600;
}
.df-edge {
fill:none; stroke-width:2;
opacity:.65;
stroke-dasharray:2000;
stroke-dashoffset:2000;
animation: dashIn 1.4s var(--ease-out) forwards;
}
@keyframes dashIn {
to { stroke-dashoffset:0; }
}
/* ─── Side mini-stats card ─── */
.mini-stats {
display:grid; gap:10px;
}
.mini-stat {
display:grid; grid-template-columns: 1fr auto; align-items:baseline;
padding:12px 14px;
background:#fafbff; border-left:3px solid var(--navy);
}
.mini-stat .k {
font-size:10px; text-transform:uppercase; letter-spacing:1.4px;
color:var(--ink-soft); font-weight:700;
}
.mini-stat .v {
font-family:'Playfair Display',serif; font-weight:800; font-size:24px;
color:var(--ink); font-variant-numeric:tabular-nums; line-height:1;
}
.mini-stat .v small { font-size:13px; font-weight:500; color:var(--ink-soft); margin-left:3px; }
/* ─── EU articles refined ─── */
.eu-grid {
display:grid; grid-template-columns:1fr; gap:10px;
}
.eu-tile {
padding:14px 16px;
background:#fefae0;
border:1px solid #fde68a;
border-left:4px solid #b45309;
cursor:pointer;
transition:all .2s ease;
display:flex; align-items:flex-start; gap:12px;
}
.eu-tile:hover {
background:#fef3c7;
transform:translateX(2px);
}
.eu-tile-num {
font-family:'Playfair Display',serif; font-style:italic;
color:#b45309; font-weight:700; font-size:13px;
flex-shrink:0; padding-top:2px;
}
.eu-tile-body { flex:1; min-width:0; }
.eu-tile-ref {
font-family:ui-monospace,Menlo,monospace;
font-size:12px; font-weight:700; color:#713f12;
letter-spacing:.4px;
}
.eu-tile-desc {
font-size:13px; color:var(--ink); margin-top:4px;
line-height:1.45;
}
.eu-tile-arrow {
color:#b45309; opacity:.6;
transition:opacity .2s ease, transform .2s ease;
flex-shrink:0;
}
.eu-tile:hover .eu-tile-arrow { opacity:1; transform:translateX(2px); }
/* ─── Generated AI justification ─── */
.ai-justify {
background:#0b1220;
color:#e5e7eb;
padding:28px 32px 28px 56px;
position:relative;
font-family:'Playfair Display', Georgia, serif;
font-size:17px; line-height:1.65;
}
.ai-justify::before {
content:"\201C"; position:absolute; left:18px; top:8px;
font-family:'Playfair Display',serif; font-size:96px; line-height:1;
color:rgba(229,231,235,.18);
}
.ai-justify mark {
background:#facc15; color:#0b1220;
padding:1px 6px; font-weight:700;
font-family: 'Inter', sans-serif; font-size:.85em;
letter-spacing:.4px;
}
.ai-justify mark.bad { background:#fecaca; color:#7f1d1d; }
.ai-justify mark.good { background:#bbf7d0; color:#14532d; }
.ai-justify .ai-byline {
display:block; margin-top:18px;
font-family:ui-monospace,Menlo,monospace; font-size:11px;
color:#94a3b8; letter-spacing:1.4px; text-transform:uppercase;
}
/* ─── Modal — Claim deep dive ─── */
.deep-modal { max-width:880px; }
.deep-claim-text {
font-family:'Playfair Display',serif; font-size:30px; line-height:1.2;
font-weight:600; color:var(--ink); letter-spacing:-.6px;
padding:18px 0;
border-bottom:1px solid var(--line);
margin-bottom:24px;
}
.deep-claim-text mark {
background:#fef08a;
padding:0 4px; border-radius:0;
box-shadow:0 -2px 0 #facc15 inset;
}
.deep-claim-text mark.danger { background:#fecaca; box-shadow:0 -2px 0 #f87171 inset; }
.deep-claim-text mark.safe { background:#bbf7d0; box-shadow:0 -2px 0 #4ade80 inset; }
.deep-section-title {
font-size:11px; text-transform:uppercase; letter-spacing:1.6px;
color:var(--navy); font-weight:700;
margin:24px 0 12px;
}
.deep-evidence-list { display:flex; flex-direction:column; gap:8px; }
.deep-evidence-row {
display:grid; grid-template-columns:auto 1fr auto; gap:14px;
padding:12px 14px;
border:1px solid var(--line);
align-items:center;
font-size:14px;
}
.deep-evidence-row .src-tag {
font-family:ui-monospace,Menlo,monospace; font-size:10px;
padding:3px 8px; background:#f1f5f9; color:var(--ink-soft);
letter-spacing:.5px;
}
.deep-similar-list { display:flex; flex-direction:column; gap:6px; }
.deep-similar-row {
display:grid; grid-template-columns:1fr 60px 80px; gap:12px;
align-items:center; padding:8px 12px;
background:#f8fafc;
font-size:13px;
}
.deep-similar-row .sim-bar {
height:8px; background:#e2e8f0; position:relative;
}
.deep-similar-row .sim-bar > div {
height:100%; background:linear-gradient(90deg, #fbbf24, #dc2626);
}
.deep-similar-row .sim-num { font-family:ui-monospace,Menlo,monospace; font-size:12px; color:var(--ink); }
/* ─── Counterfactual block in modal ─── */
.deep-cf {
padding:18px 22px;
background:#fefae0; border-left:3px solid #b45309;
font-size:14px; line-height:1.55;
}
.deep-cf strong { font-family:'Playfair Display',serif; font-weight:700; }
.deep-cf .cf-arrow {
display:inline-flex; align-items:center; gap:8px;
font-family:ui-monospace,Menlo,monospace; font-size:13px;
padding:4px 10px; background:#fff;
border:1px solid #fde68a; margin:0 4px;
}
/* ─── EU article modal ─── */
.eu-article-quote {
padding:22px 26px 22px 56px;
background:#fefae0;
font-family:'Playfair Display', serif; font-style:italic;
font-size:16px; line-height:1.6;
color:var(--ink); position:relative;
border-left:3px solid #b45309;
margin:18px 0;
}
.eu-article-quote::before {
content:"§"; position:absolute; left:18px; top:14px;
font-family:'Playfair Display',serif; font-size:32px; line-height:1;
color:#b45309; opacity:.6;
}
.eu-meta-row { display:flex; gap:16px; flex-wrap:wrap; margin-top:14px; font-size:13px; }
.eu-meta-row > div { display:flex; flex-direction:column; }
.eu-meta-row .k { font-size:10px; text-transform:uppercase; letter-spacing:1.2px; color:var(--ink-soft); font-weight:700; }
.eu-meta-row .v { font-weight:700; margin-top:3px; }
/* ─── Detection chips refined for io6 ─── */
.detect-chips { display:flex; flex-wrap:wrap; gap:6px; }
.detect-chips .chip {
font-family:ui-monospace,Menlo,monospace; font-size:11px;
padding:5px 10px;
letter-spacing:.3px;
}
/* ════════════════════════════════════════════════════════════════════
IO6 v4 — VERIFY DESK (newsroom submission, charte Verify)
Navy + yellow + beige + Playfair, fact-check submission aesthetic.
════════════════════════════════════════════════════════════════════ */
.desk-frame {
background:#fffdf6;
border:1px solid var(--line);
border-top:4px solid var(--navy);
position:relative;
overflow:hidden;
}
/* Top desk masthead — navy strip with yellow accent */
.desk-mast {
background:var(--navy);
color:#fff;
padding:12px 24px;
display:flex; align-items:center; justify-content:space-between;
gap:18px; flex-wrap:wrap;
}
.desk-mast-title {
font-family:'Playfair Display', serif;
font-size:14px; font-weight:700;
letter-spacing:.4px;
display:flex; align-items:center; gap:10px;
}
.desk-mast-title::before {
content:""; display:inline-block;
width:8px; height:8px;
background:var(--yellow);
}
.desk-mast-meta {
display:flex; align-items:center; gap:18px;
font-size:11px; color:#cbd5e1;
letter-spacing:.8px; text-transform:uppercase;
font-family:ui-monospace, Menlo, monospace;
flex-wrap:wrap;
}
.desk-mast-meta .pipe { color:rgba(255,255,255,.3); }
.desk-mast-meta strong { color:var(--yellow); font-weight:700; }
/* Body of the desk — cream paper feel */
.desk-body {
padding:38px 44px;
}
.desk-kicker {
font-family:ui-monospace, Menlo, monospace;
font-size:11px; font-weight:700; letter-spacing:2px;
color:var(--navy);
text-transform:uppercase;
display:flex; align-items:center; gap:10px;
margin-bottom:14px;
}
.desk-kicker::after {
content:""; flex:1; height:1px; background:var(--line);
}
.desk-headline {
font-family:'Playfair Display', serif;
font-size:38px; line-height:1.1;
color:var(--navy); font-weight:700;
margin:0 0 14px;
letter-spacing:-.5px;
max-width:760px;
}
.desk-headline em {
font-style:italic; color:var(--ink);
background-image:linear-gradient(180deg, transparent 60%, var(--yellow) 60%);
background-size:100% 100%;
background-repeat:no-repeat;
padding:0 4px;
}
.desk-deck {
font-family:'Playfair Display', serif;
font-size:16px; line-height:1.55;
color:var(--ink-soft);
max-width:680px;
margin:0 0 28px;
font-style:italic;
}
/* Drop area inside the desk — newsprint card */
.desk-drop {
border:1px dashed #c7c2a8;
background:#fffaeb;
padding:42px 32px;
text-align:center;
cursor:pointer;
transition:background .2s ease, border-color .2s ease;
position:relative;
}
.desk-drop:hover, .desk-drop.hover {
background:#fff5cc;
border-color:var(--navy);
}
.desk-drop.has-file {
border-style:solid; border-color:var(--navy);
background:#fff;
padding:22px 28px;
text-align:left;
}
.desk-drop-icon {
width:54px; height:54px;
margin:0 auto 16px;
border:1.5px solid var(--navy);
border-radius:50%;
display:flex; align-items:center; justify-content:center;
color:var(--navy);
background:#fff;
}
.desk-drop-title {
font-family:'Playfair Display', serif;
font-size:22px; font-weight:600;
color:var(--ink);
margin-bottom:6px;
}
.desk-drop-sub {
font-size:13px; color:var(--ink-soft);
letter-spacing:.4px;
}
.desk-drop-formats {
font-family:ui-monospace, Menlo, monospace;
font-size:11px; color:var(--ink-faint);
letter-spacing:1.2px; text-transform:uppercase;
margin-top:14px;
}
/* Filled state — like a press wire receipt */
.desk-filled {
display:flex; align-items:center; gap:18px;
}
.desk-filled .file-icon {
width:46px; height:46px;
background:var(--navy); color:#fff;
display:flex; align-items:center; justify-content:center;
flex-shrink:0;
}
.desk-filled .file-meta { flex:1; min-width:0; }
.desk-filled .file-name {
font-family:'Playfair Display', serif;
font-size:18px; font-weight:600;
color:var(--ink); word-break:break-word;
}
.desk-filled .file-stats {
font-family:ui-monospace, Menlo, monospace;
font-size:11px; color:var(--ink-soft);
letter-spacing:.4px; margin-top:4px;
display:flex; gap:14px; flex-wrap:wrap;
}
.desk-filled .file-change {
background:transparent; border:1px solid var(--line);
color:var(--ink); cursor:pointer;
font-family:'Playfair Display', serif;
font-style:italic; font-size:13px;
padding:8px 16px;
transition:all .15s ease;
}
.desk-filled .file-change:hover {
border-color:var(--navy); color:var(--navy);
}
/* Footer rule — submit row */
.desk-foot {
padding:22px 44px;
border-top:1px solid var(--line);
display:flex; align-items:center; justify-content:space-between;
gap:18px; flex-wrap:wrap;
background:#fff;
}
.desk-foot-byline {
font-family:'Playfair Display', serif;
font-size:13px; color:var(--ink-soft);
font-style:italic;
}
.desk-foot-byline strong { color:var(--navy); font-weight:700; font-style:normal; }
/* Big yellow Verify-branded CTA — luxe */
.io6-cta-btn {
position:relative; overflow:hidden;
background:linear-gradient(135deg, #fff06b 0%, var(--yellow) 45%, #f0d000 100%);
color:var(--navy);
font-family:'Playfair Display', serif; font-size:16px; font-weight:700; letter-spacing:.3px;
padding:14px 30px; border:1.5px solid var(--navy); border-radius:13px; cursor:pointer;
display:inline-flex; align-items:center; gap:10px;
box-shadow:0 10px 24px -10px rgba(245,200,0,.6), inset 0 1px 0 rgba(255,255,255,.5);
transition:transform .2s ease, box-shadow .25s ease, background .2s ease, color .2s ease;
}
.io6-cta-btn::before {
content:""; position:absolute; inset:0; pointer-events:none;
background:linear-gradient(115deg, transparent 35%, rgba(255,255,255,.55) 50%, transparent 65%);
transform:translateX(-130%); transition:transform .75s ease;
}
.io6-cta-btn::after { content:"\2192"; font-family:'Playfair Display', serif; transition:transform .25s ease; }
.io6-cta-btn:not(:disabled):hover {
background:var(--navy); color:var(--yellow); transform:translateY(-2px);
box-shadow:0 16px 32px -12px rgba(5,41,98,.5);
}
.io6-cta-btn:not(:disabled):hover::before { transform:translateX(130%); }
.io6-cta-btn:not(:disabled):hover::after { transform:translateX(4px); }
.io6-cta-btn:active:not(:disabled) { transform:translateY(0); }
.io6-cta-btn:disabled {
background:#f1f5f9; color:var(--ink-faint); border-color:var(--line); box-shadow:none; cursor:wait;
}
.io6-cta-btn:disabled::before, .io6-cta-btn:disabled::after { display:none; }
/* Status console — minimal, in charter */
.desk-status {
font-family:ui-monospace, Menlo, monospace;
font-size:11px;
color:var(--ink-soft);
letter-spacing:.5px;
display:flex; align-items:center; gap:10px;
}
.desk-status .sc-led {
display:inline-block; width:7px; height:7px; border-radius:50%;
background:#16a34a;
box-shadow:0 0 0 2px rgba(22,163,74,.18);
animation:deskLed 1.8s ease-in-out infinite;
}
@keyframes deskLed {
0%, 100% { box-shadow:0 0 0 2px rgba(22,163,74,.10); }
50% { box-shadow:0 0 0 5px rgba(22,163,74,.28); }
}
.desk-status.busy .sc-led { background:var(--orange); box-shadow:0 0 0 2px rgba(245,158,11,.2); }
.desk-status.busy .sc-led { animation-name:deskLedBusy; }
@keyframes deskLedBusy {
0%, 100% { box-shadow:0 0 0 2px rgba(245,158,11,.10); }
50% { box-shadow:0 0 0 5px rgba(245,158,11,.32); }
}
.desk-status.error .sc-led { background:var(--red); animation:none; box-shadow:0 0 0 2px rgba(220,38,38,.2); }
.desk-status .sc-text { color:var(--ink); font-weight:600; }
/* API banner refined for desk theme */
.api-banner.desk {
background:#fffdf6;
border:1px solid var(--line);
border-left:4px solid var(--navy);
padding:12px 18px;
font-size:13px;
display:flex; align-items:center; gap:10px;
}
.api-banner.desk.ok { border-left-color:#16a34a; }
.api-banner.desk.err { border-left-color:var(--red); background:#fef2f2; }
/* Section label sitting before the desk frame */
.io6-input-shell {
margin-bottom:28px;
}
.field-label-desk {
font-family:'Playfair Display', serif;
font-style:italic;
font-size:13px; font-weight:600;
color:var(--ink-faint);
letter-spacing:.4px;
margin-bottom:10px;
display:flex; align-items:center; gap:10px;
}
.field-label-desk .num {
color:var(--navy); font-style:italic;
}
.field-label-desk::after {
content:""; flex:1; height:1px; background:var(--line);
}
/* ════════════════════════════════════════════════════════════════════
XAI SUITE — 4 explicit cards (LIME, SHAP, Counterfactual, Traceability)
════════════════════════════════════════════════════════════════════ */
.xai-suite-banner {
background:#0b1220;
color:#e5e7eb;
padding:24px 28px;
display:grid; grid-template-columns: 1fr auto;
align-items:center; gap:24px;
}
.xai-suite-banner .xs-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:2px; text-transform:uppercase;
color:var(--yellow); margin-bottom:6px; font-weight:700;
}
.xai-suite-banner h3 {
font-family:'Playfair Display',serif;
font-size:28px; line-height:1.1; margin:0;
color:#fff; letter-spacing:-.4px;
}
.xai-suite-banner .xs-meta {
font-family:ui-monospace,Menlo,monospace; font-size:11px;
color:#94a3b8; letter-spacing:1.4px; text-transform:uppercase;
text-align:right; line-height:1.6;
}
.xai-suite-banner .xs-meta strong { color:var(--yellow); }
/* XAI card variants */
.xai-card {
padding:24px 26px;
background:#fff;
border:1px solid var(--line);
border-top:3px solid var(--xc-color, var(--navy));
transition:border-color .2s ease, box-shadow .25s var(--ease-out);
position:relative;
}
.xai-card.lime { --xc-color:#65a30d; }
.xai-card.shap { --xc-color:#7c3aed; }
.xai-card.counter { --xc-color:#dc2626; }
.xai-card.trace { --xc-color:#b45309; }
.xai-card:hover { box-shadow:0 12px 32px -16px rgba(15,23,42,.18); }
.xai-card-head {
display:flex; align-items:flex-start; justify-content:space-between;
gap:12px; margin-bottom:14px;
}
.xai-card-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; letter-spacing:2px; text-transform:uppercase;
color:var(--xc-color); font-weight:700;
margin-bottom:6px;
}
.xai-card h4 {
font-family:'Playfair Display',serif;
font-size:20px; line-height:1.15; margin:0 0 4px;
color:var(--ink); letter-spacing:-.2px;
}
.xai-card .xc-citation {
font-size:12px; color:var(--ink-soft); font-style:italic;
}
/* LIME — word salience */
.lime-claim {
font-family:'Playfair Display',serif; font-size:22px;
line-height:1.45; padding:18px 0;
border-top:1px solid var(--line);
border-bottom:1px solid var(--line);
margin:14px 0;
}
.lime-token {
display:inline-block;
padding:2px 5px;
margin:0 1px;
transition:transform .15s ease, box-shadow .15s ease;
cursor:default;
}
.lime-token[data-w="0"] { color:var(--ink); }
.lime-token[data-w="1"] { background:#fef9c3; color:#713f12; }
.lime-token[data-w="2"] { background:#fed7aa; color:#9a3412; }
.lime-token[data-w="3"] { background:#fecaca; color:#7f1d1d; font-weight:600; }
.lime-token[data-w="4"] { background:#dc2626; color:#fff; font-weight:700; }
.lime-token[data-w="-1"] { background:#dcfce7; color:#166534; }
.lime-token[title]:hover { transform:translateY(-1px); }
.lime-tokens-found {
margin-top:10px;
font-size:13px; color:var(--ink-soft);
line-height:1.7;
}
.lime-tokens-found code {
background:#f1f5f9; padding:1px 6px;
font-family:ui-monospace,Menlo,monospace; font-size:12px;
color:var(--ink);
}
.lime-legend {
display:flex; gap:14px; margin-top:14px; flex-wrap:wrap;
font-size:11px; color:var(--ink-soft);
letter-spacing:.4px;
}
.lime-legend span { display:flex; align-items:center; gap:6px; }
.lime-legend i {
width:14px; height:14px; display:inline-block;
}
.lime-claim-meta {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; letter-spacing:1px;
color:var(--ink-faint); text-transform:uppercase;
margin-bottom:6px;
}
/* SHAP — horizontal contribution chart */
.shap-chart { display:flex; flex-direction:column; gap:10px; margin-top:8px; }
.shap-row {
display:grid;
grid-template-columns: 150px 1fr 70px;
gap:14px;
align-items:center;
font-size:13px;
}
.shap-row .src {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:.4px;
color:var(--ink); font-weight:600;
}
.shap-row .src small { display:block; color:var(--ink-faint); font-size:10px; margin-top:2px; }
.shap-bar-wrap {
position:relative;
height:22px;
background:linear-gradient(90deg, transparent 49%, var(--line) 49%, var(--line) 51%, transparent 51%);
}
.shap-bar-fill {
position:absolute; top:0; bottom:0; height:100%;
transition:width 1s var(--ease-out);
}
.shap-bar-fill.neg { background:linear-gradient(90deg, #fca5a5, #dc2626); right:50%; }
.shap-bar-fill.pos { background:linear-gradient(90deg, #16a34a, #86efac); left:50%; }
.shap-row .val {
text-align:right;
font-family:ui-monospace,Menlo,monospace;
font-size:12px; font-weight:700;
font-variant-numeric:tabular-nums;
}
.shap-row .val.neg { color:#dc2626; }
.shap-row .val.pos { color:#16a34a; }
.shap-axis-labels {
display:flex; justify-content:space-between;
margin-top:6px; padding-left:164px; padding-right:84px;
font-size:10px; color:var(--ink-faint);
text-transform:uppercase; letter-spacing:1px;
}
/* Counterfactual — what-if leave-one-out */
.cf-sim-list { display:flex; flex-direction:column; gap:8px; }
.cf-sim-row {
padding:14px 16px;
border:1px solid var(--line);
background:#fafbff;
transition:border-color .15s ease, transform .15s ease;
}
.cf-sim-row:hover { border-color:var(--xc-color); transform:translateX(2px); }
.cf-sim-head {
display:flex; align-items:center; justify-content:space-between;
gap:12px; margin-bottom:6px;
}
.cf-sim-source {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; font-weight:700; color:var(--ink);
letter-spacing:.4px;
}
.cf-sim-flip {
display:inline-flex; align-items:center; gap:6px;
font-size:11px; font-weight:700;
padding:3px 8px;
letter-spacing:.6px; text-transform:uppercase;
}
.cf-sim-flip[data-flip="true"] { background:#fef2f2; color:#991b1b; }
.cf-sim-flip[data-flip="false"] { background:#f1f5f9; color:var(--ink-soft); }
.cf-sim-detail {
font-size:13px; color:var(--ink-soft);
line-height:1.5;
font-family:'Playfair Display',serif;
font-style:italic;
}
.cf-sim-detail strong {
font-style:normal; font-family:'Inter',sans-serif;
font-weight:700; color:var(--ink);
font-variant-numeric:tabular-nums;
}
/* Traceability — EU citations linked to claims */
.trace-grid { display:flex; flex-direction:column; gap:12px; }
.trace-row {
padding:14px 16px;
background:#fefae0; border:1px solid #fde68a;
border-left:3px solid #b45309;
cursor:pointer;
transition:transform .15s ease;
}
.trace-row:hover { transform:translateX(3px); }
.trace-ref {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; font-weight:700; color:#713f12;
letter-spacing:.4px;
}
.trace-title {
font-family:'Playfair Display',serif;
font-size:15px; color:var(--ink); margin-top:4px;
}
.trace-claims {
margin-top:8px; padding-top:8px;
border-top:1px dashed rgba(180,83,9,.3);
font-size:12px; color:var(--ink-soft);
}
.trace-claims em {
color:#7c2d12; font-style:italic;
}
/* ════════════════════════════════════════════════════════════════════
IO2 — Manipulation Detection (Malek)
"Media analysis board" style: technical grid, 4 modules as
gauge cards, image + bbox in the center, 3 XAI heatmaps in the bottom strip.
Stays within the Verify brand (navy + yellow + cream).
════════════════════════════════════════════════════════════════════ */
/* Header strip — file under analysis */
.io2-mast {
background:var(--navy);
color:#fff;
padding:12px 24px;
display:flex; align-items:center; justify-content:space-between;
gap:18px; flex-wrap:wrap;
}
.io2-mast-title {
font-family:'Playfair Display',serif;
font-size:14px; font-weight:700;
display:flex; align-items:center; gap:10px;
}
.io2-mast-title::before {
content:""; width:8px; height:8px; background:var(--yellow);
}
.io2-mast-meta {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:1.4px; text-transform:uppercase;
color:#cbd5e1; display:flex; gap:14px;
}
.io2-mast-meta strong { color:var(--yellow); }
/* Modes selector — luxe segmented control (themed by --mc set on <body>) */
.io2-mode-tabs {
--mt-c: var(--mc, var(--navy));
display:flex; gap:5px; padding:5px;
border:1px solid color-mix(in srgb, var(--mt-c) 16%, var(--line));
border-radius:16px;
background:linear-gradient(180deg, #f7f8fc 0%, #eceff6 100%);
box-shadow:inset 0 1px 3px rgba(15,23,42,.07);
margin-bottom:22px;
}
.io2-mode-tabs button {
flex:1; position:relative; isolation:isolate;
background:transparent; border:0; border-radius:11px;
padding:13px 14px;
font-family:'Playfair Display',serif; font-size:15px; font-weight:600;
color:var(--ink-soft); cursor:pointer; letter-spacing:.2px;
display:inline-flex; align-items:center; justify-content:center; gap:9px;
transition:color .22s ease, background .22s ease, box-shadow .3s cubic-bezier(.16,1,.3,1), transform .22s ease;
}
.io2-mode-tabs button .mt-ico {
display:inline-flex; width:17px; height:17px; flex:0 0 auto;
opacity:.65; transition:opacity .22s ease, transform .22s ease, color .22s ease;
}
.io2-mode-tabs button .mt-ico svg { width:100%; height:100%; stroke:currentColor; }
.io2-mode-tabs button:hover:not(.active) { color:var(--ink); background:rgba(255,255,255,.6); }
.io2-mode-tabs button:hover:not(.active) .mt-ico { opacity:.95; }
.io2-mode-tabs button.active {
color:var(--navy); background:#fff; transform:translateY(-1px);
box-shadow:
0 9px 24px -9px color-mix(in srgb, var(--mt-c) 48%, transparent),
0 1px 2px rgba(15,23,42,.09),
inset 0 0 0 1px color-mix(in srgb, var(--mt-c) 22%, transparent);
}
.io2-mode-tabs button.active .mt-ico { opacity:1; color:var(--mt-c); transform:scale(1.08); }
.io2-mode-tabs button.active::after {
content:""; position:absolute; left:24%; right:24%; bottom:5px; height:2.5px; border-radius:3px;
background:linear-gradient(90deg, transparent, var(--mt-c), transparent);
}
@media (max-width:680px){
.io2-mode-tabs { flex-wrap:wrap; }
.io2-mode-tabs button { flex:1 1 calc(50% - 5px); font-size:13.5px; padding:11px 10px; }
}
/* Drop zone — clean technical look */
.io2-drop {
position:relative;
border:2px dashed var(--line);
background:#fffdf6;
padding:40px 32px;
text-align:center; cursor:pointer;
transition:background .2s ease, border-color .2s ease;
}
.io2-drop:hover, .io2-drop.hover {
background:#fef9c3; border-color:var(--navy);
}
.io2-drop.has-file {
border-style:solid; border-color:var(--navy);
background:#fff;
padding:20px 24px;
text-align:left;
}
.io2-drop-circle {
width:60px; height:60px;
margin:0 auto 14px;
border:1.5px solid var(--navy);
background:#fff;
display:flex; align-items:center; justify-content:center;
color:var(--navy);
}
.io2-drop-title {
font-family:'Playfair Display',serif;
font-size:22px; font-weight:600;
color:var(--ink);
margin-bottom:6px;
}
.io2-drop-sub { font-size:13px; color:var(--ink-soft); }
/* CTA — luxe navy hardware with light-sweep + sliding arrow (glow themed by --mc) */
.io2-cta {
position:relative; overflow:hidden;
background:linear-gradient(135deg, #0b2e67 0%, var(--navy) 45%, #03184a 100%);
color:#fff;
font-family:'Playfair Display',serif; font-size:15px; font-weight:700; letter-spacing:.3px;
padding:14px 28px; border:0; border-radius:13px; cursor:pointer;
display:inline-flex; align-items:center; gap:10px;
box-shadow:0 10px 26px -10px color-mix(in srgb, var(--mc, var(--navy)) 55%, transparent), inset 0 1px 0 rgba(255,255,255,.14);
transition:transform .2s ease, box-shadow .25s ease, filter .2s ease;
}
.io2-cta::before {
content:""; position:absolute; inset:0; pointer-events:none;
background:linear-gradient(115deg, transparent 35%, rgba(255,255,255,.28) 50%, transparent 65%);
transform:translateX(-130%); transition:transform .75s ease;
}
.io2-cta::after { content:"\2192"; font-family:'Playfair Display',serif; transition:transform .25s ease; }
.io2-cta:hover:not(:disabled) {
transform:translateY(-2px); filter:brightness(1.07);
box-shadow:0 16px 34px -12px color-mix(in srgb, var(--mc, var(--navy)) 65%, transparent), inset 0 1px 0 rgba(255,255,255,.18);
}
.io2-cta:hover:not(:disabled)::before { transform:translateX(130%); }
.io2-cta:hover:not(:disabled)::after { transform:translateX(4px); }
.io2-cta:active:not(:disabled) { transform:translateY(0); }
.io2-cta:disabled { background:#cbd5e1; box-shadow:none; cursor:wait; }
.io2-cta:disabled::before, .io2-cta:disabled::after { display:none; }
/* ─── HERO with score gauge + 4 module gauges ─── */
.io2-hero-grid {
display:grid;
grid-template-columns: 1fr 280px;
gap:0;
border:1px solid var(--line);
background:#fff;
overflow:hidden;
}
@media (max-width: 900px) { .io2-hero-grid { grid-template-columns:1fr; } }
.io2-verdict-side {
padding:32px 36px;
background:#fff;
border-right:1px solid var(--line);
position:relative;
border-left:6px solid var(--io2-bd, var(--navy));
}
@media (max-width: 900px) {
.io2-verdict-side { border-right:0; border-bottom:1px solid var(--line); }
}
.io2-verdict-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:2px; text-transform:uppercase;
color:var(--ink-soft); margin-bottom:8px;
}
.io2-verdict-label {
font-family:'Playfair Display',serif;
font-size:42px; font-weight:800;
line-height:1; letter-spacing:-1px;
color:var(--io2-color);
margin:6px 0 18px;
}
.io2-verdict-deck {
font-family:'Playfair Display', serif;
font-style:italic; font-size:15px;
color:var(--ink-soft);
max-width:420px;
line-height:1.55;
margin-bottom:22px;
}
.io2-verdict-bar {
height:14px;
background:linear-gradient(90deg, #22C55E 0%, #22C55E 40%, #F59E0B 40%, #F59E0B 60%, #F97316 60%, #F97316 80%, #E53E3E 80%, #E53E3E 100%);
position:relative;
margin:14px 0 8px;
}
.io2-verdict-pin {
position:absolute; top:-6px;
width:2px; height:26px; background:#0b1220;
transform:translateX(-1px);
transition:left 1s var(--ease-out);
}
.io2-verdict-pin::after {
content:""; position:absolute; top:-7px; left:-5px;
width:12px; height:12px; background:#0b1220;
transform:rotate(45deg);
}
.io2-verdict-bar-labels {
display:flex; justify-content:space-between;
font-family:ui-monospace,Menlo,monospace;
font-size:9px; color:var(--ink-faint);
letter-spacing:1px; text-transform:uppercase;
margin-top:6px;
}
/* The 4 sub-module mini-gauges on the right */
.io2-modules-side {
padding:24px 28px;
background:linear-gradient(180deg, #fffdf6 0%, #ffffff 100%);
display:flex; flex-direction:column; gap:14px;
}
.io2-mod-cell {
padding:0;
}
.io2-mod-cell .mod-head {
display:flex; align-items:baseline; justify-content:space-between;
margin-bottom:6px;
}
.io2-mod-cell .mod-name {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; text-transform:uppercase; letter-spacing:1.4px;
color:var(--ink-soft); font-weight:700;
}
.io2-mod-cell .mod-val {
font-family:'Playfair Display',serif;
font-weight:700; font-size:18px;
color:var(--ink);
font-variant-numeric:tabular-nums;
}
.io2-mod-bar {
height:6px; background:#f1f5f9;
position:relative;
}
.io2-mod-bar > div {
height:100%; width:0;
background:linear-gradient(90deg, var(--mb-from, #22C55E), var(--mb-to, #E53E3E));
transition:width 1s var(--ease-out);
}
.io2-mod-cell .mod-desc {
font-size:10px; color:var(--ink-faint);
margin-top:4px; font-style:italic;
}
/* Image + bboxes (large central display) */
.io2-image-card {
padding:24px;
background:#0b1220;
color:#cbd5e1;
border:1px solid var(--line);
}
.io2-image-head {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; letter-spacing:2px; text-transform:uppercase;
color:#facc15; font-weight:700;
display:flex; align-items:center; gap:8px;
margin-bottom:14px;
}
.io2-image-head::before {
content:""; width:6px; height:6px; border-radius:50%;
background:#facc15;
}
.io2-image-card img {
width:100%; display:block;
max-height:520px; object-fit:contain;
background:#000;
}
.io2-image-empty {
padding:80px 20px; text-align:center;
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:1.5px; color:#475569;
}
.io2-bbox-legend {
margin-top:14px;
display:flex; gap:8px; flex-wrap:wrap;
}
.io2-bbox-pill {
font-family:ui-monospace,Menlo,monospace;
font-size:11px;
padding:4px 10px;
background:rgba(250,204,21,0.12);
color:#fef08a;
border:1px solid rgba(250,204,21,0.3);
}
/* Extracted text card */
.io2-text-card {
padding:24px 26px;
background:#fff; border:1px solid var(--line);
border-left:4px solid var(--yellow);
}
.io2-text-card .ed-section-head { padding-bottom:0; border-bottom:0; margin-bottom:8px; }
.io2-text-extract {
font-family:'Playfair Display',serif;
font-size:24px; line-height:1.3;
color:var(--ink);
margin:14px 0;
padding:14px 18px;
background:#fffdf6;
border-left:3px solid var(--navy);
}
.io2-text-meta {
display:flex; gap:18px; flex-wrap:wrap;
margin-top:14px;
font-size:13px;
color:var(--ink-soft);
}
.io2-text-meta > div { display:flex; flex-direction:column; }
.io2-text-meta .k {
font-size:10px; text-transform:uppercase; letter-spacing:1.2px;
color:var(--ink-faint); font-weight:700;
}
.io2-text-meta .v { color:var(--ink); font-weight:600; margin-top:2px; }
.io2-text-meta .v.manip { color:#dc2626; }
.io2-text-meta .v.neutre { color:#16a34a; }
/* XAI heatmap strip */
.io2-xai-strip {
display:grid; grid-template-columns:repeat(3, 1fr);
gap:14px;
}
@media (max-width: 900px) { .io2-xai-strip { grid-template-columns:1fr; } }
.io2-xai-card {
background:#fff; border:1px solid var(--line);
padding:16px;
transition:transform .2s ease, box-shadow .2s ease;
}
.io2-xai-card:hover {
transform:translateY(-2px);
box-shadow:0 12px 28px -16px rgba(15,23,42,.18);
}
.io2-xai-card .xai-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; letter-spacing:1.6px; text-transform:uppercase;
font-weight:700;
margin-bottom:6px;
}
.io2-xai-card.viridis .xai-kicker { color:#7c3aed; }
.io2-xai-card.inferno .xai-kicker { color:#c2410c; }
.io2-xai-card.jet .xai-kicker { color:#1d4ed8; }
.io2-xai-card h4 {
font-family:'Playfair Display',serif;
font-size:18px; line-height:1.15;
margin:0 0 4px;
color:var(--ink); letter-spacing:-.2px;
}
.io2-xai-card .xai-citation {
font-size:11px; color:var(--ink-soft); font-style:italic;
margin-bottom:10px;
}
.io2-xai-card img {
width:100%; display:block; cursor:zoom-in;
transition:opacity .2s ease;
}
.io2-xai-card img:hover { opacity:.92; }
.io2-xai-card .xai-desc {
font-size:12px; color:var(--ink-soft);
line-height:1.5; margin-top:10px;
}
/* ════════════════════════════════════════════════════════════════════
IO2 v2 — Hero gauge SVG + extra XAI (SHAP, LIME, per-module, counter)
════════════════════════════════════════════════════════════════════ */
/* Circular SVG gauge in hero */
.io2-gauge {
position:relative;
width:170px; height:170px;
flex-shrink:0;
}
.io2-gauge svg { width:100%; height:100%; transform:rotate(-90deg); }
.io2-gauge .g-bg { fill:none; stroke:#f1f5f9; stroke-width:14; }
.io2-gauge .g-arc {
fill:none;
stroke-width:14; stroke-linecap:round;
stroke-dasharray:0 1000;
transition:stroke-dasharray 1.4s cubic-bezier(.16,1,.3,1);
}
.io2-gauge .g-center {
position:absolute; inset:0;
display:flex; flex-direction:column; align-items:center; justify-content:center;
}
.io2-gauge .g-num {
font-family:'Playfair Display',serif; font-weight:800;
font-size:36px; line-height:1; color:var(--ink);
font-variant-numeric:tabular-nums;
}
.io2-gauge .g-lbl {
font-size:10px; text-transform:uppercase; letter-spacing:1.5px;
color:var(--ink-soft); margin-top:5px; font-weight:700;
}
/* Refined hero with gauge on the right side */
.io2-hero-grid-v2 {
display:grid;
grid-template-columns: 1fr 200px 280px;
gap:0;
border:1px solid var(--line);
background:#fff;
overflow:hidden;
}
@media (max-width: 1000px) { .io2-hero-grid-v2 { grid-template-columns: 1fr; } }
.io2-hero-gauge-side {
padding:24px;
display:flex; align-items:center; justify-content:center;
border-right:1px solid var(--line);
background:linear-gradient(135deg, #fffdf6 0%, #ffffff 100%);
}
@media (max-width: 1000px) {
.io2-hero-gauge-side { border-right:0; border-bottom:1px solid var(--line); }
}
/* Module gauges with mono monogram (T R V D M) */
.io2-modules-side .io2-mod-cell {
display:grid; grid-template-columns: 26px 1fr; gap:12px; align-items:start;
}
.io2-mod-mono {
width:26px; height:26px; border-radius:50%;
display:flex; align-items:center; justify-content:center;
color:#fff; font-family:'Playfair Display',serif;
font-weight:700; font-size:12px;
flex-shrink:0;
}
.io2-mod-mono.trocr { background:#b45309; } /* T */
.io2-mod-mono.roberta { background:#5b21b6; } /* R */
.io2-mod-mono.vit { background:#1d4ed8; } /* V */
.io2-mod-mono.detr { background:#be185d; } /* D */
.io2-mod-mono.manipnet { background:#0f766e; } /* M */
/* Module verdict labels (verdict per module from threshold) */
.io2-mod-verdict-pill {
display:inline-block; padding:1px 7px;
font-size:9px; font-weight:700; letter-spacing:.6px;
text-transform:uppercase; margin-top:3px;
}
.io2-mod-verdict-pill.auth { background:#dcfce7; color:#166534; }
.io2-mod-verdict-pill.susp { background:#fef3c7; color:#92400e; }
.io2-mod-verdict-pill.manip { background:#fed7aa; color:#9a3412; }
.io2-mod-verdict-pill.tres { background:#fee2e2; color:#7f1d1d; }
/* ─── XAI Suite intro for io2 ─── */
.io2-xai-banner {
background:#0b1220;
color:#e5e7eb;
padding:22px 28px;
display:grid; grid-template-columns: 1fr auto;
align-items:center; gap:22px;
border:1px solid var(--line);
}
.io2-xai-banner .xs-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:2px; text-transform:uppercase;
color:var(--yellow); margin-bottom:6px; font-weight:700;
}
.io2-xai-banner h3 {
font-family:'Playfair Display',serif;
font-size:24px; line-height:1.15; margin:0;
color:#fff; letter-spacing:-.3px;
}
.io2-xai-banner .xs-meta {
font-family:ui-monospace,Menlo,monospace; font-size:11px;
color:#94a3b8; letter-spacing:1.4px; text-transform:uppercase;
text-align:right; line-height:1.7;
}
.io2-xai-banner .xs-meta strong { color:var(--yellow); }
/* SHAP-style waterfall — module contribution bars */
.io2-shap-list { display:flex; flex-direction:column; gap:12px; }
.io2-shap-row {
display:grid; grid-template-columns: 36px 130px 1fr 80px;
gap:14px; align-items:center;
padding:8px 0;
font-size:13px;
}
.io2-shap-row .nm {
font-family:ui-monospace,Menlo,monospace; font-size:11px;
font-weight:700; letter-spacing:.4px; color:var(--ink);
}
.io2-shap-bar-wrap {
position:relative; height:18px;
background:linear-gradient(90deg, var(--line) 49.6%, var(--line) 50.4%, transparent 50.4%);
background-size:100% 100%;
border-left:1px solid var(--line);
}
.io2-shap-bar {
height:100%; width:0;
transition:width 1s var(--ease-out);
}
.io2-shap-bar.neg { background:linear-gradient(90deg, #fca5a5, #dc2626); float:right; margin-right:50%; }
.io2-shap-bar.pos { background:linear-gradient(90deg, #16a34a, #86efac); margin-left:50%; }
.io2-shap-row .v {
text-align:right;
font-family:ui-monospace,Menlo,monospace; font-size:13px;
font-weight:700; font-variant-numeric:tabular-nums;
}
.io2-shap-row .v.pos { color:#16a34a; }
.io2-shap-row .v.neg { color:#dc2626; }
.io2-shap-axis {
display:flex; justify-content:space-between;
font-size:10px; color:var(--ink-faint);
letter-spacing:1px; text-transform:uppercase;
margin-top:6px; padding:0 80px 0 184px;
}
/* LIME word salience tokens (re-uses lime-token CSS pattern) */
.io2-lime-claim {
font-family:'Playfair Display',serif; font-size:22px;
line-height:1.6; padding:14px 0;
border-top:1px solid var(--line);
border-bottom:1px solid var(--line);
margin:14px 0;
}
.io2-lime-tok {
display:inline-block;
padding:2px 5px; margin:0 1px;
transition:transform .15s ease;
cursor:default;
}
.io2-lime-tok[data-w="0"] { color:var(--ink); }
.io2-lime-tok[data-w="1"] { background:#fef9c3; color:#713f12; }
.io2-lime-tok[data-w="2"] { background:#fed7aa; color:#9a3412; }
.io2-lime-tok[data-w="3"] { background:#fecaca; color:#7f1d1d; font-weight:600; }
.io2-lime-tok[data-w="4"] { background:#dc2626; color:#fff; font-weight:700; }
.io2-lime-tok[title]:hover { transform:translateY(-1px); }
/* Per-module verdict cells (5 cells, one per sub-model) */
.io2-pmv-grid {
display:grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap:12px;
}
.io2-pmv-cell {
padding:14px 16px;
border:1px solid var(--line);
background:linear-gradient(180deg, #fafbff 0%, #ffffff 100%);
transition:transform .15s ease, box-shadow .2s ease;
}
.io2-pmv-cell:hover { transform:translateY(-2px); box-shadow:0 6px 14px -8px rgba(15,23,42,.18); }
.io2-pmv-cell .pmv-head {
display:flex; align-items:center; gap:8px;
font-family:ui-monospace,Menlo,monospace; font-size:10px;
font-weight:700; letter-spacing:1.2px; text-transform:uppercase;
color:var(--ink-soft);
margin-bottom:8px;
}
.io2-pmv-cell .pmv-score {
font-family:'Playfair Display',serif; font-weight:800;
font-size:24px; line-height:1; color:var(--ink);
font-variant-numeric:tabular-nums;
}
.io2-pmv-cell .pmv-verdict {
display:inline-block; margin-top:8px;
padding:3px 9px; font-size:10px; font-weight:700;
letter-spacing:.6px; text-transform:uppercase;
}
.io2-pmv-cell[data-v="auth"] { border-top:3px solid #22C55E; }
.io2-pmv-cell[data-v="susp"] { border-top:3px solid #F59E0B; }
.io2-pmv-cell[data-v="manip"] { border-top:3px solid #F97316; }
.io2-pmv-cell[data-v="tres"] { border-top:3px solid #E53E3E; }
.io2-pmv-cell[data-v="auth"] .pmv-verdict { background:#dcfce7; color:#166534; }
.io2-pmv-cell[data-v="susp"] .pmv-verdict { background:#fef3c7; color:#92400e; }
.io2-pmv-cell[data-v="manip"] .pmv-verdict { background:#fed7aa; color:#9a3412; }
.io2-pmv-cell[data-v="tres"] .pmv-verdict { background:#fee2e2; color:#7f1d1d; }
/* Counterfactual rows */
.io2-cf-list { display:flex; flex-direction:column; gap:8px; }
.io2-cf-row {
display:grid; grid-template-columns: 36px 1fr auto auto;
gap:14px; align-items:center;
padding:12px 16px;
background:#fafbff;
border:1px solid var(--line);
transition:border-color .15s ease, transform .15s ease;
}
.io2-cf-row:hover { border-color:var(--navy); transform:translateX(2px); }
.io2-cf-row .cf-mono { /* re-uses io2-mod-mono */ }
.io2-cf-row .cf-text {
font-size:13px; color:var(--ink-soft); line-height:1.4;
}
.io2-cf-row .cf-text strong {
color:var(--ink); font-weight:700;
font-variant-numeric:tabular-nums;
}
.io2-cf-row .cf-arrow-num {
font-family:ui-monospace,Menlo,monospace;
font-size:13px; font-weight:700;
color:var(--ink); font-variant-numeric:tabular-nums;
}
.io2-cf-row .cf-flip {
font-size:10px; padding:3px 9px;
font-weight:700; letter-spacing:.6px; text-transform:uppercase;
}
.io2-cf-row .cf-flip.flip { background:#fee2e2; color:#7f1d1d; }
.io2-cf-row .cf-flip.stable { background:#f1f5f9; color:var(--ink-soft); }
/* ════════════════════════════════════════════════════════════════════
IO4 — Photoshop Forensics (Rayen)
"Forensics lab" style: navy + yellow + cream, I/C/S/E monograms,
2 side-by-side overlays (mask + grad-cam), adjustable threshold.
════════════════════════════════════════════════════════════════════ */
.io4-mast {
background:#0b1220;
color:#fff; padding:14px 24px;
display:flex; align-items:center; justify-content:space-between;
gap:18px; flex-wrap:wrap;
border:1px solid #1f2937;
}
.io4-mast-title {
font-family:'Playfair Display',serif;
font-size:14px; font-weight:700;
display:flex; align-items:center; gap:10px;
}
.io4-mast-title::before {
content:""; width:8px; height:8px;
background:var(--yellow);
}
.io4-mast-meta {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:1.4px; text-transform:uppercase;
color:#94a3b8; display:flex; gap:14px;
}
.io4-mast-meta strong { color:var(--yellow); }
/* Drop zone — lab clipboard style */
.io4-mode-btn {
flex:1 1 220px; min-width:200px;
display:flex; flex-direction:column; gap:3px;
text-align:left; cursor:pointer;
padding:13px 16px;
border:1px solid #d4c994; background:#fffdf6;
font-family:'Inter',system-ui,sans-serif; font-weight:600; font-size:14px; color:var(--ink);
transition:background .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.io4-mode-btn small { font-weight:400; font-size:11.5px; color:var(--ink-soft); line-height:1.45; }
.io4-mode-btn:hover:not(.active) { background:#fff8b3; border-color:var(--navy); }
.io4-mode-btn.active {
background:var(--navy); color:#fff; border-color:var(--navy);
box-shadow:0 6px 22px rgba(5,41,98,.22);
}
.io4-mode-btn.active small { color:rgba(255,255,255,.78); }
.io4-drop {
position:relative;
border:2px dashed #d4c994;
background:#fffdf6;
padding:36px 28px;
text-align:center; cursor:pointer;
transition:background .2s ease, border-color .2s ease;
}
.io4-drop:hover, .io4-drop.hover {
background:#fff8b3; border-color:var(--navy);
}
.io4-drop.has-file { border-style:solid; border-color:var(--navy); padding:20px 24px; text-align:left; }
.io4-drop-cross {
display:inline-flex; align-items:center; justify-content:center;
width:50px; height:50px;
background:var(--navy); color:var(--yellow);
margin-bottom:14px;
font-family:'Playfair Display',serif;
font-weight:800; font-size:24px;
}
.io4-drop-title {
font-family:'Playfair Display',serif;
font-size:21px; font-weight:600;
color:var(--ink); margin-bottom:6px;
}
.io4-drop-sub { font-size:13px; color:var(--ink-soft); }
.io4-drop-formats {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; letter-spacing:1.4px; text-transform:uppercase;
color:var(--ink-faint);
margin-top:14px;
}
/* CTA — same as io6 (yellow with navy text) */
.io4-cta {
background:var(--yellow); color:var(--navy);
font-family:'Playfair Display',serif;
font-size:15px; font-weight:700;
padding:13px 26px;
border:1.5px solid var(--navy); cursor:pointer;
letter-spacing:.3px;
transition:all .15s ease;
display:inline-flex; align-items:center; gap:8px;
}
.io4-cta::after { content:"→"; transition:transform .2s ease; }
.io4-cta:hover:not(:disabled) {
background:var(--navy); color:var(--yellow);
transform:translateY(-1px);
}
.io4-cta:hover:not(:disabled)::after { transform:translateX(4px); }
.io4-cta:disabled { opacity:.6; cursor:wait; }
/* Threshold slider */
.io4-threshold {
display:flex; align-items:center; gap:14px;
padding:14px 18px;
background:#fff;
border:1px solid var(--line);
margin-bottom:18px;
flex-wrap:wrap;
}
.io4-threshold-label {
font-family:'Playfair Display',serif;
font-style:italic; font-size:14px;
color:var(--ink);
}
.io4-threshold input[type=range] {
flex:1; min-width:200px; max-width:280px;
accent-color:var(--navy);
}
.io4-threshold-val {
font-family:ui-monospace,Menlo,monospace;
font-weight:700; color:var(--navy);
font-variant-numeric:tabular-nums;
font-size:14px;
padding:3px 10px; background:#fff8b3;
border:1px solid #d4c994;
}
.io4-threshold-hint {
font-size:11px; color:var(--ink-soft);
letter-spacing:.4px;
width:100%;
}
/* ─── Hero verdict ───────────────────────────────────────────────── */
.io4-hero {
padding:32px 40px;
border:1px solid var(--line);
background:#fff;
border-left:6px solid var(--io4-bd, var(--navy));
display:grid;
grid-template-columns: 1fr 200px;
gap:32px; align-items:center;
}
@media (max-width: 800px) { .io4-hero { grid-template-columns:1fr; } }
.io4-hero[data-v="AUTHENTIC"] { --io4-bd:#16a34a; --io4-ink:#14532d; }
.io4-hero[data-v="FAKE"] { --io4-bd:#dc2626; --io4-ink:#7f1d1d; }
.io4-hero-kicker {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:2px; text-transform:uppercase;
color:var(--ink-soft); margin-bottom:8px;
display:flex; align-items:center; gap:10px;
}
.io4-hero-kicker::before {
content:""; width:8px; height:8px;
background:var(--io4-bd); border-radius:50%;
}
.io4-hero-verdict {
font-family:'Playfair Display',serif;
font-size:48px; font-weight:800;
line-height:1; letter-spacing:-1px;
color:var(--io4-ink);
margin:6px 0 16px;
}
.io4-hero-class {
display:inline-block;
padding:5px 14px;
background:#fef9c3; color:#713f12;
font-family:'Playfair Display',serif; font-style:italic;
font-size:18px;
margin-bottom:12px;
}
.io4-hero-deck {
font-size:14px; line-height:1.55; color:var(--ink-soft);
max-width:480px;
font-style:italic;
font-family:'Playfair Display',serif;
}
.io4-hero-meta {
display:flex; gap:20px; flex-wrap:wrap; margin-top:18px;
font-size:12px;
}
.io4-hero-meta > div { display:flex; flex-direction:column; }
.io4-hero-meta .k { font-size:10px; text-transform:uppercase; letter-spacing:1.2px; color:var(--ink-faint); font-weight:700; }
.io4-hero-meta .v { font-family:ui-monospace,Menlo,monospace; font-weight:700; margin-top:3px; color:var(--ink); }
/* Big confidence number on the right */
.io4-hero-conf {
text-align:center;
}
.io4-hero-conf .num {
font-family:'Playfair Display',serif;
font-weight:800; font-size:56px;
line-height:1; color:var(--io4-ink);
font-variant-numeric:tabular-nums;
}
.io4-hero-conf .lbl {
font-size:10px; text-transform:uppercase; letter-spacing:1.6px;
color:var(--ink-soft); margin-top:8px; font-weight:700;
}
.io4-hero-conf .thresh-mark {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; color:var(--ink-faint);
margin-top:6px;
}
/* ─── 4-class confidence bars ─── */
.io4-cls-grid {
display:grid; gap:14px;
}
.io4-cls-row {
display:grid;
grid-template-columns: 36px 1fr 70px;
gap:14px; align-items:center;
padding:8px 0;
}
.io4-cls-mono {
width:32px; height:32px; border-radius:50%;
display:flex; align-items:center; justify-content:center;
color:#fff; font-family:'Playfair Display',serif;
font-weight:700; font-size:14px;
}
.io4-cls-mono.i { background:#5b21b6; } /* Inpainting — purple */
.io4-cls-mono.c { background:#b45309; } /* Copy-move — amber */
.io4-cls-mono.s { background:#be185d; } /* Splicing — pink */
.io4-cls-mono.e { background:#1d4ed8; } /* Enhancement — blue */
.io4-cls-info {
display:flex; flex-direction:column;
gap:4px;
}
.io4-cls-info .nm {
font-family:'Playfair Display',serif;
font-weight:600; font-size:15px;
display:flex; align-items:baseline; gap:8px;
}
.io4-cls-info .nm .winner {
font-family:ui-monospace,Menlo,monospace;
font-size:10px; padding:1px 7px;
background:#dc2626; color:#fff;
letter-spacing:.6px;
}
.io4-cls-bar {
height:10px; background:#f1f5f9;
position:relative;
overflow:hidden;
}
.io4-cls-bar > div {
height:100%; width:0;
transition:width 1s var(--ease-out);
}
.io4-cls-bar > div.winner {
background:linear-gradient(90deg, #dc2626, #ef4444);
}
.io4-cls-bar > div.other {
background:linear-gradient(90deg, #94a3b8, #cbd5e1);
}
.io4-cls-bar .thresh-line {
position:absolute; top:-3px; bottom:-3px;
width:1.5px; background:var(--navy);
pointer-events:none;
}
.io4-cls-bar .thresh-line::after {
content:"⋆"; position:absolute; top:-12px; left:-4px;
color:var(--navy); font-size:10px;
}
.io4-cls-row .val {
text-align:right;
font-family:ui-monospace,Menlo,monospace;
font-size:14px; font-weight:700;
color:var(--ink); font-variant-numeric:tabular-nums;
}
.io4-cls-row .val.winner { color:#dc2626; }
/* ─── Two overlays side by side ─── */
.io4-overlays {
display:grid; grid-template-columns:1fr 1fr; gap:14px;
}
@media (max-width: 800px) { .io4-overlays { grid-template-columns:1fr; } }
.io4-overlay-card {
background:#0b1220; color:#cbd5e1;
border:1px solid #1f2937;
padding:16px;
}
.io4-overlay-card .head {
font-family:ui-monospace,Menlo,monospace;
font-size:11px; letter-spacing:1.6px; text-transform:uppercase;
font-weight:700;
margin-bottom:10px;
display:flex; align-items:center; gap:8px;
}
.io4-overlay-card.mask .head { color:#fb7185; }
.io4-overlay-card.cam .head { color:#facc15; }
.io4-overlay-card.mask .head::before {
content:""; width:6px; height:6px; background:#fb7185;
}
.io4-overlay-card.cam .head::before {
content:""; width:6px; height:6px; background:#facc15;
}
.io4-overlay-card img {
width:100%; display:block;
cursor:zoom-in;
transition:opacity .2s ease;
}
.io4-overlay-card img:hover { opacity:.94; }
.io4-overlay-card .caption {
font-size:11px; color:#94a3b8;
margin-top:8px; line-height:1.5;
font-family:'Playfair Display',serif;
font-style:italic;
}
/* ─── Decision logic explanation card ─── */
.io4-logic-card {
padding:24px 28px 24px 56px;
background:#fff;
border:1px solid var(--line);
position:relative;
font-family:'Playfair Display', serif;
font-size:15px; line-height:1.65;
}
.io4-logic-card::before {
content:"§"; position:absolute; left:18px; top:14px;
font-family:'Playfair Display',serif;
color:var(--navy); opacity:.4;
font-size:36px; line-height:1;
}
.io4-logic-card mark {
background:#fff8b3; padding:1px 6px;
font-family:ui-monospace,Menlo,monospace;
font-size:.8em; letter-spacing:.4px;
font-weight:700;
}
.io4-logic-card mark.bad { background:#fecaca; color:#7f1d1d; }
.io4-logic-card mark.good { background:#bbf7d0; color:#14532d; }
.io4-logic-card .lc-byline {
display:block; margin-top:14px;
font-family:ui-monospace,Menlo,monospace;
font-size:11px;
color:var(--ink-faint); letter-spacing:1.2px; text-transform:uppercase;
font-style:normal;
}
/* ═══════════════════════════════════════════════════════════
IO6 — "Verify Index": cosmetics campaigns already verified
═══════════════════════════════════════════════════════════ */
.vidx { margin: 4px 0 38px; }
/* scroll-reveal */
.vidx-rv { opacity:0; transform:translateY(22px); transition:opacity .7s var(--ease-out), transform .7s var(--ease-out); }
.vidx-rv.in { opacity:1; transform:none; }
.vidx-grid > * { transition:opacity .45s var(--ease-out), transform .45s var(--ease-out); }
.vidx-grid.filtering > * { opacity:0; transform:scale(.96); }
/* header */
.vidx-top { display:flex; align-items:flex-end; justify-content:space-between; gap:20px; flex-wrap:wrap; }
.vidx-kicker {
display:inline-flex; align-items:center; gap:8px;
font-family:ui-monospace,Menlo,monospace; font-size:11px; font-weight:700;
letter-spacing:2px; text-transform:uppercase; color:#9a3412; margin-bottom:8px;
}
.vidx-live { display:inline-flex; align-items:center; gap:6px; color:#16a34a; font-size:10.5px; letter-spacing:1.6px; }
.vidx-live .ld { width:7px; height:7px; border-radius:50%; background:#16a34a; box-shadow:0 0 0 0 rgba(22,163,74,.55); animation:vidx-pulse 1.9s infinite; }
@keyframes vidx-pulse { 0%{box-shadow:0 0 0 0 rgba(22,163,74,.5);} 70%{box-shadow:0 0 0 8px rgba(22,163,74,0);} 100%{box-shadow:0 0 0 0 rgba(22,163,74,0);} }
.vidx-top h3 {
font-family:'Playfair Display', Georgia, serif; font-weight:800;
font-size:30px; line-height:1.1; color:var(--navy); margin:0; max-width:560px;
}
.vidx-top .vidx-sub { font-size:13.5px; color:#6b7280; max-width:300px; line-height:1.55; }
/* stats ribbon */
.vidx-stats {
display:grid; grid-template-columns:repeat(3,1fr); gap:0;
margin:22px 0 24px; border:1px solid var(--line); background:#fff;
}
@media (max-width:640px){ .vidx-stats{ grid-template-columns:1fr; } }
.vidx-stat { padding:18px 22px; border-right:1px solid var(--line); }
.vidx-stat:last-child { border-right:0; }
@media (max-width:640px){ .vidx-stat{ border-right:0; border-bottom:1px solid var(--line);} .vidx-stat:last-child{border-bottom:0;} }
.vidx-stat .v {
font-family:'Playfair Display', Georgia, serif; font-weight:800; font-size:34px;
line-height:1; color:var(--navy); font-variant-numeric:tabular-nums;
}
.vidx-stat .l {
font-size:11px; letter-spacing:1.4px; text-transform:uppercase; color:#9ca3af; margin-top:8px;
font-family:ui-monospace,Menlo,monospace;
}
.vidx-stat.bad .v { color:#dc2626; }
/* "On the global market" — auto-scrolling strip of real products (FAKE / REAL highlighted) */
.mw { margin-bottom:28px; }
.mw-head { display:flex; flex-direction:column; gap:6px; margin-bottom:16px; }
.mw-k {
font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:2.4px;
text-transform:uppercase; color:#9a3412;
}
.mw-sub { font-size:12.5px; color:#6b7280; line-height:1.55; max-width:600px; }
.mw-leg { display:inline-flex; align-items:center; gap:7px; flex-wrap:wrap; font-size:11px; color:#9ca3af; margin-top:2px; }
.mw-leg b {
font-family:ui-monospace,Menlo,monospace; font-weight:800; font-size:9.5px; letter-spacing:1.6px;
padding:2px 7px 3px; border-radius:4px; color:#fff;
}
.mw-leg b.bad { background:#dc2626; }
.mw-leg b.ok { background:#16a34a; }
.mw-leg .sep { opacity:.5; margin:0 2px; }
.mw-marquee {
-webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
padding:6px 0;
}
.mw-marquee .marquee__track { --mq-gap:16px; align-items:stretch; }
.mw-card {
flex:0 0 auto; width:272px; box-sizing:border-box;
background:#fff; border:1px solid var(--line); border-radius:14px; overflow:hidden;
box-shadow:0 8px 24px rgba(5,41,98,.05); transition:box-shadow .4s var(--ease-out), transform .4s var(--ease-out);
}
.mw-card:hover { box-shadow:0 18px 40px rgba(5,41,98,.16); transform:translateY(-3px); }
.mw-card[data-v="bad"] { --mw-c:#dc2626; --mw-tint:rgba(220,38,38,.07); }
.mw-card[data-v="ok"] { --mw-c:#16a34a; --mw-tint:rgba(22,163,74,.07); }
.mw-shot { position:relative; height:152px; background:#eef0f3; overflow:hidden; }
.mw-shot img {
width:100%; height:100%; object-fit:cover; display:block;
transition:transform .9s var(--ease-out); filter:saturate(1.04);
}
.mw-card:hover .mw-shot img { transform:scale(1.06); }
.mw-shot::after {
content:""; position:absolute; inset:0; pointer-events:none;
background:linear-gradient(180deg, rgba(255,255,255,0) 55%, var(--mw-tint) 100%);
box-shadow:inset 0 -34px 26px -18px rgba(255,255,255,.9), inset 0 0 0 1px rgba(5,41,98,.04), inset 0 3px 0 0 var(--mw-c);
}
/* small corner pill */
.mw-tag {
position:absolute; top:10px; left:10px; z-index:3;
font-family:ui-monospace,Menlo,monospace; font-size:10px; font-weight:800; letter-spacing:1.8px;
padding:4px 9px; border-radius:4px; color:#fff; background:var(--mw-c);
box-shadow:0 4px 12px rgba(0,0,0,.22);
}
/* big rubber-stamp word across the photo — the "mise en valeur" */
.mw-stamp {
position:absolute; top:50%; left:50%; transform:translate(-50%,-50%) rotate(-8deg); z-index:2;
font-family:ui-monospace,Menlo,monospace; font-weight:800; font-size:24px; letter-spacing:5px;
color:var(--mw-c); text-transform:uppercase; pointer-events:none;
padding:4px 14px 5px; border:3px solid var(--mw-c); border-radius:7px;
background:rgba(255,255,255,.82); text-shadow:0 1px 0 rgba(255,255,255,.9);
box-shadow:0 6px 16px rgba(0,0,0,.12);
}
.mw-card[data-v="ok"] .mw-stamp { transform:translate(-50%,-50%) rotate(-6deg); }
.mw-body { padding:13px 16px 15px; border-top:3px solid var(--mw-c); }
.mw-brand {
font-family:ui-monospace,Menlo,monospace; font-size:10px; letter-spacing:2px;
text-transform:uppercase; color:#6b7280;
}
.mw-name {
font-family:'Playfair Display', Georgia, serif; font-weight:800; font-size:16.5px;
line-height:1.15; color:#13132b; margin:2px 0 6px;
}
.mw-claim { font-style:italic; font-size:12px; color:#374151; line-height:1.4; min-height:32px; }
.mw-foot {
display:flex; align-items:flex-end; justify-content:space-between; gap:12px;
margin-top:9px; padding-top:8px; border-top:1px solid var(--line);
}
.mw-why { font-size:9.5px; color:#9ca3af; line-height:1.4; }
.mw-score {
font-family:'Playfair Display', Georgia, serif; font-weight:800; font-size:18px;
line-height:1; color:var(--mw-c); font-variant-numeric:tabular-nums; flex:0 0 auto;
}
.mw-note { font-size:10.5px; color:#9ca3af; line-height:1.55; margin:11px 2px 0; }
.mw-note em { font-style:italic; color:#6b7280; }
@media (max-width:640px){ .mw-card{ width:240px; } .mw-stamp{ font-size:20px; } }
@media (prefers-reduced-motion: reduce){ .mw-marquee .marquee__track{ animation:none; } }
/* filter chips */
.vidx-bar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:20px; }
.vidx-chip {
font:inherit; cursor:pointer; border:1px solid var(--line); background:#fff;
padding:8px 16px; font-size:13px; font-weight:600; color:#4b5563;
transition:all .2s var(--ease-out); display:inline-flex; align-items:center; gap:7px;
}
.vidx-chip:hover { border-color:var(--navy); color:var(--navy); }
.vidx-chip .n { font-family:ui-monospace,Menlo,monospace; font-size:11px; color:#9ca3af; }
.vidx-chip[aria-pressed="true"] { background:var(--navy); color:#fff; border-color:var(--navy); }
.vidx-chip[aria-pressed="true"] .n { color:rgba(255,255,255,.7); }
.vidx-chip .dot { width:8px; height:8px; }
.vidx-chip.f-ok .dot { background:#16a34a; }
.vidx-chip.f-bad .dot { background:#dc2626; }
/* faux ad poster card */
.ad-card {
position:relative; text-align:left; cursor:pointer; font:inherit;
background:#fff; border:1px solid var(--line); overflow:hidden;
display:flex; flex-direction:column;
transition:transform .3s var(--ease-out), box-shadow .3s var(--ease-out), border-color .3s;
}
.ad-card:hover { transform:translateY(-5px); box-shadow:0 22px 48px rgba(5,41,98,.16); border-color:var(--navy); }
.ad-poster {
position:relative; aspect-ratio:3/4; overflow:hidden;
background:linear-gradient(155deg, var(--th-a,#e7e9ff) 0%, var(--th-b,#cdd2f5) 100%);
padding:24px 22px; display:flex; flex-direction:column; justify-content:flex-end;
}
.ad-poster::after { /* faint product silhouette */
content:""; position:absolute; right:-18%; top:50%; transform:translateY(-50%);
width:62%; height:78%; border-radius:50% 50% 46% 46%;
background:radial-gradient(closest-side, rgba(255,255,255,.55), rgba(255,255,255,0));
pointer-events:none;
}
.ad-poster .ap-brand {
position:relative; z-index:2; font-family:ui-monospace,Menlo,monospace; font-size:10.5px;
letter-spacing:2.6px; text-transform:uppercase; color:var(--th-ink,#5b3a8a); margin-bottom:8px;
opacity:.92;
}
.ad-poster .ap-name {
position:relative; z-index:2; font-family:'Playfair Display', Georgia, serif; font-weight:800;
font-size:25px; line-height:1.08; color:#13132b; margin-bottom:10px;
}
.ad-poster .ap-tag {
position:relative; z-index:2; font-family:'Playfair Display', Georgia, serif; font-style:italic;
font-size:15px; line-height:1.45; color:#3a3a52; max-width:90%;
}
/* corner verdict ribbon */
.ad-ribbon { position:absolute; top:0; right:0; width:128px; height:128px; overflow:hidden; z-index:3; pointer-events:none; }
.ad-ribbon span {
position:absolute; display:block; width:182px; padding:7px 0; right:-46px; top:28px;
transform:rotate(45deg); text-align:center; color:#fff;
font-family:ui-monospace,Menlo,monospace; font-size:10.5px; font-weight:700; letter-spacing:2px; text-transform:uppercase;
box-shadow:0 3px 10px rgba(0,0,0,.18);
}
.ad-ribbon.ok span { background:#16a34a; }
.ad-ribbon.bad span { background:#dc2626; }
/* hover reveal panel */
.ad-reveal {
position:absolute; left:0; right:0; bottom:0; z-index:4;
padding:18px 20px 16px; color:#fff;
background:linear-gradient(0deg, rgba(8,10,30,.94) 30%, rgba(8,10,30,.78) 70%, rgba(8,10,30,0) 100%);
transform:translateY(101%); transition:transform .35s var(--ease-out);
}
.ad-card:hover .ad-reveal { transform:translateY(0); }
.ad-reveal .ar-k { font-family:ui-monospace,Menlo,monospace; font-size:10px; letter-spacing:2px; text-transform:uppercase; opacity:.7; margin-bottom:6px; }
.ad-reveal .ar-t { font-size:13.5px; line-height:1.5; }
.ad-foot {
display:flex; align-items:center; justify-content:space-between; gap:12px;
padding:13px 16px; font-size:11.5px; color:#6b7280;
}
.ad-foot .meter { display:flex; align-items:center; gap:8px; }
.ad-foot .meter .bar { width:54px; height:5px; background:#eef1f5; overflow:hidden; }
.ad-foot .meter .bar > i { display:block; height:100%; background:var(--m-c,#16a34a); width:0; transition:width .9s var(--ease-out); }
.ad-foot .meter .pc { font-family:ui-monospace,Menlo,monospace; font-weight:700; color:var(--navy); font-variant-numeric:tabular-nums; }
.ad-foot .go { color:var(--navy); font-weight:700; white-space:nowrap; }
/* featured "case of the week" */
.vidx-feature {
display:grid; grid-template-columns:minmax(260px,1.05fr) 1.25fr; gap:0;
border:1px solid var(--line); background:#fff; margin-bottom:26px; overflow:hidden;
}
@media (max-width:820px){ .vidx-feature{ grid-template-columns:1fr; } }
.vidx-feature .ff-poster {
position:relative; min-height:330px; overflow:hidden; padding:34px 30px;
display:flex; flex-direction:column; justify-content:flex-end;
background:linear-gradient(155deg, var(--th-a,#e7e9ff) 0%, var(--th-b,#cdd2f5) 100%);
}
.vidx-feature .ff-poster::after {
content:""; position:absolute; right:-14%; top:50%; transform:translateY(-50%);
width:58%; height:80%; border-radius:50% 50% 46% 46%;
background:radial-gradient(closest-side, rgba(255,255,255,.6), rgba(255,255,255,0));
}
.vidx-feature .ff-poster .ap-brand { position:relative; z-index:2; font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:3px; text-transform:uppercase; color:var(--th-ink,#5b3a8a); margin-bottom:10px; }
.vidx-feature .ff-poster .ap-name { position:relative; z-index:2; font-family:'Playfair Display', Georgia, serif; font-weight:800; font-size:36px; line-height:1.05; color:#13132b; margin-bottom:12px; }
.vidx-feature .ff-poster .ap-tag { position:relative; z-index:2; font-family:'Playfair Display', Georgia, serif; font-style:italic; font-size:18px; color:#3a3a52; max-width:88%; }
.vidx-feature .ff-body { padding:34px 36px; display:flex; flex-direction:column; }
.vidx-feature .ff-k {
display:inline-flex; align-items:center; gap:9px; align-self:flex-start;
font-family:ui-monospace,Menlo,monospace; font-size:10.5px; font-weight:700; letter-spacing:2.4px; text-transform:uppercase;
color:#9a3412; margin-bottom:14px;
}
.vidx-feature .ff-k::before { content:""; width:24px; height:2px; background:currentColor; }
.vidx-feature .ff-verdict {
display:inline-flex; align-items:center; gap:9px; align-self:flex-start;
font-family:ui-monospace,Menlo,monospace; font-size:12px; font-weight:700; letter-spacing:2px; text-transform:uppercase;
color:#fff; padding:7px 13px; margin-bottom:16px;
}
.vidx-feature .ff-verdict.ok { background:#16a34a; }
.vidx-feature .ff-verdict.bad { background:#dc2626; }
.vidx-feature .ff-claim {
font-family:'Playfair Display', Georgia, serif; font-size:23px; line-height:1.3; color:var(--navy);
margin:0 0 16px; padding-left:16px; border-left:3px solid var(--line);
}
.vidx-feature .ff-sum { font-size:14.5px; line-height:1.65; color:#4b5563; margin:0 0 22px; }
.vidx-feature .ff-cta {
align-self:flex-start; font:inherit; cursor:pointer;
background:var(--navy); color:#fff; border:0; padding:12px 22px; font-size:13px; font-weight:700;
letter-spacing:.4px; transition:transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.vidx-feature .ff-cta:hover { transform:translateY(-2px); box-shadow:0 12px 26px rgba(5,41,98,.22); }
/* the grid */
.vidx-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:18px; }
@media (max-width:1000px){ .vidx-grid{ grid-template-columns:repeat(2,1fr);} }
@media (max-width:560px){ .vidx-grid{ grid-template-columns:1fr;} }
.vidx-empty { padding:40px; text-align:center; color:#9ca3af; font-size:14px; border:1px dashed var(--line); }
/* ─── advanced report modal (.modal-box.deep-modal.vrx) ─── */
.vrx { --vc:#16a34a; }
.vrx.bad { --vc:#dc2626; }
.vrx .vrx-banner {
position:relative; margin:-42px -48px 24px; padding:34px 48px 28px; overflow:hidden;
background:linear-gradient(155deg, var(--th-a,#e7e9ff), var(--th-b,#cdd2f5));
}
@media (max-width:560px){ .vrx .vrx-banner{ margin:-28px -24px 22px; padding:26px 24px; } }
.vrx .vrx-banner::after {
content:""; position:absolute; right:-10%; top:50%; transform:translateY(-50%);
width:46%; height:120%; border-radius:50%;
background:radial-gradient(closest-side, rgba(255,255,255,.6), rgba(255,255,255,0));
}
.vrx .vrx-banner .vb-brand { position:relative; z-index:2; font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:3px; text-transform:uppercase; color:var(--th-ink,#5b3a8a); margin-bottom:8px; }
.vrx .vrx-banner .vb-name { position:relative; z-index:2; font-family:'Playfair Display', Georgia, serif; font-weight:800; font-size:28px; line-height:1.1; color:#13132b; margin:0; }
.vrx .vrx-banner .vb-pill {
position:relative; z-index:2; display:inline-flex; align-items:center; gap:8px; margin-top:14px;
font-family:ui-monospace,Menlo,monospace; font-size:11px; font-weight:700; letter-spacing:2px; text-transform:uppercase;
color:#fff; background:var(--vc); padding:7px 12px;
}
.vrx .vrx-claim {
margin:0 0 20px; padding:16px 18px; background:#f8fafc; border-left:3px solid var(--vc);
font-family:'Playfair Display', Georgia, serif; font-style:italic; font-size:19px; line-height:1.4; color:var(--navy);
}
.vrx .vrx-meter-row { display:flex; align-items:center; gap:16px; margin:0 0 22px; }
.vrx .vrx-meter { flex:1; height:9px; background:#eef1f5; overflow:hidden; }
.vrx .vrx-meter > i { display:block; height:100%; background:var(--vc); width:0; transition:width 1s var(--ease-out); }
.vrx .vrx-meter-num { font-family:'Playfair Display', serif; font-weight:800; font-size:22px; color:var(--navy); font-variant-numeric:tabular-nums; }
.vrx .vrx-meter-lbl { font-family:ui-monospace,Menlo,monospace; font-size:10px; letter-spacing:1.6px; text-transform:uppercase; color:#9ca3af; }
.vrx h4 { font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:2px; text-transform:uppercase; color:#9ca3af; margin:0 0 12px; }
.vrx .vrx-checks { list-style:none; margin:0 0 22px; padding:0; }
.vrx .vrx-checks li { display:flex; gap:12px; align-items:flex-start; padding:11px 0; border-bottom:1px solid var(--line); font-size:14.5px; line-height:1.55; color:#374151; }
.vrx .vrx-checks li:last-child { border-bottom:0; }
.vrx .vrx-checks li .ic { flex:none; width:20px; height:20px; border-radius:50%; display:flex; align-items:center; justify-content:center; color:#fff; font-size:12px; font-weight:700; margin-top:1px; }
.vrx .vrx-checks li .ic { background:var(--vc); }
.vrx .vrx-rule { font-size:13px; line-height:1.6; background:#fef9c3; border:1px solid #fde68a; color:#713f12; padding:13px 15px; }
.vrx .vrx-rule strong { display:block; margin-bottom:4px; }
.vrx .vrx-disc { margin-top:18px; font-size:11.5px; color:#9ca3af; border-top:1px solid var(--line); padding-top:13px; }
/* ═══════════════════════════════════════════════════════════
IO1 — Video deepfake detection (result)
═══════════════════════════════════════════════════════════ */
.io1-hero {
display:grid; grid-template-columns:1fr auto; gap:32px; align-items:center;
border:1px solid var(--line); border-left:6px solid var(--io1-bd,var(--navy));
background:#fff; padding:28px 32px; margin-bottom:26px;
}
@media (max-width:760px){ .io1-hero{ grid-template-columns:1fr; } }
.io1-hero[data-v="real"] { --io1-bd:#16a34a; --io1-c:#15803d; }
.io1-hero[data-v="fake"] { --io1-bd:#dc2626; --io1-c:#b91c1c; }
.io1-hero .h-kicker {
display:flex; align-items:center; gap:11px;
font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:1.8px; text-transform:uppercase;
color:#9ca3af; margin-bottom:13px;
}
.io1-hero .h-kicker .status-ico { width:30px; height:30px; }
.io1-hero .h-verdict { font-family:'Playfair Display',Georgia,serif; font-weight:800; font-size:40px; line-height:1.05; color:var(--io1-c,var(--navy)); margin-bottom:10px; }
.io1-hero .h-sub { font-size:15px; line-height:1.62; color:#4b5563; max-width:540px; }
.io1-hero .h-meta { display:flex; gap:26px; margin-top:18px; flex-wrap:wrap; }
.io1-hero .h-meta > div { display:flex; flex-direction:column; }
.io1-hero .h-meta .k { font-family:ui-monospace,Menlo,monospace; font-size:10px; letter-spacing:1.4px; text-transform:uppercase; color:#9ca3af; }
.io1-hero .h-meta .v { font-weight:700; color:var(--ink); margin-top:3px; }
.io1-gauge { position:relative; width:178px; height:178px; flex:none; }
.io1-gauge svg { width:100%; height:100%; transform:rotate(-90deg); }
.io1-gauge .g-bg { fill:none; stroke:#eef1f5; stroke-width:14; }
.io1-gauge .g-arc { fill:none; stroke:var(--io1-bd,var(--navy)); stroke-width:14; stroke-linecap:round; stroke-dasharray:0 999; transition:stroke-dasharray 1.1s var(--ease-out); }
.io1-gauge .g-center { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; }
.io1-gauge .g-num { font-family:'Playfair Display',serif; font-weight:800; font-size:36px; color:var(--navy); font-variant-numeric:tabular-nums; }
.io1-gauge .g-lbl { font-family:ui-monospace,Menlo,monospace; font-size:9.5px; letter-spacing:1.4px; text-transform:uppercase; color:#9ca3af; margin-top:5px; text-align:center; }
.io1-face-wrap { display:flex; align-items:flex-start; gap:18px; flex-wrap:wrap; }
.io1-face-wrap img { width:148px; height:148px; object-fit:cover; border:1px solid var(--line); background:#0b1020; }
.io1-face-wrap .fw-txt { flex:1; min-width:200px; font-size:13.5px; line-height:1.6; color:#4b5563; }
.io1-noface { background:#fffbeb; border:1px solid #fde68a; color:#92400e; font-size:13.5px; line-height:1.55; padding:12px 15px; }
.io1-heat-grid { display:grid; grid-template-columns:1fr 1fr; gap:18px; }
@media (max-width:640px){ .io1-heat-grid{ grid-template-columns:1fr; } }
.io1-heat { border:1px solid #1a2238; background:#0b1020; padding:12px; }
.io1-heat img { width:100%; display:block; cursor:zoom-in; }
.io1-heat .cap { color:#9aa3b2; font-size:11px; font-family:ui-monospace,Menlo,monospace; letter-spacing:1px; text-transform:uppercase; margin-top:9px; }
.io1-explain { font-family:'Playfair Display',Georgia,serif; font-size:18px; line-height:1.66; color:var(--ink); }
.io1-zone-tags { display:flex; gap:8px; flex-wrap:wrap; margin-top:14px; }
.io1-zone-tags .zt { font-family:ui-monospace,Menlo,monospace; font-size:11px; letter-spacing:.4px; padding:5px 10px; background:#f1f5f9; color:#475569; }
.io1-zone-tags .zt.hot { background:#fee2e2; color:#991b1b; }
/* ════════════════════════════════════════════════════════════════════
CREATIVE DROP ZONES — unified, soulful "deposit your file here" area.
Overrides the earlier .coh-drop / .desk-drop / .io2-drop / .io4-drop
definitions (same specificity → later wins). Themed by --mc (set on
<body> per ?m=).
════════════════════════════════════════════════════════════════════ */
.coh-drop, .desk-drop, .io2-drop, .io4-drop {
--dz-c: var(--mc, var(--navy));
position:relative; isolation:isolate; overflow:hidden;
display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
cursor:pointer; padding:52px 30px 46px; border:0; border-radius:18px;
background:
radial-gradient(120% 80% at 50% -20%, color-mix(in srgb, var(--dz-c) 17%, transparent), transparent 60%),
radial-gradient(90% 70% at 50% 122%, color-mix(in srgb, var(--dz-c) 10%, transparent), transparent 55%),
linear-gradient(180deg, #ffffff 0%, #f2f4fb 100%);
box-shadow:0 1px 2px rgba(15,23,42,.04), inset 0 1px 0 rgba(255,255,255,.75);
transition:transform .3s cubic-bezier(.16,1,.3,1), box-shadow .3s, background .3s;
}
/* dashed frame (animatable, behind content) */
.coh-drop::before, .desk-drop::before, .io2-drop::before, .io4-drop::before {
content:""; position:absolute; inset:7px; border-radius:11px; z-index:-1; pointer-events:none;
border:2px dashed color-mix(in srgb, var(--dz-c) 26%, var(--line));
transition:border-color .3s, inset .3s, opacity .3s;
}
/* faint dot-grid texture, masked to the centre */
.coh-drop::after, .desk-drop::after, .io2-drop::after, .io4-drop::after {
content:""; position:absolute; inset:0; z-index:-2; pointer-events:none; opacity:.55; transition:opacity .3s;
background-image:radial-gradient(circle, color-mix(in srgb, var(--dz-c) 16%, transparent) 1px, transparent 1.5px);
background-size:22px 22px;
-webkit-mask-image:radial-gradient(75% 80% at 50% 38%, #000, transparent 78%);
mask-image:radial-gradient(75% 80% at 50% 38%, #000, transparent 78%);
}
.coh-drop:hover, .desk-drop:hover, .io2-drop:hover, .io4-drop:hover {
transform:translateY(-2px);
box-shadow:0 24px 46px -22px color-mix(in srgb, var(--dz-c) 42%, transparent);
}
.coh-drop:focus-visible, .desk-drop:focus-visible, .io2-drop:focus-visible, .io4-drop:focus-visible {
outline:none; transform:translateY(-2px);
box-shadow:0 0 0 3px color-mix(in srgb, var(--dz-c) 35%, transparent), 0 24px 46px -22px color-mix(in srgb, var(--dz-c) 42%, transparent);
}
.coh-drop:hover::before, .desk-drop:hover::before, .io2-drop:hover::before, .io4-drop:hover::before,
.coh-drop:focus-visible::before, .desk-drop:focus-visible::before, .io2-drop:focus-visible::before, .io4-drop:focus-visible::before { border-color:color-mix(in srgb, var(--dz-c) 52%, transparent); }
.coh-drop:hover::after, .desk-drop:hover::after, .io2-drop:hover::after, .io4-drop:hover::after { opacity:.9; }
/* DRAG-OVER (.hover added by JS) — light up + marching ants */
.coh-drop.hover, .desk-drop.hover, .io2-drop.hover, .io4-drop.hover {
transform:scale(1.012);
background:
radial-gradient(130% 120% at 50% -10%, color-mix(in srgb, var(--dz-c) 20%, transparent), transparent 62%),
linear-gradient(180deg, color-mix(in srgb, var(--dz-c) 7%, #fff), #f3f6fc);
box-shadow:0 0 0 4px color-mix(in srgb, var(--dz-c) 18%, transparent), 0 26px 52px -22px color-mix(in srgb, var(--dz-c) 48%, transparent);
}
.coh-drop.hover::before, .desk-drop.hover::before, .io2-drop.hover::before, .io4-drop.hover::before {
inset:9px; border:0; border-radius:10px;
background-image:
linear-gradient(90deg, var(--dz-c) 50%, transparent 50%),
linear-gradient(90deg, var(--dz-c) 50%, transparent 50%),
linear-gradient(0deg, var(--dz-c) 50%, transparent 50%),
linear-gradient(0deg, var(--dz-c) 50%, transparent 50%);
background-repeat:repeat-x, repeat-x, repeat-y, repeat-y;
background-size:14px 2px, 14px 2px, 2px 14px, 2px 14px;
background-position:0 0, 0 100%, 0 0, 100% 0;
animation:dz-march .7s infinite linear;
}
@keyframes dz-march { to { background-position:14px 0, -14px 100%, 0 -14px, 100% 14px; } }
.coh-drop.hover::after, .desk-drop.hover::after, .io2-drop.hover::after, .io4-drop.hover::after { opacity:1; }
/* the icon containers — give them a glowing breathing ring */
.drop-icon-ring, .desk-drop-icon, .io2-drop-circle, .io4-drop-cross {
position:relative; width:74px; height:74px; margin:0 auto 18px;
display:flex; align-items:center; justify-content:center; border-radius:22px;
color:var(--dz-c); font-size:0;
background:linear-gradient(150deg, color-mix(in srgb, var(--dz-c) 22%, #fff), color-mix(in srgb, var(--dz-c) 7%, #fff));
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--dz-c) 28%, transparent),
inset 0 1px 0 rgba(255,255,255,.7),
0 12px 26px -12px color-mix(in srgb, var(--dz-c) 55%, transparent);
transition:transform .3s cubic-bezier(.16,1,.3,1), background .3s, box-shadow .3s;
}
.drop-icon-ring::before, .desk-drop-icon::before, .io2-drop-circle::before, .io4-drop-cross::before {
content:""; position:absolute; inset:-10px; border-radius:30px; z-index:-1;
border:1.5px solid color-mix(in srgb, var(--dz-c) 32%, transparent);
animation:dz-breathe 2.6s ease-in-out infinite;
}
@keyframes dz-breathe {
0%,100% { transform:scale(1); opacity:.7; }
50% { transform:scale(1.12); opacity:0; }
}
.coh-drop:hover .drop-icon-ring, .io2-drop:hover .io2-drop-circle, .io4-drop:hover .io4-drop-cross, .desk-drop:hover .desk-drop-icon,
.coh-drop.hover .drop-icon-ring, .io2-drop.hover .io2-drop-circle, .io4-drop.hover .io4-drop-cross, .desk-drop.hover .desk-drop-icon {
transform:translateY(-2px) scale(1.06);
background:color-mix(in srgb, var(--dz-c) 20%, #fff);
}
.drop-icon-ring .icon, .desk-drop-icon .icon, .io2-drop-circle .icon { width:32px !important; height:32px !important; font-size:32px; }
.drop-icon-ring .icon svg, .desk-drop-icon .icon svg, .io2-drop-circle .icon svg { width:32px; height:32px; stroke:var(--dz-c); stroke-width:1.6; }
/* io4 uses a literal "+" — keep it but make it a proper glyph */
.io4-drop-cross { font-size:36px; font-weight:300; line-height:0; }
/* titles / subs / hints */
.drop-title, .desk-drop-title, .io2-drop-title, .io4-drop-title {
font-family:'Playfair Display',serif; font-size:19px; font-weight:700; color:var(--ink); margin:0 0 6px; line-height:1.2;
}
.drop-sub, .desk-drop-sub, .io2-drop-sub, .io4-drop-sub {
font-size:13px; color:var(--ink-soft); line-height:1.5; max-width:38ch; margin:0 auto;
}
.drop-hint, .io4-drop-formats, .desk-drop-formats {
margin-top:14px; font-size:11px; font-weight:600; letter-spacing:.4px; text-transform:uppercase;
color:color-mix(in srgb, var(--dz-c) 70%, var(--ink-faint));
display:inline-flex; align-items:center; gap:7px;
padding:5px 11px; border-radius:9999px;
background:color-mix(in srgb, var(--dz-c) 9%, #fff);
border:1px solid color-mix(in srgb, var(--dz-c) 18%, transparent);
}
.drop-hint kbd {
font:inherit; background:color-mix(in srgb, var(--dz-c) 16%, #fff); border:1px solid color-mix(in srgb, var(--dz-c) 25%, transparent);
border-radius:4px; padding:1px 5px; font-size:10px;
}
/* FILE LOADED state — clean solid card, accent border, left aligned */
.coh-drop.has-file, .desk-drop.has-file, .io2-drop.has-file, .io4-drop.has-file {
padding:18px 22px; text-align:left; align-items:stretch; justify-content:flex-start;
background:#fff;
box-shadow:0 1px 2px rgba(15,23,42,.05), inset 0 0 0 1.5px color-mix(in srgb, var(--dz-c) 45%, var(--line));
border-radius:14px;
}
.coh-drop.has-file::before, .desk-drop.has-file::before, .io2-drop.has-file::before, .io4-drop.has-file::before { display:none; }
.coh-drop.has-file::after, .desk-drop.has-file::after, .io2-drop.has-file::after, .io4-drop.has-file::after { display:none; }
.coh-drop.has-file .drop-icon-ring::before, .io2-drop.has-file .io2-drop-circle::before,
.io4-drop.has-file .io4-drop-cross::before, .desk-drop.has-file .desk-drop-icon::before { animation:none; opacity:0; }
@media (max-width: 600px) {
.coh-drop, .desk-drop, .io2-drop, .io4-drop { padding:34px 18px 32px; }
.drop-icon-ring, .desk-drop-icon, .io2-drop-circle, .io4-drop-cross { width:54px; height:54px; }
}
@media (prefers-reduced-motion: reduce) {
.drop-icon-ring::before, .desk-drop-icon::before, .io2-drop-circle::before, .io4-drop-cross::before { animation:none; }
.coh-drop.hover::before, .desk-drop.hover::before, .io2-drop.hover::before, .io4-drop.hover::before { animation:none; }
.coh-drop, .desk-drop, .io2-drop, .io4-drop, .drop-icon-ring, .desk-drop-icon, .io2-drop-circle, .io4-drop-cross { transition:none; }
}
/* ════════════════════════════════════════════════════════════════════
LUXE REPORT OVERHAUL — applies inside .result-modal (so it only
affects the popup report, not any in-page residue). Themed by
--mc (module colour) and --io1-bd (verdict colour, set on .io1-hero).
════════════════════════════════════════════════════════════════════ */
.result-modal .coh-results { display:flex; flex-direction:column; gap:22px; }
/* ── Verdict hero (.io1-hero) — premium "cover" card ─────────────── */
.result-modal .io1-hero {
position:relative; overflow:hidden;
grid-template-columns:1fr auto; gap:42px; align-items:center;
border:1px solid var(--line); border-left:6px solid var(--io1-bd, var(--navy));
border-radius:18px; padding:36px 40px;
background:
radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--io1-bd, var(--navy)) 9%, transparent), transparent 55%),
linear-gradient(180deg, #ffffff 0%, #fafbfd 100%);
box-shadow:0 1px 2px rgba(15,23,42,.05), 0 24px 50px -28px color-mix(in srgb, var(--io1-bd, var(--navy)) 30%, transparent);
}
.result-modal .io1-hero::before {
content:""; position:absolute; right:-40px; top:-40px; width:300px; height:300px; border-radius:50%; pointer-events:none;
background:radial-gradient(circle, color-mix(in srgb, var(--io1-bd, var(--navy)) 14%, transparent), transparent 65%);
z-index:0;
}
.result-modal .io1-hero > * { position:relative; z-index:1; }
.result-modal .io1-hero .h-kicker {
font-family:'Inter', sans-serif; font-size:10.5px; letter-spacing:1.6px; text-transform:uppercase;
color:var(--ink-faint); margin-bottom:18px;
display:inline-flex; align-items:center; gap:10px;
}
.result-modal .io1-hero .h-kicker .status-ico {
width:34px; height:34px; border-radius:50%;
background:color-mix(in srgb, var(--io1-bd, var(--navy)) 14%, #fff);
color:var(--io1-bd, var(--navy));
display:inline-flex; align-items:center; justify-content:center;
}
.result-modal .io1-hero .h-kicker .status-ico svg { width:16px; height:16px; }
.result-modal .io1-hero .h-verdict {
font-family:'Playfair Display',Georgia,serif; font-weight:800;
font-size:clamp(34px, 4.2vw, 50px); line-height:1.04;
color:var(--io1-c, var(--navy)); margin:0 0 14px; letter-spacing:-0.01em;
}
.result-modal .io1-hero .h-sub {
font-size:15.5px; line-height:1.65; color:var(--ink-soft); max-width:54ch; margin:0;
}
.result-modal .io1-hero .h-meta {
margin-top:24px; padding-top:20px; border-top:1px solid var(--line-soft);
gap:0; display:flex; flex-wrap:wrap;
}
.result-modal .io1-hero .h-meta > div { padding:0 26px 0 0; margin-right:26px; border-right:1px solid var(--line-soft); }
.result-modal .io1-hero .h-meta > div:last-child { border-right:0; margin-right:0; padding-right:0; }
.result-modal .io1-hero .h-meta .k {
font-family:'Inter', sans-serif; font-size:10px; letter-spacing:1.2px; text-transform:uppercase;
color:var(--ink-faint); font-weight:700;
}
.result-modal .io1-hero .h-meta .v {
font-family:'Playfair Display',serif; font-size:20px; font-weight:800;
color:var(--navy); margin-top:4px; font-variant-numeric:tabular-nums; letter-spacing:-0.01em;
}
/* ── Confidence gauge — bigger, smoother ──────────────────────────── */
.result-modal .io1-gauge { width:210px; height:210px; }
.result-modal .io1-gauge .g-bg { stroke:#eef1f5; stroke-width:11; }
.result-modal .io1-gauge .g-arc {
stroke:var(--io1-bd, var(--navy)); stroke-width:11; stroke-linecap:round;
filter:drop-shadow(0 4px 12px color-mix(in srgb, var(--io1-bd, var(--navy)) 40%, transparent));
}
.result-modal .io1-gauge .g-num {
font-family:'Playfair Display',serif; font-size:46px; font-weight:800;
color:var(--io1-c, var(--navy)); letter-spacing:-0.02em;
}
.result-modal .io1-gauge .g-lbl {
font-family:'Inter', sans-serif; font-size:9px; letter-spacing:1.6px; text-transform:uppercase;
color:var(--ink-faint); margin-top:8px; font-weight:700;
}
/* ── Section cards (.coh-card) — premium numbered chapters ────────── */
.result-modal .coh-card {
position:relative;
padding:34px 36px 32px;
border:1px solid var(--line-soft); border-radius:16px;
background:linear-gradient(180deg, #ffffff 0%, #fcfdff 100%);
box-shadow:0 1px 2px rgba(15,23,42,.04), 0 14px 32px -22px rgba(15,23,42,.16);
transition:box-shadow .3s var(--ease-out), transform .3s var(--ease-out);
}
.result-modal .coh-card + .coh-card { margin-top:0; } /* gap handled by .coh-results */
.result-modal .coh-card:hover {
box-shadow:0 1px 2px rgba(15,23,42,.05), 0 22px 48px -22px color-mix(in srgb, var(--mc, var(--navy)) 28%, rgba(15,23,42,.16));
transform:translateY(-1px);
}
.result-modal .coh-card-head { margin-bottom:8px; align-items:center; }
.result-modal .coh-card-head-left { gap:18px; align-items:center; }
.result-modal .coh-card-num {
flex:0 0 auto; width:38px; height:38px; min-width:0; padding:0;
border-radius:50%;
background:color-mix(in srgb, var(--mc, var(--navy)) 12%, #fff);
color:var(--mc, var(--navy));
font-family:'Playfair Display',serif; font-style:normal; font-weight:800; font-size:15px;
letter-spacing:0;
display:inline-flex; align-items:center; justify-content:center;
border:1px solid color-mix(in srgb, var(--mc, var(--navy)) 22%, transparent);
}
.result-modal .coh-card-head h3 {
font-family:'Playfair Display',serif; font-weight:800;
font-size:clamp(22px, 2.4vw, 28px); letter-spacing:-0.012em;
color:var(--navy); margin:0; line-height:1.15;
}
.result-modal .coh-card-sub {
font-size:14px; color:var(--ink-soft); line-height:1.6;
margin:6px 0 22px 56px; max-width:68ch;
}
/* ── Face portrait — framed, glowing ──────────────────────────────── */
.result-modal .io1-face-wrap { gap:24px; align-items:flex-start; margin-left:56px; }
.result-modal .io1-face-wrap img {
width:172px; height:172px; border-radius:14px; border:0;
background:#0b1020; object-fit:cover;
box-shadow:0 0 0 1px color-mix(in srgb, var(--io1-bd, var(--navy)) 30%, transparent),
0 20px 40px -18px color-mix(in srgb, var(--io1-bd, var(--navy)) 50%, transparent),
0 6px 14px -8px rgba(15,23,42,.18);
}
.result-modal .io1-face-wrap .fw-txt {
flex:1; min-width:220px; font-size:14.5px; line-height:1.7; color:var(--ink-soft);
padding-top:6px;
}
.result-modal .io1-noface {
margin-left:56px;
background:linear-gradient(135deg, #fffbeb, #fef3c7);
border:1px solid #fde68a; color:#92400e;
font-size:14px; line-height:1.6; padding:16px 18px; border-radius:12px;
}
/* ── Heatmap evidence cards ───────────────────────────────────────── */
.result-modal .io1-heat-grid { margin-left:56px; gap:20px; }
.result-modal .io1-heat {
border:0; padding:0; border-radius:14px; overflow:hidden;
background:linear-gradient(160deg, #0c1530, #050a1a);
box-shadow:0 18px 38px -22px rgba(3,12,32,0.6), 0 0 0 1px rgba(255,255,255,0.04) inset;
}
.result-modal .io1-heat img { border-radius:0; }
.result-modal .io1-heat .cap {
padding:11px 14px 13px; margin:0;
font-family:'Inter', sans-serif; font-size:10.5px; font-weight:700; letter-spacing:1.2px;
color:rgba(255,255,255,0.65); text-transform:uppercase;
border-top:1px solid rgba(255,255,255,0.06);
}
/* ── Plain-language explanation — editorial pull-quote ────────────── */
.result-modal .io1-explain {
position:relative;
margin-left:56px;
padding:0 0 0 24px;
border-left:3px solid color-mix(in srgb, var(--mc, var(--navy)) 50%, transparent);
font-family:'Playfair Display',Georgia,serif; font-size:19px; line-height:1.7;
color:var(--ink); font-weight:500;
}
.result-modal .io1-explain::first-letter {
font-weight:800; font-size:1.2em;
color:var(--mc, var(--navy));
}
/* ── Zone tags — pill chips, module-tinted, "hot" zones flagged ──── */
.result-modal .io1-zone-tags { margin-left:56px; gap:9px; margin-top:18px; }
.result-modal .io1-zone-tags .zt {
font-family:'Inter', sans-serif; font-size:11px; font-weight:700; letter-spacing:0.4px;
padding:6px 12px; border-radius:9999px;
background:color-mix(in srgb, var(--mc, var(--navy)) 8%, #fff);
color:color-mix(in srgb, var(--mc, var(--navy)) 75%, var(--ink));
border:1px solid color-mix(in srgb, var(--mc, var(--navy)) 18%, transparent);
}
.result-modal .io1-zone-tags .zt.hot {
background:color-mix(in srgb, var(--red) 12%, #fff);
color:#b91c1c;
border-color:color-mix(in srgb, var(--red) 30%, transparent);
}
@media (max-width: 760px) {
.result-modal .io1-hero { padding:26px 22px; gap:24px; }
.result-modal .io1-hero .h-meta > div { padding-right:18px; margin-right:18px; }
.result-modal .io1-gauge { width:172px; height:172px; }
.result-modal .io1-gauge .g-num { font-size:36px; }
.result-modal .coh-card { padding:24px 22px; }
.result-modal .coh-card-sub,
.result-modal .io1-face-wrap,
.result-modal .io1-noface,
.result-modal .io1-heat-grid,
.result-modal .io1-explain,
.result-modal .io1-zone-tags { margin-left:0; }
.result-modal .io1-face-wrap img { width:140px; height:140px; }
}
/* ── Report hero: analysed media in a refined navy frame, sealed by a verdict ── */
.result-modal .rm-input-hero {
position:relative; margin:0 0 24px; border-radius:16px; overflow:hidden; isolation:isolate;
background:
radial-gradient(130% 95% at 50% 0%, #163465 0%, transparent 62%),
linear-gradient(180deg,#0c1f44 0%, #081431 100%);
box-shadow:0 1px 2px rgba(15,23,42,.06), inset 0 0 0 1px rgba(255,255,255,.06), 0 18px 42px -22px rgba(8,16,40,.5);
}
.result-modal .rm-input-hero::before { /* hairline gold inner frame */
content:""; position:absolute; inset:10px; border-radius:9px; pointer-events:none; z-index:5;
border:1px solid rgba(200,162,74,.28);
}
.result-modal .rm-input-hero .rm-input-media {
display:flex; align-items:center; justify-content:center; min-height:236px; padding:34px 32px 40px;
}
.result-modal .rm-input-frame { /* wraps the media so the seal can sit on it */
position:relative; display:inline-block; line-height:0; max-width:100%;
border-radius:5px; background:#fff; padding:7px; /* thin white "mat" */
box-shadow:0 26px 54px -18px rgba(0,0,0,.62), 0 0 0 1px rgba(0,0,0,.06), inset 0 0 0 1px rgba(0,0,0,.04);
}
.result-modal .rm-input-frame img,
.result-modal .rm-input-frame video {
max-width:100%; max-height:330px; width:auto; height:auto; object-fit:contain; display:block; border-radius:2px;
}
.result-modal .rm-input-hero .rm-input-cap {
position:absolute; left:0; right:0; bottom:0; z-index:4;
display:flex; align-items:center; gap:9px; padding:24px 18px 13px;
font-family:ui-monospace,Menlo,monospace; font-size:9.5px; letter-spacing:1.2px; text-transform:uppercase;
color:rgba(255,255,255,.6);
background:linear-gradient(0deg, rgba(6,13,32,.96) 0%, rgba(6,13,32,.5) 55%, transparent 100%);
}
.result-modal .rm-input-cap::before { /* thin gold rule above the caption */
content:""; position:absolute; left:18px; right:18px; top:14px; height:1px;
background:linear-gradient(90deg, transparent, rgba(200,162,74,.55), transparent);
}
.result-modal .rm-input-cap .ic { width:12px; height:12px; flex:0 0 auto; opacity:.85; color:rgba(200,162,74,.9); }
.result-modal .rm-input-cap .ic svg { width:100%; height:100%; stroke:currentColor; }
.result-modal .rm-input-cap .nm { color:#fff; text-transform:none; letter-spacing:.2px; font-weight:600; max-width:42ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* the verdict — an embossed certification seal pressed onto the photo (top-right) */
.result-modal .rm-input-seal {
position:absolute; top:12px; right:12px; z-index:6;
width:114px; height:114px;
transform:rotate(7deg); transform-origin:center;
pointer-events:none; opacity:.95; mix-blend-mode:multiply;
filter:drop-shadow(0 1px 0 rgba(255,255,255,.5)) drop-shadow(0 5px 11px rgba(0,0,0,.16));
}
.result-modal .rm-input-seal svg { width:100%; height:100%; display:block; }
@media (max-width: 700px) {
.result-modal .rm-input-seal { width:90px; height:90px; top:9px; right:9px; }
.result-modal .rm-input-hero .rm-input-media { min-height:170px; padding:22px 16px 30px; }
.result-modal .rm-input-frame img, .result-modal .rm-input-frame video { max-height:240px; }
}
/* keep the giant page watermark out of normal flow (it was pushing content down) */
.result-modal .result-modal__body > .rm-watermark { position:absolute; z-index:0; }
@media print {
.result-modal .rm-input-hero { background:#0c1f44; box-shadow:none; }
.result-modal .rm-input-seal { mix-blend-mode:normal; opacity:1; }
}
/* ════════════════════════════════════════════════════════════════════
LUXE PROCESS CARD — "model is working" panel, on the Verify charter
(navy structure + yellow accent). Not module-coloured.
════════════════════════════════════════════════════════════════════ */
.process-card {
position:relative; overflow:hidden;
border:1px solid color-mix(in srgb, var(--navy) 14%, var(--line)); border-radius:16px;
padding:26px 30px 24px;
background:
radial-gradient(130% 100% at 100% 0%, rgba(5,41,98,.05), transparent 56%),
linear-gradient(180deg, #ffffff 0%, #fafbfd 100%);
box-shadow:0 1px 2px rgba(15,23,42,.05), 0 22px 50px -26px rgba(5,41,98,.28);
}
.process-card::before { /* yellow brand accent bar on the left */
content:""; position:absolute; left:0; top:0; bottom:0; width:4px;
background:linear-gradient(180deg, var(--yellow), color-mix(in srgb, var(--yellow) 55%, #fff));
}
.process-card::after { /* navy scanning line sweeping down while analysing */
content:""; position:absolute; left:0; right:0; top:0; height:2px; pointer-events:none;
background:linear-gradient(90deg, transparent, color-mix(in srgb, var(--navy) 75%, #4f7fd6), transparent);
box-shadow:0 0 18px 2px rgba(5,41,98,.28);
opacity:.5; animation:pc-scan 2.8s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes pc-scan { 0% { top:4%; } 50% { top:96%; } 100% { top:4%; } }
.process-card .process-head { align-items:center; margin-bottom:20px; }
.process-card .process-head .ph-title {
font-family:'Playfair Display',serif; font-size:21px; line-height:1.15;
display:inline-flex; align-items:center; gap:12px; color:var(--navy);
}
.process-card .process-head .ph-title .icon-svg, .process-card .process-head .ph-title svg {
width:34px !important; height:34px !important; padding:7px; border-radius:10px;
background:rgba(5,41,98,.1); color:var(--navy);
animation:pc-spin 3.2s linear infinite;
}
@keyframes pc-spin { to { transform:rotate(360deg); } }
.process-card .process-head .ph-status {
font-family:'Inter',sans-serif; font-size:10.5px; font-weight:800; letter-spacing:1px; text-transform:uppercase;
color:var(--navy); background:var(--yellow); padding:5px 11px; border-radius:2px;
}
.process-card .process-track {
height:7px; border-radius:9999px; background:#eef1f5; overflow:hidden; margin-bottom:24px;
box-shadow:inset 0 1px 2px rgba(15,23,42,.06);
}
.process-card .process-track > div {
background:linear-gradient(90deg, #052962 0%, #2456b3 50%, #1e4faf 100%);
background-size:200% 100%; border-radius:9999px; animation:pc-shimmer 1.8s linear infinite;
}
@keyframes pc-shimmer { 0% { background-position:200% 0; } 100% { background-position:0 0; } }
.process-card .pstep { padding:13px 4px; border-bottom-color:var(--line-soft); }
.process-card .pstep .ps-icon {
width:34px; height:34px; border-radius:11px;
background:#f4f6f9; color:var(--ink-faint);
}
.process-card .pstep .ps-icon .icon-svg, .process-card .pstep .ps-icon svg { width:15px; height:15px; }
.process-card .pstep[data-state="active"] .ps-icon {
background:var(--navy); color:#fff;
box-shadow:0 0 0 0 rgba(5,41,98,.4);
animation:pc-pulse 1.4s ease-out infinite;
}
@keyframes pc-pulse {
0% { box-shadow:0 0 0 0 rgba(5,41,98,.4); }
70% { box-shadow:0 0 0 10px rgba(5,41,98,0); }
100% { box-shadow:0 0 0 0 rgba(5,41,98,0); }
}
.process-card .pstep[data-state="done"] .ps-icon { background:rgba(22,163,74,.14); color:#16a34a; }
.process-card .pstep .ps-label { font-size:14.5px; font-weight:600; color:var(--ink); }
.process-card .pstep[data-state="active"] .ps-label { color:var(--navy); }
.process-card .pstep .ps-time { font-family:'Inter',sans-serif; font-size:11px; letter-spacing:.6px; text-transform:uppercase; }
.process-card .pstep[data-state="active"] .ps-time { color:var(--navy); font-weight:800; }
@media (prefers-reduced-motion: reduce) {
.process-card::after, .process-card .process-head .ph-title svg, .process-card .process-track > div,
.process-card .pstep[data-state="active"] .ps-icon, .process-card .pc-elapsed::before { animation:none; }
}
.process-card .process-head { flex-wrap:wrap; }
.process-card .pc-elapsed {
flex-basis:100%; margin-top:9px; padding-top:9px; border-top:1px dashed var(--line-soft);
font-family:'Inter',sans-serif; font-size:11.5px; line-height:1.5; color:var(--ink-faint);
font-variant-numeric:tabular-nums; display:flex; align-items:center; gap:9px;
}
.process-card .pc-elapsed::before {
content:""; width:6px; height:6px; border-radius:50%; background:var(--navy); flex:0 0 auto;
box-shadow:0 0 0 0 rgba(5,41,98,.35); animation:pc-pulse 1.6s ease-out infinite;
}
.process-card .pc-elapsed.warn { color:#92400e; }
.process-card .pc-elapsed.warn::before { background:#f59e0b; box-shadow:0 0 0 0 rgba(245,158,11,.4); }
/* ── Drop zones, second polish pass: bigger, with a "drop here" pulse cue ── */
.coh-drop, .desk-drop, .io2-drop, .io4-drop { padding:54px 30px 50px; }
.coh-drop .drop-icon-ring, .io2-drop .io2-drop-circle, .io4-drop .io4-drop-cross, .desk-drop .desk-drop-icon { width:72px; height:72px; border-radius:20px; }
.coh-drop .drop-title, .desk-drop .desk-drop-title, .io2-drop .io2-drop-title, .io4-drop .io4-drop-title { font-size:21px; }
/* a faint downward arrow cue under the icon, breathing */
.drop-icon-ring::after, .io2-drop-circle::after, .desk-drop-icon::after {
content:"↓"; position:absolute; left:50%; bottom:-26px; transform:translateX(-50%);
font-size:15px; color:color-mix(in srgb, var(--dz-c) 60%, transparent); font-weight:700;
animation:dz-arrow 1.8s ease-in-out infinite;
}
@keyframes dz-arrow { 0%,100% { transform:translateX(-50%) translateY(-2px); opacity:.4; } 50% { transform:translateX(-50%) translateY(3px); opacity:1; } }
.coh-drop.has-file .drop-icon-ring::after, .io2-drop.has-file .io2-drop-circle::after, .desk-drop.has-file .desk-drop-icon::after,
.io4-drop.has-file .io4-drop-cross::after { display:none; }
@media (prefers-reduced-motion: reduce) { .drop-icon-ring::after, .io2-drop-circle::after, .desk-drop-icon::after { animation:none; } }
/* ════════════════════════════════════════════════════════════════════
EXAMPLES GALLERIES — one per module, each with a DIFFERENT layout.
On the Verify charter (navy / yellow / Playfair / Inter).
════════════════════════════════════════════════════════════════════ */
.ex-section { margin:30px 0 8px; }
.ex-head { margin-bottom:18px; }
.ex-head .ex-k {
display:inline-block; font-size:10px; font-weight:800; letter-spacing:1.4px; text-transform:uppercase;
color:var(--navy); background:var(--yellow); padding:5px 11px; border-radius:2px; margin-bottom:11px;
}
.ex-head h3 { font-family:'Playfair Display',serif; font-size:clamp(22px,2.4vw,28px); line-height:1.15; margin:0 0 6px; color:var(--navy); }
.ex-head p { font-size:14px; line-height:1.6; color:var(--ink-soft); margin:0; max-width:64ch; }
.ex-badge {
display:inline-flex; align-items:center; gap:6px;
font-family:'Inter',sans-serif; font-size:10px; font-weight:800; letter-spacing:.7px; text-transform:uppercase;
padding:5px 9px; border-radius:9999px;
}
.ex-badge.bad { background:#fee2e2; color:#b91c1c; }
.ex-badge.warn { background:#ffedd5; color:#9a3412; }
.ex-badge.ok { background:#dcfce7; color:#166534; }
.ex-badge .d { width:6px; height:6px; border-radius:50%; background:currentColor; }
/* ── Layout A — io1: 3D flip cards "can you tell?" ─────────────────── */
.ex-flip { display:grid; grid-template-columns:repeat(auto-fit, minmax(220px,1fr)); gap:18px; }
.ex-flip .fc { perspective:1100px; aspect-ratio:1; cursor:pointer; }
.ex-flip .fc-inner { position:relative; width:100%; height:100%; transition:transform .7s cubic-bezier(.4,0,.2,1); transform-style:preserve-3d; border-radius:16px; }
.ex-flip .fc:hover .fc-inner, .ex-flip .fc:focus-within .fc-inner { transform:rotateY(180deg); }
.ex-flip .fc-face { position:absolute; inset:0; border-radius:16px; overflow:hidden; backface-visibility:hidden; -webkit-backface-visibility:hidden; box-shadow:0 14px 32px -18px rgba(15,23,42,.3), 0 0 0 1px var(--line); }
.ex-flip .fc-front img { width:100%; height:100%; object-fit:cover; display:block; }
.ex-flip .fc-front::after { content:"↻ survol"; position:absolute; right:10px; bottom:10px; font:700 10px/1 'Inter',sans-serif; letter-spacing:.6px; text-transform:uppercase; color:#fff; background:rgba(3,16,40,.55); padding:5px 8px; border-radius:9999px; -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px); }
.ex-flip .fc-back { transform:rotateY(180deg); display:flex; flex-direction:column; align-items:flex-start; justify-content:center; gap:10px; padding:20px; background:linear-gradient(160deg,#fff,#f6f8fc); border:1px solid var(--line); }
.ex-flip .fc-back .v { font-family:'Playfair Display',serif; font-size:19px; font-weight:800; color:var(--navy); line-height:1.15; }
.ex-flip .fc-back .why { font-size:12.5px; line-height:1.5; color:var(--ink-soft); }
.ex-flip .fc-back.is-ai .v { color:#5b21b6; }
.ex-flip .fc-back.is-real .v { color:#15803d; }
/* ── Layout B — io2: persuasion spectrum strip ────────────────────── */
.ex-spectrum { display:grid; grid-template-columns:repeat(4,1fr); gap:14px; }
@media (max-width:780px){ .ex-spectrum { grid-template-columns:repeat(2,1fr); } }
.ex-spectrum .sp { border:1px solid var(--line); border-radius:14px; overflow:hidden; background:#fff; box-shadow:0 8px 22px -16px rgba(15,23,42,.2); }
.ex-spectrum .sp .ph { aspect-ratio:4/5; overflow:hidden; position:relative; }
.ex-spectrum .sp .ph img { width:100%; height:100%; object-fit:cover; display:block; }
.ex-spectrum .sp .ph .ex-badge { position:absolute; top:9px; left:9px; }
.ex-spectrum .sp .cap { padding:12px 13px 14px; }
.ex-spectrum .sp .cap .t { font-family:'Inter',sans-serif; font-size:12.5px; font-weight:700; color:var(--navy); line-height:1.3; }
.ex-spectrum .sp .cap .tags { display:flex; flex-wrap:wrap; gap:5px; margin-top:7px; }
.ex-spectrum .sp .cap .tags span { font-size:10px; font-weight:600; color:var(--ink-soft); background:#f4f6f9; border:1px solid var(--line-soft); padding:3px 7px; border-radius:9999px; }
.ex-meter { margin-top:14px; }
.ex-meter .bar { height:7px; border-radius:9999px; background:linear-gradient(90deg,#dc2626,#f59e0b,#84cc16,#16a34a); }
.ex-meter .lbls { display:flex; justify-content:space-between; margin-top:6px; font:800 10px/1 'Inter',sans-serif; letter-spacing:1px; text-transform:uppercase; color:var(--ink-faint); }
/* ── Layout C — io4: "spot the manipulation" evidence cards ───────── */
.ex-evidence { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px,1fr)); gap:16px; }
.ex-evidence .ev { border:1px solid var(--line); border-radius:16px; overflow:hidden; background:#fff; box-shadow:0 10px 26px -18px rgba(15,23,42,.22); display:flex; flex-direction:column; }
.ex-evidence .ev .ph { position:relative; aspect-ratio:4/3; overflow:hidden; }
.ex-evidence .ev .ph img { width:100%; height:100%; object-fit:cover; display:block; }
.ex-evidence .ev.bad .ph::after { content:""; position:absolute; inset:0; box-shadow:inset 0 0 0 3px #dc2626; }
.ex-evidence .ev .ph .ex-badge { position:absolute; top:10px; left:10px; }
.ex-evidence .ev .body { padding:14px 16px 16px; }
.ex-evidence .ev .body .t { font-family:'Playfair Display',serif; font-size:16px; font-weight:700; color:var(--navy); margin:0 0 5px; }
.ex-evidence .ev .body .why { font-size:12.5px; line-height:1.5; color:var(--ink-soft); }
.ex-evidence .ev.bad { border-color:#fecaca; }
/* ── Layout D — io5: social-post coherence mockups ────────────────── */
.ex-posts { display:grid; grid-template-columns:repeat(auto-fit, minmax(260px,1fr)); gap:18px; }
.ex-posts .po { border:1px solid var(--line); border-radius:16px; overflow:hidden; background:#fff; box-shadow:0 12px 30px -20px rgba(15,23,42,.22); }
.ex-posts .po .po-img { aspect-ratio:16/10; overflow:hidden; }
.ex-posts .po .po-img img { width:100%; height:100%; object-fit:cover; display:block; }
.ex-posts .po .po-cap { padding:13px 15px 11px; font-size:13.5px; line-height:1.5; color:var(--ink); }
.ex-posts .po .po-cap b { color:var(--navy); }
.ex-posts .po .po-verdict { display:flex; align-items:center; gap:9px; padding:11px 15px; font-size:12.5px; font-weight:600; border-top:1px solid var(--line-soft); }
.ex-posts .po .po-verdict.ok { background:linear-gradient(0deg,rgba(22,163,74,.07),transparent); color:#166534; }
.ex-posts .po .po-verdict.bad { background:linear-gradient(0deg,rgba(220,38,38,.07),transparent); color:#b91c1c; }
.ex-posts .po .po-verdict .ico { width:22px; height:22px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:11px; font-weight:800; flex:0 0 auto; }
.ex-posts .po .po-verdict.ok .ico { background:rgba(22,163,74,.16); }
.ex-posts .po .po-verdict.bad .ico { background:rgba(220,38,38,.16); }
.ex-foot { margin-top:14px; font-size:11.5px; color:var(--ink-faint); }
@media (prefers-reduced-motion: reduce) { .ex-flip .fc-inner { transition:none; } }
/* Re-order each module pane so the examples gallery sits ABOVE the analysis:
api-banner → intro strip → examples gallery → (tabs / form / process / result) */
#pane-io1, #pane-io2, #pane-io3, #pane-io4 { display:flex; flex-direction:column; }
#pane-io1 > *, #pane-io2 > *, #pane-io3 > *, #pane-io4 > * { order:3; }
#pane-io1 > .api-banner, #pane-io2 > .api-banner, #pane-io3 > .api-banner, #pane-io4 > .api-banner { order:0; }
#pane-io1 > .coh-intro, #pane-io2 > .coh-intro, #pane-io3 > .coh-intro, #pane-io4 > .coh-intro { order:1; }
#pane-io1 > .ex-section, #pane-io2 > .ex-section, #pane-io3 > .ex-section, #pane-io4 > .ex-section { order:2; margin-top:8px; }
</style>
</head>
<body>
<div id="site-header" data-slim="true"></div>
<!-- ============ MODULE HERO — cinematic, bound by JS to ?m= ============ -->
<header class="mhero" id="m-hero">
<div class="mhero__img"><img id="m-hero-img" src="assets/img/oi1.png?v=2" alt="" /></div>
<div class="mhero__scan" aria-hidden="true"></div>
<span class="mhero__ghost" id="m-hero-ghost" aria-hidden="true">00</span>
<div class="mhero__inner">
<div class="mhero__top">
<div class="mhero__crumb">
<a href="verifier.html">
<svg class="icon-svg" viewBox="0 0 24 24" style="width:13px;height:13px;"><path d="M19 12H5M11 19l-7-7 7-7"/></svg>
Tous les modules
</a>
</div>
<span class="mhero__idx">Module <b id="m-hero-idx">00</b> <i>/ 05</i></span>
</div>
<div class="mhero__main">
<div data-reveal>
<span hidden><span id="m-badge" class="module-badge">Module</span></span>
<span class="mhero__chip"><span class="dot"></span> <span id="m-hero-chip">Module</span></span>
<h1 id="m-title">Module</h1>
<p id="m-desc" class="mhero__lead"></p>
<div class="mhero__actions">
<a href="#m-panes" class="btn-yellow lux-shine">Start an analysis ↓</a>
<a href="methodologie.html" class="btn-outline">How it works</a>
</div>
</div>
<div class="mhero__console" data-reveal aria-hidden="true">
<div class="cc-head">
<span class="cc-title"><span class="cc-live"></span> <span id="m-hero-console-title">Analysis</span></span>
<span class="cc-dots"><i></i><i></i><i></i></span>
</div>
<div class="cc-bar"><i></i></div>
<ul id="m-hero-signals"></ul>
</div>
</div>
</div>
</header>
<div class="mspec"><div class="mspec__inner" id="m-hero-spec"></div></div>
<main class="container-x" style="max-width: 1100px;">
<div id="m-panes"></div>
<!-- =================== IO3 — Real coherence pipeline =================== -->
<section id="pane-io3" class="px-6 py-6" style="display:none;">
<div id="api-status" class="api-banner">Connecting to the service…</div>
<!-- Intro strip -->
<div class="coh-intro">
<div class="coh-intro-text">
<div class="coh-intro-kicker">Image &amp; caption</div>
<h2>Does the caption really match the image?</h2>
<p>Drop an image or a video, add the caption that goes with it: we compare the two and tell you within seconds whether they really tell the same story — along with the areas of the image that mattered for the verdict. Ideal for spotting an image taken out of context or a misleading caption.</p>
</div>
<div class="coh-intro-modules">
<div class="intro-mod"><span class="mono mono-sm clip">·</span><span class="nm">The scene<small>Setting, context, mood</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm sam">·</span><span class="nm">The objects present<small>What can be seen in the image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm whisper">·</span><span class="nm">The soundtrack<small>Spoken words — for videos</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm yolo">·</span><span class="nm">Visible text<small>Text embedded in the image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm ocr">·</span><span class="nm">The match<small>Image and caption compared</small></span><span class="pct"></span></div>
</div>
</div>
<div class="coh-tabs" role="tablist">
<div class="coh-tab active" data-tab="image"><span class="tab-ico"><span class="icon icon-16 icon-stroke" data-icon="image"></span> Analyze an image</span></div>
<div class="coh-tab" data-tab="video"><span class="tab-ico"><span class="icon icon-16 icon-stroke" data-icon="video"></span> Analyze a video</span></div>
</div>
<!-- Image pane -->
<div class="coh-pane active" data-pane="image">
<form id="form-image" class="coh-form" onsubmit="return false;">
<input type="file" id="file-image" accept="image/jpeg,image/png" hidden />
<div>
<div class="field-label"><span class="num">01.</span> Image to analyze</div>
<div id="drop-image" class="coh-drop" tabindex="0" data-input="file-image" data-kind="image">
<div class="drop-icon-ring"><span class="icon icon-28 icon-stroke" data-icon="image"></span></div>
<div class="drop-title">Drag and drop an image</div>
<div class="drop-sub">or click to browse · JPG, PNG · 20 MB max</div>
<div class="drop-hint"><kbd>⌘V</kbd> paste from clipboard</div>
</div>
</div>
<div>
<div class="field-label"><span class="num">02.</span> Caption to verify</div>
<div class="caption-wrap">
<textarea id="text-image" class="coh-textarea" maxlength="500" placeholder="Copy the caption that goes with the image — e.g.: “A man on a bicycle in a city street”"></textarea>
<span class="caption-counter" data-counter-for="text-image">0 / 500</span>
</div>
<div class="caption-suggestions" data-target="text-image">
<span class="sg-label">Examples</span>
<button type="button" class="sg-pill">A bright yellow sun in a blue sky</button>
<button type="button" class="sg-pill">A man on a bicycle in a city street</button>
<button type="button" class="sg-pill">A crowd protesting in the city center</button>
<button type="button" class="sg-pill">A red sports car parked in front of a café</button>
</div>
</div>
<div class="coh-cta">
<button id="btn-image" type="button" class="btn-primary coh-cta-btn">Start the analysis <span class="cta-arrow"></span></button>
<span id="status-image" class="coh-status">Result in a few seconds</span>
</div>
</form>
<div id="process-image"></div>
<div id="result-image" style="margin-top:30px;"></div>
</div>
<!-- Video pane -->
<div class="coh-pane" data-pane="video">
<form id="form-video" class="coh-form" onsubmit="return false;">
<input type="file" id="file-video" accept="video/mp4,video/quicktime" hidden />
<div>
<div class="field-label"><span class="num">01.</span> Video to analyze</div>
<div id="drop-video" class="coh-drop" tabindex="0" data-input="file-video" data-kind="video">
<div class="drop-icon-ring"><span class="icon icon-28 icon-stroke" data-icon="video"></span></div>
<div class="drop-title">Drag and drop a video</div>
<div class="drop-sub">or click to browse · MP4, MOV · 200 MB max</div>
<div class="drop-hint">Both image and soundtrack are analyzed</div>
</div>
</div>
<div>
<div class="field-label"><span class="num">02.</span> Caption to verify</div>
<div class="caption-wrap">
<textarea id="text-video" class="coh-textarea" maxlength="500" placeholder="Copy the caption that goes with the video — e.g.: “A crowd protesting in the city center”"></textarea>
<span class="caption-counter" data-counter-for="text-video">0 / 500</span>
</div>
<div class="caption-suggestions" data-target="text-video">
<span class="sg-label">Examples</span>
<button type="button" class="sg-pill">A crowd protesting in the city center</button>
<button type="button" class="sg-pill">A flooded street, passersby in the water</button>
<button type="button" class="sg-pill">A political official at a press conference</button>
</div>
</div>
<div class="coh-cta">
<button id="btn-video" type="button" class="btn-primary coh-cta-btn">Start the analysis <span class="cta-arrow"></span></button>
<span id="status-video" class="coh-status">Allow about twenty seconds</span>
</div>
</form>
<div id="process-video"></div>
<div id="result-video" style="margin-top:30px;"></div>
</div>
<!-- Examples gallery — caption coherence (social-post mockups) -->
<section class="ex-section">
<div class="ex-head">
<span class="ex-k">When the caption lies</span>
<h3>Do the image and the caption tell the same story?</h3>
<p>Two posts where the caption fits the image, two where it uses it out of context. The module compares the actual content of the image with the text that goes with it.</p>
</div>
<div class="ex-posts">
<div class="po">
<div class="po-img"><img src="assets/img/examples/m-real1.jpg?v=2" alt="" loading="lazy" /></div>
<div class="po-cap"><b>Caption:</b> “The summit under snow, photographed yesterday morning.”</div>
<div class="po-verdict ok"><span class="ico"></span> The image and the caption tell the same story.</div>
</div>
<div class="po">
<div class="po-img"><img src="assets/img/examples/m-real3.jpg?v=2" alt="" loading="lazy" /></div>
<div class="po-cap"><b>Caption:</b> “Portrait taken during last week's interview.”</div>
<div class="po-verdict ok"><span class="ico"></span> Consistent: a portrait, a portrait caption.</div>
</div>
<div class="po">
<div class="po-img"><img src="assets/img/examples/m-real2.jpg?v=2" alt="" loading="lazy" /></div>
<div class="po-cap"><b>Caption:</b> “Riots downtown this afternoon.”</div>
<div class="po-verdict bad"><span class="ico"></span> Inconsistent: the image shows a dog — nothing to do with a riot.</div>
</div>
<div class="po">
<div class="po-img"><img src="assets/img/examples/m-news1.jpg?v=2" alt="" loading="lazy" /></div>
<div class="po-cap"><b>Caption:</b> “Exclusive photo of the scene, taken on site.”</div>
<div class="po-verdict bad"><span class="ico"></span> Misleading caption: it's just a stack of newspapers, not an event scene.</div>
</div>
</div>
<p class="ex-foot">Images: Unsplash. Fictional captions, for illustration only.</p>
</section>
</section>
<!-- =================== IO6 — Cosmetic Ads Fact-Check (Yassmine) =================== -->
<section id="pane-io6" class="px-6 py-6" style="display:none;">
<div id="api-status-io6" class="api-banner desk">Connecting to the service…</div>
<!-- Intro strip -->
<div class="coh-intro">
<div class="coh-intro-text">
<div class="coh-intro-kicker">Advertising &amp; cosmetics</div>
<h2>Do this ad's claims hold up?</h2>
<p>Drop a cosmetics ad: we pull out every claim — about ingredients, effects, labels — and we check whether it is accurate or misleading against the EU rules on cosmetic claims. You get a clear verdict, claim by claim, and an overall reliability score.</p>
</div>
<div class="coh-intro-modules">
<div class="intro-mod"><span class="mono mono-sm whisper">·</span><span class="nm">The soundtrack<small>What is said in the ad</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm yolo">·</span><span class="nm">The visuals<small>Products and scenes shown</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm ocr">·</span><span class="nm">On-screen text<small>Displayed text and fine print</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm clip">·</span><span class="nm">The claims<small>Ingredients, effects, labels advertised</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm sam">·</span><span class="nm">The EU rules<small>Permitted cosmetic claims</small></span><span class="pct"></span></div>
</div>
</div>
<!-- Showcase: campaigns already verified -->
<div id="io6-showcase"></div>
<form id="form-io6" class="io6-input-shell" onsubmit="return false;">
<div class="field-label-desk">
<span class="num">01.</span>
<span>Submission to the Verify newsroom</span>
</div>
<input type="file" id="file-io6" accept="video/mp4,video/quicktime" hidden />
<div class="desk-frame">
<div class="desk-mast">
<div class="desk-mast-title">VERIFY · Advertising &amp; Cosmetics Desk</div>
<div class="desk-mast-meta">
<span>Claim verification</span>
<span class="pipe">·</span>
<span>EU rules</span>
<span class="pipe">·</span>
<span>Case <strong id="desk-dossier">No. 0001</strong></span>
</div>
</div>
<div class="desk-body">
<div class="desk-kicker">Submission · for verification of cosmetic claims</div>
<h3 class="desk-headline">Submit a cosmetics ad for <em>verification</em>.</h3>
<p class="desk-deck">The Verify newsroom checks every claim in the ad against the EU rules on cosmetic claims. Clear verdict: <strong>RELIABLE</strong> or <strong>MISLEADING</strong> — only claims that break the rules are flagged as misleading.</p>
<div id="drop-io6" class="desk-drop" tabindex="0" data-input="file-io6" data-kind="video">
<div class="desk-drop-icon">
<span class="icon icon-22 icon-stroke" data-icon="video"></span>
</div>
<div class="desk-drop-title">Drag and drop the ad video</div>
<div class="desk-drop-sub">or click to browse</div>
<div class="desk-drop-formats">MP4 · MOV · 200 MB max</div>
</div>
</div>
<div class="desk-foot">
<div class="desk-foot-byline">
Verified by <strong>the Verify newsroom</strong> · against EU rules
</div>
<div style="display:flex; gap:18px; align-items:center; flex-wrap:wrap;">
<span id="status-io6" class="desk-status">
<span class="sc-led"></span>
<span class="sc-text">READY</span>
· about 30 s
</span>
<button id="btn-io6" type="button" class="io6-cta-btn">Submit the ad</button>
</div>
</div>
</div>
</form>
<div id="process-io6"></div>
<div id="result-io6" style="margin-top:30px;"></div>
</section>
<!-- =================== IO2 — Manipulation Detection (Malek) =================== -->
<section id="pane-io2" class="px-6 py-6" style="display:none;">
<div id="api-status-io2" class="api-banner desk">Connecting to the service…</div>
<div class="coh-intro">
<div class="coh-intro-text">
<div class="coh-intro-kicker">Visual manipulation</div>
<h2>Is this image trying to manipulate you?</h2>
<p>Drop an image or a video: we spot staging and emotional-persuasion techniques — biased framing, dramatization, false urgency signals, alarmist text — often used in advertising, propaganda and viral content. You get a verdict, the elements spotted, and the areas of the image that mattered.</p>
</div>
<div class="coh-intro-modules">
<div class="intro-mod"><span class="mono mono-sm whisper">·</span><span class="nm">The text<small>Words and phrases present on the image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm clip">·</span><span class="nm">The tone<small>Neutral, biased or alarmist</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm yolo">·</span><span class="nm">The staging<small>Framing and dramatization</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm sam">·</span><span class="nm">Urgency signals<small>Countdowns, alerts, pressuring buttons</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm ocr">·</span><span class="nm">The synthesis<small>Everything is combined for the verdict</small></span><span class="pct"></span></div>
</div>
</div>
<div class="io2-mode-tabs" role="tablist">
<button type="button" class="active" data-io2-mode="image"><span class="mt-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="18" height="17" rx="1.5"/><circle cx="9" cy="9.5" r="1.6"/><path d="M3 17l5-5 4 4 3-3 6 5"/></svg></span>Analyze an image</button>
<button type="button" data-io2-mode="video"><span class="mt-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="14" height="14" rx="1.5"/><path d="M17 9.5l4-2.5v10l-4-2.5z"/></svg></span>Analyze a video</button>
</div>
<form id="form-io2" class="io6-input-shell" onsubmit="return false;">
<div class="field-label-desk">
<span class="num">01.</span>
<span>Image or video to analyze</span>
</div>
<input type="file" id="file-io2" accept="image/*,video/mp4,video/avi,video/quicktime" hidden />
<div id="drop-io2" class="io2-drop" tabindex="0" data-input="file-io2" data-kind="image">
<div class="io2-drop-circle">
<span class="icon icon-22 icon-stroke" data-icon="image"></span>
</div>
<div class="io2-drop-title">Drag and drop an image or a video</div>
<div class="io2-drop-sub">JPG · PNG · WEBP · BMP · MP4 · AVI — for videos, the first frame is analyzed.</div>
</div>
<div style="margin-top:18px; display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap;">
<span id="status-io2" class="desk-status">
<span class="sc-led"></span>
<span class="sc-text">READY</span>
· a few seconds
</span>
<button id="btn-io2" type="button" class="io2-cta">Start the analysis</button>
</div>
</form>
<!-- Examples gallery — persuasion spectrum -->
<section class="ex-section">
<div class="ex-head">
<span class="ex-k">Spotting the staging</span>
<h3>From “designed to make you react” to neutral</h3>
<p>Left to right: from the most visually persuasive to the most neutral. The module scores each of these levers — framing, gaze, dramatization — to place a visual on this scale.</p>
</div>
<div class="ex-spectrum">
<div class="sp">
<div class="ph"><img src="assets/img/examples/m-manip2.jpg?v=2" alt="Propaganda poster" loading="lazy" /><span class="ex-badge bad"><span class="d"></span>Strong persuasion</span></div>
<div class="cap"><div class="t">Recruitment poster (1917)</div><div class="tags"><span>direct gaze</span><span>finger pointing at you</span><span>direct appeal</span></div></div>
</div>
<div class="sp">
<div class="ph"><img src="assets/img/examples/m-manip4.jpg?v=2" alt="Propaganda poster" loading="lazy" /><span class="ex-badge bad"><span class="d"></span>Strong persuasion</span></div>
<div class="cap"><div class="t">Mobilization poster (1943)</div><div class="tags"><span>heroic framing</span><span>low-angle shot</span><span>imperative slogan</span></div></div>
</div>
<div class="sp">
<div class="ph"><img src="assets/img/examples/m-doc1.jpg?v=2" alt="Documentary photo" loading="lazy" /><span class="ex-badge warn"><span class="d"></span>Light staging</span></div>
<div class="cap"><div class="t">Press photo</div><div class="tags"><span>informative framing</span><span>light dramatization</span></div></div>
</div>
<div class="sp">
<div class="ph"><img src="assets/img/examples/m-real1.jpg?v=2" alt="Neutral photo" loading="lazy" /><span class="ex-badge ok"><span class="d"></span>Neutral</span></div>
<div class="cap"><div class="t">Documentary landscape</div><div class="tags"><span>no emotional lever</span></div></div>
</div>
</div>
<div class="ex-meter">
<div class="bar"></div>
<div class="lbls"><span>Strong persuasion</span><span>Neutral</span></div>
</div>
<p class="ex-foot">Examples: posters — public domain (Wikimedia Commons); photos — Unsplash. Shown to illustrate the techniques, with no endorsement.</p>
</section>
<div id="process-io2"></div>
<div id="result-io2" style="margin-top:30px;"></div>
</section>
<!-- =================== IO4 — Image Tampering Detection (Rayen) =================== -->
<section id="pane-io4" class="px-6 py-6" style="display:none;">
<div id="api-status-io4" class="api-banner desk">Connecting to the service…</div>
<div class="coh-intro">
<div class="coh-intro-text">
<div class="coh-intro-kicker">Retouching &amp; editing</div>
<h2>Has this photo been retouched?</h2>
<p>Drop a photo: we look for traces of modification — added elements, duplicated areas, photo composites, cosmetic retouching — and we pinpoint the affected areas directly on the image. You get a verdict, the most likely type of modification and a confidence score.</p>
</div>
<div class="coh-intro-modules">
<div class="intro-mod"><span class="mono mono-sm clip">·</span><span class="nm">Added elements<small>Something has been inserted</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm whisper">·</span><span class="nm">Duplication<small>A part of the image has been copied</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm sam">·</span><span class="nm">Photo composite<small>A piece comes from another image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm yolo">·</span><span class="nm">Cosmetic retouching<small>Smoothing, beautifying, adjustments</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm ocr">·</span><span class="nm">Localization<small>The modified areas, on the image</small></span><span class="pct"></span></div>
</div>
</div>
<form id="form-io4" class="io6-input-shell" onsubmit="return false;">
<div id="io4-modepick" style="display:flex; gap:10px; margin-bottom:18px; flex-wrap:wrap;">
<button type="button" data-io4-mode="single" class="io4-mode-btn active">One photo<small>Look for traces of editing in a single image</small></button>
<button type="button" data-io4-mode="compare" class="io4-mode-btn">Compare to the original<small>Have the original? We diff the pixels and pinpoint exactly what changed</small></button>
</div>
<div class="field-label-desk">
<span class="num">01.</span>
<span id="io4-label-1">Photo to analyze</span>
</div>
<input type="file" id="file-io4" accept="image/jpeg,image/png,image/webp,image/bmp" hidden />
<div id="drop-io4" class="io4-drop" tabindex="0" data-input="file-io4" data-kind="image">
<div class="io4-drop-cross">+</div>
<div class="io4-drop-title">Drop a photo</div>
<div class="io4-drop-sub">JPG · PNG · WEBP · BMP — any size</div>
<div class="io4-drop-formats">Result in an instant</div>
</div>
<div id="wrap-io4-ref" style="display:none; margin-top:22px;">
<div class="field-label-desk">
<span class="num">02.</span>
<span>The original photo (for comparison)</span>
</div>
<input type="file" id="file-io4-ref" accept="image/jpeg,image/png,image/webp,image/bmp" hidden />
<div id="drop-io4-ref" class="io4-drop" tabindex="0" data-input="file-io4-ref" data-kind="image">
<div class="io4-drop-cross">+</div>
<div class="io4-drop-title">Drop the ORIGINAL photo</div>
<div class="io4-drop-sub">The untouched version, to compare against</div>
<div class="io4-drop-formats">We highlight every changed pixel</div>
</div>
</div>
<div style="margin-top:18px; display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap;">
<span id="status-io4" class="desk-status">
<span class="sc-led"></span>
<span class="sc-text">READY</span>
</span>
<button id="btn-io4" type="button" class="io4-cta">Start the analysis</button>
</div>
</form>
<!-- Examples gallery — spot the manipulation -->
<section class="ex-section">
<div class="ex-head">
<span class="ex-k">Authentic or retouched?</span>
<h3>Four photos. Only one has been faked.</h3>
<p>This is the kind of material the module examines. The photo in the red frame is a famous historical composite — the other three are authentic. The module pinpoints exactly the suspect area.</p>
</div>
<div class="ex-evidence">
<div class="ev bad">
<div class="ph"><img src="assets/img/examples/m-edit1.jpg?v=2" alt="Historical photo composite" loading="lazy" /><span class="ex-badge bad"><span class="d"></span>Composite</span></div>
<div class="body"><div class="t">Photo composite (around 1860)</div><div class="why">Abraham Lincoln's head grafted onto John C. Calhoun's body — one of the earliest known photo fakes. Collar seam, inconsistent lighting, posture.</div></div>
</div>
<div class="ev">
<div class="ph"><img src="assets/img/examples/m-orig1.jpg?v=2" alt="Authentic photo" loading="lazy" /><span class="ex-badge ok"><span class="d"></span>Authentic</span></div>
<div class="body"><div class="t">Wildlife photo</div><div class="why">No trace of copy-paste, cloning or local recompression. Consistent noise and edges across the whole image.</div></div>
</div>
<div class="ev">
<div class="ph"><img src="assets/img/examples/m-real3.jpg?v=2" alt="Authentic portrait" loading="lazy" /><span class="ex-badge ok"><span class="d"></span>Authentic</span></div>
<div class="body"><div class="t">Portrait</div><div class="why">Uniform skin texture and grain, no “too smooth” area and no cut-out halo. Metadata and quantization table intact.</div></div>
</div>
<div class="ev">
<div class="ph"><img src="assets/img/examples/m-real4.jpg?v=2" alt="Authentic photo" loading="lazy" /><span class="ex-badge ok"><span class="d"></span>Authentic</span></div>
<div class="body"><div class="t">Night sky</div><div class="why">A single compression signature across the entire file — no added element and no pasted-in area.</div></div>
</div>
</div>
<p class="ex-foot">Examples: Lincoln/Calhoun composite — public domain (Wikimedia Commons); photos — Wikimedia Commons / Unsplash.</p>
</section>
<div id="process-io4"></div>
<div id="result-io4" style="margin-top:30px;"></div>
</section>
<!-- =================== IO1 — Fake Media Detection (deepfake & AI-generated) (Islem) =================== -->
<section id="pane-io1" class="px-6 py-6" style="display:none;">
<div id="api-status-io1" class="api-banner desk">Connecting to the service…</div>
<div class="coh-intro">
<div class="coh-intro-text">
<div class="coh-intro-kicker">Real or faked</div>
<h2>Is this image — or this video — authentic?</h2>
<p>Three checks to choose from below: a <strong>deepfaked face in a photo</strong>, a <strong>deepfaked face in a video</strong>, or an <strong>image entirely fabricated by artificial intelligence</strong>. You get a verdict, a confidence score, the areas that led to this conclusion and a plain-language explanation.</p>
</div>
<div class="coh-intro-modules">
<div class="intro-mod"><span class="mono mono-sm clip">·</span><span class="nm">Deepfake — photo<small>Faked face in an image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm whisper">·</span><span class="nm">Deepfake — video<small>Faked face in a video</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm sam">·</span><span class="nm">AI-generated image<small>Real photo or fabricated image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm yolo">·</span><span class="nm">Decisive areas<small>Highlighted on the image</small></span><span class="pct"></span></div>
<div class="intro-mod"><span class="mono mono-sm ocr">·</span><span class="nm">Explanation<small>The result told simply</small></span><span class="pct"></span></div>
</div>
</div>
<div class="io2-mode-tabs" role="tablist">
<button type="button" class="active" data-io1-mode="df-image"><span class="mt-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8.5 14.5c1 1.2 2.2 1.8 3.5 1.8s2.5-.6 3.5-1.8"/><circle cx="9" cy="10" r="1" fill="currentColor" stroke="none"/><circle cx="15" cy="10" r="1" fill="currentColor" stroke="none"/></svg></span>Deepfake — photo</button>
<button type="button" data-io1-mode="df-video"><span class="mt-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="14" height="14" rx="1.5"/><path d="M17 9.5l4-2.5v10l-4-2.5z"/></svg></span>AI-generated video</button>
<button type="button" data-io1-mode="ai-image"><span class="mt-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l1.7 6.3L20 11l-6.3 1.7L12 19l-1.7-6.3L4 11l6.3-1.7z"/></svg></span>AI-generated image</button>
</div>
<form id="form-io1" class="io6-input-shell" onsubmit="return false;">
<div class="field-label-desk">
<span class="num">01.</span>
<span id="io1-field-label">Photo (with a face) to analyze</span>
</div>
<input type="file" id="file-io1" accept="image/jpeg,image/png,image/webp,image/bmp" hidden />
<div id="drop-io1" class="io2-drop" tabindex="0" data-input="file-io1" data-kind="image">
<div class="io2-drop-circle">
<span class="icon icon-22 icon-stroke" data-icon="image"></span>
</div>
<div class="io2-drop-title">Drag and drop a photo with a face</div>
<div class="io2-drop-sub">JPG · PNG · WEBP · BMP — we check whether the face has been replaced by a fake.</div>
</div>
<div style="margin-top:18px; display:flex; align-items:center; justify-content:space-between; gap:18px; flex-wrap:wrap;">
<span id="status-io1" class="desk-status">
<span class="sc-led"></span>
<span class="sc-text">READY</span>
· a few seconds
</span>
<button id="btn-io1" type="button" class="io2-cta">Start the analysis</button>
</div>
</form>
<!-- Examples gallery — AI vs real (flip cards) -->
<section class="ex-section">
<div class="ex-head">
<span class="ex-k">What it looks like</span>
<h3>Can you tell the real from the AI?</h3>
<p>Four images: two fabricated by artificial intelligence, two authentic. Hover (or tab) over a card to reveal the verdict — this is exactly the kind of signal the module isolates.</p>
</div>
<div class="ex-flip">
<div class="fc" tabindex="0">
<div class="fc-inner">
<div class="fc-face fc-front"><img src="assets/img/examples/m-ai1.png?v=2" alt="AI-generated image" loading="lazy" /></div>
<div class="fc-face fc-back is-ai">
<span class="ex-badge bad"><span class="d"></span>AI-generated</span>
<div class="v">Fabricated image</div>
<div class="why">“Astronaut riding a horse” — produced by a diffusion model (DALL·E 2). The hands, the harness and the background carry the marks of generation.</div>
</div>
</div>
</div>
<div class="fc" tabindex="0">
<div class="fc-inner">
<div class="fc-face fc-front"><img src="assets/img/examples/m-real2.jpg?v=2" alt="Real photo" loading="lazy" /></div>
<div class="fc-face fc-back is-real">
<span class="ex-badge ok"><span class="d"></span>Real photo</span>
<div class="v">Authentic</div>
<div class="why">A real photograph (Unsplash). Sensor noise, shallow depth-of-field blur and anatomical consistency: no generation marker.</div>
</div>
</div>
</div>
<div class="fc" tabindex="0">
<div class="fc-inner">
<div class="fc-face fc-front"><img src="assets/img/examples/m-ai2.png?v=2" alt="AI-generated face" loading="lazy" /></div>
<div class="fc-face fc-back is-ai">
<span class="ex-badge bad"><span class="d"></span>AI-generated</span>
<div class="v">Synthetic face</div>
<div class="why">“This woman does not exist” — a face produced by a GAN. Fine asymmetries, a “painted” blurry background and inconsistent accessories give it away.</div>
</div>
</div>
</div>
<div class="fc" tabindex="0">
<div class="fc-inner">
<div class="fc-face fc-front"><img src="assets/img/examples/m-real3.jpg?v=2" alt="Real photo" loading="lazy" /></div>
<div class="fc-face fc-back is-real">
<span class="ex-badge ok"><span class="d"></span>Real photo</span>
<div class="v">Authentic</div>
<div class="why">A real photographic portrait (Unsplash). Light, grain and hair detail are physically consistent.</div>
</div>
</div>
</div>
</div>
<p class="ex-foot">Examples: AI images — Wikimedia Commons; real photos — Unsplash.</p>
</section>
<div id="process-io1"></div>
<div id="result-io1" style="margin-top:30px;"></div>
</section>
<!-- =================== Generic placeholder for analyses not yet open =================== -->
<section id="pane-generic" class="px-6 py-6" style="display:none;">
<div class="drop-zone">
<div class="icon-up"></div>
<h3 class="font-serif" style="font-size:24px;margin:14px 0 8px;">Coming soon</h3>
<p class="text-gray-500 mb-4">This analysis is coming soon.</p>
<div class="flex flex-col md:flex-row gap-3 justify-center items-center">
<a href="verifier.html" class="btn-outline">See the other analyses</a>
</div>
<p class="text-xs text-gray-500 mt-4">In the meantime, try “Image &amp; caption”, “Visual manipulation”, “Retouching &amp; editing” or “Advertising &amp; cosmetics”.</p>
</div>
</section>
</main>
<div id="site-footer"></div>
<script src="assets/js/config.js?v=2"></script>
<script src="assets/js/components.js?v=14"></script>
<script src="assets/js/main.js?v=7"></script>
<script src="assets/js/coherence.js?v=11"></script>
<script src="assets/js/cosmetic.js?v=13"></script>
<script src="assets/js/manipulation.js?v=4"></script>
<script src="assets/js/forensics.js?v=8"></script>
<script src="assets/js/synthesis.js?v=5"></script>
<script>
// ── Theme the cinematic module hero per ?m= (image, accent, console, spec) ──
document.addEventListener('DOMContentLoaded', () => {
const m = (new URLSearchParams(location.search).get('m') || 'io1').toLowerCase();
const I = 'assets/img/';
const HERO = {
io1: { img: I+'oi1.png?v=2', mc: '#8b5cf6', console: 'Deepfake analysis',
signals: [['Facial landmarks','ok'],['Temporal consistency','run'],['Generation artifacts','ok'],['Verdict','run']],
stats: [['247','analyses · 7 d'],['‹ 1 min','average time']], formats: 'MP4 · MOV · AVI' },
io2: { img: I+'oi2.png?v=2', mc: '#f59e0b', console: 'Manipulation detection',
signals: [['Framing & composition','ok'],['Emotional grading','run'],['Editing & pacing','ok'],['Persuasion score','run']],
stats: [['89','analyses · 7 d'],['‹ 30 s','average time']], formats: 'JPG · PNG · MP4 · 50 MB' },
io4: { img: I+'oi4.png?v=2', mc: '#22c55e', console: 'Photo forensics',
signals: [['ELA analysis','ok'],['Quantization table','ok'],['Clone detection','run'],['Suspect areas','run']],
stats: [['112','analyses · 7 d'],['‹ 40 s','average time']], formats: 'JPG · PNG · TIFF · RAW' },
io5: { img: I+'oi5.png?v=2', mc: '#14b8a6', console: 'Caption consistency & fidelity',
signals: [['Reading the image','ok'],['Reading the caption','ok'],['Semantic alignment','run'],['Exaggerations & omissions','run']],
stats: [['203','analyses · 7 d'],['‹ 2 min','average time']], formats: 'JPG · PNG · MP4 · URL' },
io6: { img: I+'oi6.png?v=2', mc: '#f97316', console: 'Advertising claims',
signals: [['Before / after','ok'],['Testimonials','run'],['Numeric claims','run'],['EU compliance','ok']],
stats: [['74','analyses · 7 d'],['‹ 90 s','average time']], formats: 'MP4 · MOV · JPG · ad URL' },
};
const cfg = HERO[m] || HERO.io1;
const SEQ_NO = { io1: 1, io2: 2, io4: 3, io5: 4, io6: 5 };
const idx = String(SEQ_NO[m] || 1);
const $ = (id) => document.getElementById(id);
const hero = $('m-hero'); if (hero) hero.style.setProperty('--mc', cfg.mc);
document.body.style.setProperty('--mc', cfg.mc); // so the analysis panes pick up the module accent
if ($('m-hero-img')) $('m-hero-img').src = cfg.img;
if ($('m-hero-ghost')) $('m-hero-ghost').textContent = idx.padStart(2, '0');
if ($('m-hero-idx')) $('m-hero-idx').textContent = idx.padStart(2, '0');
// The chip mirrors the legacy badge text (set by coherence.js / cosmetic.js, which run first)
if ($('m-hero-chip') && $('m-badge')) $('m-hero-chip').textContent = $('m-badge').textContent || cfg.console;
if ($('m-hero-console-title')) $('m-hero-console-title').textContent = cfg.console;
if ($('m-hero-signals')) {
$('m-hero-signals').innerHTML = cfg.signals.map(([label, st]) => `
<li><span class="mk ${st}">${st === 'ok' ? '✓' : '·'}</span>${label}<span class="s ${st}">${st === 'ok' ? 'OK' : 'in progress'}</span></li>`).join('');
}
if ($('m-hero-spec')) {
$('m-hero-spec').innerHTML =
cfg.stats.map(([v, l]) => `<div class="mspec__item"><strong>${v}</strong><span>${l}</span></div>`).join('') +
`<div class="mspec__item is-formats"><b>Formats</b>${cfg.formats}</div>`;
}
});
</script>
<script>
// ── Analysis results → luxe popup ─────────────────────────────────────
// Each #result-ioX (and result-image / result-video) is moved into its
// own fullscreen "report" modal. Module scripts keep targeting the same
// id; a MutationObserver swings the modal open the moment a result lands.
document.addEventListener('DOMContentLoaded', () => {
const PAIRS = [
{ m: 'io5', r: 'result-image', t: 'Image–caption consistency', mc: '#14b8a6' },
{ m: 'io5', r: 'result-video', t: 'Video–caption consistency', mc: '#14b8a6' },
{ m: 'io6', r: 'result-io6', t: 'Cosmetics advertising', mc: '#f97316' },
{ m: 'io2', r: 'result-io2', t: 'Visual manipulation', mc: '#f59e0b' },
{ m: 'io4', r: 'result-io4', t: 'Photo forensics', mc: '#22c55e' },
{ m: 'io1', r: 'result-io1', t: 'AI-generated video', mc: '#8b5cf6' },
];
const META = {
io1: { kicker: 'AI-generated video & deepfake', method: ['Multi-frame extraction', 'GPT-4o visual analysis per keyframe', 'AI-generation tells (Sora / Veo / Runway / Kling)', 'Vote aggregation across frames'] },
io2: { kicker: 'Visual manipulation', method: ['Framing & composition', 'Emotional grading', 'Visual urgency signals', 'Multi-modal synthesis'] },
io4: { kicker: 'Photo forensics', method: ['Error Level Analysis (ELA)', 'JPEG quantization tables', 'Clone detection', 'Mapping of altered areas'] },
io5: { kicker: 'Caption consistency & fidelity', method: ['CLIP / BLIP semantic reading', 'Image ↔ caption alignment', 'Out-of-context image detection', 'Exaggerations & omissions'] },
io6: { kicker: 'Cosmetic claims',method: ['Before / after', 'Deepfaked testimonials', 'Numeric claims', 'Compliance with EU rules'] },
};
const MODULE_NO = { io1: 1, io2: 2, io4: 3, io5: 4, io6: 5 };
const MODULE_TOTAL = Object.keys(MODULE_NO).length;
const MOD_IMG = {
io1: 'assets/img/oi1.png?v=2',
io2: 'assets/img/oi2.png?v=2',
io4: 'assets/img/oi4.png?v=2',
io5: 'assets/img/oi5.png?v=2',
io6: 'assets/img/oi6.png?v=2',
};
const hasContent = (el) => !!el && (el.children.length > 0 || el.textContent.trim().length > 0);
const pad2 = (n) => String(n).padStart(2, '0');
const fmtDate = (d) => {
const dt = d.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', year: 'numeric' });
const tm = d.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' });
return `${dt} · ${tm}`;
};
const newReportId = () => 'A-' + String(Math.floor(1000 + Math.random() * 8999));
const newHash = () => {
const c = () => Math.floor(Math.random() * 0xffff).toString(16).padStart(4, '0');
return `${c()}·${c()}·${c()}`;
};
// ── Remember the file the user submitted (works for click-pick AND drag-drop) ──
let lastInputFile = null;
const rememberFile = (f) => { if (f && /^(image|video)\//.test(f.type || '')) lastInputFile = f; };
document.addEventListener('change', (e) => {
const t = e.target;
if (t && t.matches && t.matches('input[type="file"]')) rememberFile(t.files && t.files[0]);
}, true);
document.addEventListener('drop', (e) => {
rememberFile(e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files[0]);
}, true);
// Coarse verdict state ('fake' | 'real' | 'suspect' | null) for the report stamp
function verdictState(result) {
const s = extractSummary(result);
const st = (s && s.state ? String(s.state) : '').toUpperCase();
if (st === 'FAKE' || st === 'REAL' || st === 'SUSPECT') return st.toLowerCase();
if (/INCOHERENT|MISLEAD|FAKE|DEEPFAKE|TRUQU|TROMPEU|ALTER|TAMPER|FORGE|MANIPUL|AI_?GENERAT/.test(st)) return 'fake';
if (/COHERENT|RELIABLE|FIABLE|AUTHENTIC|^REAL|GENUINE|^OK$|VERIDIQUE|VERITABLE/.test(st)) return 'real';
if (/SUSPECT|TO_?VERIFY|A_?VERIFIER|MODERATE|DOUBT|UNCERTAIN|VERIFY/.test(st)) return 'suspect';
const vEl = result.querySelector('.h-verdict, .vh-verdict, .verdict-word, .verdict-mark, .h-headline');
const txt = ((vEl ? vEl.textContent : (s && s.verdict) || '') || '').toLowerCase();
if (/faux|truqu|trompeu|incoh[ée]r|deepfake|g[ée]n[ée]r|synth[ée]ti|artificiel|\bfake\b|montage|retouch|manipul|alt[ée]r|mislead/.test(txt)) return 'fake';
if (/authentiqu|\br[ée]el(le)?\b|fiable|coh[ée]r|conforme|genuine|v[ée]ritabl|\breal\b|\bok\b/.test(txt)) return 'real';
if (/suspect|[àa] v[ée]rifier|to verify|incertain|douteu|mod[ée]r/.test(txt)) return 'suspect';
return null;
}
// Build the report hero: the submitted image/video, topped by a FAKE/REAL stamp.
function buildInputHero(modal, body, anchor, state) {
const old = body.querySelector('.rm-input-hero');
if (old) old.remove();
if (modal._inputUrl) { try { URL.revokeObjectURL(modal._inputUrl); } catch (e) {} modal._inputUrl = null; }
const f = lastInputFile;
if (!f) return;
const isVid = (f.type || '').startsWith('video/');
const url = URL.createObjectURL(f);
modal._inputUrl = url;
const icSvg = isVid
? '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="14" height="14" rx="1.5"/><path d="M17 9.5l4-2.5v10l-4-2.5z"/></svg>'
: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3.5" width="18" height="17" rx="1.5"/><circle cx="9" cy="9.5" r="1.6"/><path d="M3 17l5-5 4 4 3-3 6 5"/></svg>';
// ── verdict seal: an embossed certification stamp on the photo ───────
let sealHtml = '';
if (state) {
const INK = '#0b2452';
const ACC = state === 'fake' ? '#9b2226' : state === 'real' ? '#1d5e3a' : '#9a6b16';
const WORD = state === 'fake' ? 'FAKE' : state === 'real' ? 'REAL' : 'TO VERIFY';
const WSIZE = state === 'suspect' ? 13 : 19;
const WLS = state === 'suspect' ? 1.4 : 2.4;
const dateStr = new Date().toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' }).replace(/\//g, ' · ');
const sid = 'rm-s-' + Math.random().toString(36).slice(2, 8);
const ICON = state === 'fake'
? `<path d="M -6 -6 L 6 6 M 6 -6 L -6 6" stroke="${ACC}" stroke-width="2.3" stroke-linecap="round"/>`
: state === 'real'
? `<path d="M -7 0 L -2 5.5 L 7.6 -6.2" fill="none" stroke="${ACC}" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/>`
: `<text y="7" text-anchor="middle" font-family="Georgia,'Times New Roman',serif" font-weight="700" font-size="20" fill="${ACC}">!</text>`;
sealHtml = `<div class="rm-input-seal" data-v="${state}" aria-hidden="true"><svg viewBox="0 0 132 132">
<defs>
<path id="${sid}-t" d="M 21 66 A 45 45 0 0 1 111 66" fill="none"/>
<path id="${sid}-b" d="M 21 66 A 45 45 0 0 0 111 66" fill="none"/>
</defs>
<circle cx="66" cy="66" r="63" fill="none" stroke="${INK}" stroke-width="1.2"/>
<circle cx="66" cy="66" r="56" fill="none" stroke="${INK}" stroke-width="0.6"/>
<circle cx="66" cy="66" r="53" fill="none" stroke="${ACC}" stroke-width="2.2"/>
<text font-family="ui-monospace,Menlo,monospace" font-size="7.3" letter-spacing="2.2" font-weight="600" fill="${INK}"><textPath href="#${sid}-t" startOffset="50%" text-anchor="middle">VERIFY · AI FORENSIC ANALYSIS</textPath></text>
<text font-family="ui-monospace,Menlo,monospace" font-size="7.3" letter-spacing="2.4" font-weight="600" fill="${INK}"><textPath href="#${sid}-b" startOffset="50%" text-anchor="middle">${dateStr}</textPath></text>
<circle cx="10" cy="66" r="1.7" fill="${ACC}"/><circle cx="122" cy="66" r="1.7" fill="${ACC}"/>
<g transform="translate(66 55)">${ICON}</g>
<line x1="46" y1="69" x2="86" y2="69" stroke="${INK}" stroke-width="0.6"/>
<text x="66" y="90" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-weight="800" font-size="${WSIZE}" letter-spacing="${WLS}" fill="${ACC}">${WORD}</text>
</svg></div>`;
}
const hero = document.createElement('div');
hero.className = 'rm-input-hero';
hero.innerHTML = `
<div class="rm-input-media">
<div class="rm-input-frame">
${isVid
? `<video src="${url}" controls muted playsinline preload="metadata"></video>`
: `<img src="${url}" alt="File submitted for analysis" />`}
${sealHtml}
</div>
</div>
<div class="rm-input-cap"><span class="ic">${icSvg}</span><span class="nm"></span><span>&nbsp;·&nbsp;${isVid ? 'video' : 'image'} submitted for analysis</span></div>`;
hero.querySelector('.rm-input-cap .nm').textContent = f.name || (isVid ? 'video' : 'image');
body.insertBefore(hero, anchor);
}
// Pull a verdict / confidence / metrics summary out of the rendered result
function extractSummary(result) {
const hero = result.querySelector('.io1-hero, .verdict-hero, .verdict-banner, .fc-verdict-banner, [class*="hero"]');
if (!hero) return null;
const vEl = hero.querySelector('.h-verdict, .vh-verdict, .verdict-word, .verdict-mark, .h-headline, h1, h2, h3');
const verdict = vEl ? vEl.textContent.trim().replace(/\s+/g, ' ') : '';
let state = hero.getAttribute('data-v') || hero.getAttribute('data-verdict') || '';
if (!state) {
const cls = (hero.className + ' ' + (vEl ? vEl.className : '')).toLowerCase();
if (/incoherent|fake|misleading|truqu|trompeu|alter|manipul|suspect/.test(cls)) state = 'fake';
else if (/coherent|real|authentic|fiable|reliable|ok/.test(cls)) state = 'real';
}
let conf = '';
const cNum = hero.querySelector('[data-count]');
if (cNum) conf = (cNum.getAttribute('data-count') || '').replace(/[^\d]/g, '');
if (!conf) { const m = hero.textContent.match(/(\d{1,3})\s*%/); if (m) conf = m[1]; }
const meta = [];
hero.querySelectorAll('.h-meta > div, .vh-meta > div').forEach(d => {
const k = d.querySelector('.k, dt'), v = d.querySelector('.v, dd');
if (k && v) meta.push({ k: k.textContent.trim(), v: v.textContent.trim() });
});
return { verdict, state, conf, meta };
}
function renderDashboard(modal, result) {
const body = modal.querySelector('.result-modal__body');
if (!body) return;
body.querySelectorAll('.rm-kpi, .rm-statusbar').forEach(el => el.remove());
modal.querySelectorAll('.rm-toc__verdict').forEach(el => el.remove());
const s = extractSummary(result);
const stateCls = s && (s.state === 'fake' ? 'is-fake' : s.state === 'real' ? 'is-real' : '');
const stateColor = s && (s.state === 'fake' ? '#dc2626' : s.state === 'real' ? '#16a34a' : '');
const reportId = (modal.querySelector('[data-rm-id]') || {}).textContent || '';
const hashTxt = (modal.querySelector('[data-rm-sig-hash]') || {}).textContent || '';
const anchor = body.querySelector('#' + result.id) || result;
// hero: the submitted image/video + FAKE/REAL stamp, at the very top
buildInputHero(modal, body, anchor, verdictState(result));
// status bar
const sb = document.createElement('div');
sb.className = 'rm-statusbar';
sb.innerHTML = `
<span class="st-led"><span class="dot"></span> ANALYSIS COMPLETE</span>
<span class="st-item">Case <b>${reportId}</b></span>
<span class="st-item">Fingerprint <b class="mono">${hashTxt}</b></span>
${s && s.conf ? `<span class="st-item">Confidence <b>${s.conf} %</b></span>` : ''}
<span class="st-spacer"></span>
<span class="st-bars" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></span>`;
body.insertBefore(sb, anchor);
// KPI tiles
if (s) {
const tiles = [];
tiles.push(`<div class="rm-kpi__tile" style="--kpi-c:#16a34a;"><span class="lbl">Status</span><span class="led2"><span class="dot"></span> Complete</span></div>`);
if (s.verdict) tiles.push(`<div class="rm-kpi__tile"${stateColor ? ` style="--kpi-c:${stateColor};"` : ''}><span class="lbl">Verdict</span><span class="val ${stateCls}">${s.verdict}</span></div>`);
if (s.conf) {
const p = Math.max(0, Math.min(100, parseInt(s.conf, 10) || 0));
tiles.push(`<div class="rm-kpi__tile"${stateColor ? ` style="--kpi-c:${stateColor};"` : ''}><span class="lbl">Confidence score</span><span class="val">${s.conf} %</span><span class="bar"><i style="width:${p}%;"></i></span></div>`);
}
s.meta.forEach(m => {
if (/confiance|confidence/i.test(m.k)) return;
tiles.push(`<div class="rm-kpi__tile"><span class="lbl">${m.k}</span><span class="val sm">${m.v}</span></div>`);
});
const kpi = document.createElement('div');
kpi.className = 'rm-kpi';
kpi.innerHTML = tiles.join('');
body.insertBefore(kpi, anchor);
// sidebar verdict widget
if (s.verdict) {
const aside = modal.querySelector('.rm-toc');
if (aside) {
const p = s.conf ? (parseInt(s.conf, 10) || 0) : 0;
const vw = document.createElement('div');
vw.className = 'rm-toc__verdict';
vw.innerHTML = `
<div class="vw-lbl">Verdict</div>
<div class="vw-val ${stateCls}">${s.verdict}</div>
${s.conf ? `<div class="vw-conf"><span class="ring" style="--p:${p};${stateColor ? `--mc:${stateColor};` : ''}"></span> ${s.conf} % confidence</div>` : ''}`;
aside.insertBefore(vw, aside.firstChild);
}
}
}
}
function buildToc(modal, result) {
const nav = modal.querySelector('[data-rm-nav]');
const body = modal.querySelector('.result-modal__body');
if (!nav || !body) return;
const sections = [];
const hero = result.querySelector('.io1-hero, .verdict-hero, .verdict-banner, .fc-verdict-banner');
if (hero) {
if (!hero.id) hero.id = result.id + '-verdict';
sections.push({ id: hero.id, label: 'Verdict' });
}
result.querySelectorAll('.coh-card').forEach((card, i) => {
const h = card.querySelector('.coh-card-head h3, h3, h2');
if (!h) return;
if (!card.id) card.id = `${result.id}-sec-${i + 1}`;
sections.push({ id: card.id, label: h.textContent.trim() });
});
if (sections.length < 2) { nav.innerHTML = ''; return; }
nav.innerHTML = sections.map((s, i) => `
<a href="#${s.id}" data-rm-target="${s.id}"${i === 0 ? ' class="is-current"' : ''}>
<span class="n">${pad2(i + 1)}</span><span>${s.label}</span>
</a>`).join('');
nav.querySelectorAll('a').forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault();
const target = document.getElementById(a.dataset.rmTarget);
if (!target) return;
const tRect = target.getBoundingClientRect();
const bRect = body.getBoundingClientRect();
body.scrollTo({ top: Math.max(0, tRect.top - bRect.top + body.scrollTop - 16), behavior: 'smooth' });
});
});
if (modal._tocObs) modal._tocObs.disconnect();
modal._tocObs = new IntersectionObserver((entries) => {
let bestId = null, bestRatio = 0;
entries.forEach(e => { if (e.intersectionRatio > bestRatio) { bestRatio = e.intersectionRatio; bestId = e.target.id; } });
if (bestId) nav.querySelectorAll('a').forEach(a => a.classList.toggle('is-current', a.dataset.rmTarget === bestId));
}, { root: body, rootMargin: '0px 0px -55% 0px', threshold: [0, 0.25, 0.6, 1] });
sections.forEach(s => { const el = document.getElementById(s.id); if (el) modal._tocObs.observe(el); });
}
PAIRS.forEach(({ m, r, t, mc }) => {
const result = document.getElementById(r);
if (!result) return;
const modNo = MODULE_NO[m] || 0;
const meta = META[m] || META.io1;
const modal = document.createElement('div');
modal.className = 'result-modal'; modal.hidden = true;
modal.style.setProperty('--mc', mc);
modal.innerHTML = `
<div class="result-modal__bgimg" aria-hidden="true">${MOD_IMG[m] ? `<img src="${MOD_IMG[m]}" alt="" loading="lazy" />` : ''}</div>
<div class="result-modal__backdrop"></div>
<div class="result-modal__panel has-rm-layout" role="dialog" aria-modal="true" aria-labelledby="rm-title-${r}">
<header class="result-modal__head">
<div class="rm-head-top">
<div class="rm-head-thumb" aria-hidden="true">${MOD_IMG[m] ? `<img src="${MOD_IMG[m]}" alt="" loading="lazy" />` : ''}</div>
<div class="rm-head-titles">
<span class="rm-kicker">Analysis report</span>
<h2 class="rm-title" id="rm-title-${r}">${t} — report</h2>
</div>
<div class="rm-actions">
<button class="rm-btn rm-print" type="button" title="Export to PDF">
<span aria-hidden="true">⤓</span> <span class="lbl">Export to PDF</span>
</button>
<button class="rm-close" type="button" aria-label="Close">✕</button>
</div>
</div>
<div class="rm-meta">
<span class="rm-meta-item"><span class="dot"></span>Case <b data-rm-id>${newReportId()}</b></span>
<span class="rm-meta-item"><span class="dot"></span><b data-rm-date>${fmtDate(new Date())}</b></span>
<span class="rm-meta-item"><span class="dot"></span>Module <b>${pad2(modNo)}</b> / 05</span>
<span class="rm-meta-item"><span class="dot"></span>Verified by <b>Verify · AI</b></span>
</div>
</header>
<div class="rm-layout">
<aside class="rm-toc">
<h4>Contents</h4>
<nav class="rm-toc__nav" data-rm-nav></nav>
<div class="rm-toc__about">
<h5>Analysis method</h5>
<ul>${meta.method.map(s => `<li>${s}</li>`).join('')}</ul>
</div>
</aside>
<div class="result-modal__body"></div>
<div class="rm-intro">
<div class="scan" aria-hidden="true"></div>
<span class="label"><span class="pulse"></span> Compiling the report</span>
<span class="text">Verify · ${t}</span>
<div class="bar"><i></i></div>
</div>
</div>
</div>`;
const body = modal.querySelector('.result-modal__body');
const intro = modal.querySelector('.rm-intro');
// Watermark + (later) signature + footer — siblings inside the body
const watermark = document.createElement('div');
watermark.className = 'rm-watermark'; watermark.setAttribute('aria-hidden', 'true');
watermark.textContent = 'VERIFY';
body.appendChild(watermark);
body.appendChild(result);
const signature = document.createElement('div');
signature.className = 'rm-signature';
signature.innerHTML = `
<div class="seal" aria-hidden="true">
<div>VERIFIED</div><strong>VERIFY</strong><div class="yr">${new Date().getFullYear()}</div>
</div>
<dl class="meta">
<div><dt>Method</dt><dd>${meta.kicker}</dd></div>
<div><dt>Model</dt><dd>Verify Multi-AI · v4.2</dd></div>
<div><dt>Issue date</dt><dd data-rm-sig-date>${fmtDate(new Date())}</dd></div>
<div><dt>Fingerprint</dt><dd class="mono" data-rm-sig-hash>${newHash()}</dd></div>
</dl>
<div class="by">
<span class="lbl">Verified by</span>
<span class="name">Verify · <span class="ai">AI</span></span>
</div>`;
body.appendChild(signature);
const footer = document.createElement('div');
footer.className = 'rm-footer';
footer.innerHTML = `
<div class="rm-foot-msg">
<span class="seal" aria-hidden="true">✓</span>
Report generated by Verify. Keep the PDF for your records.
</div>
<div class="rm-foot-actions">
<button type="button" class="rm-foot-btn ghost rm-rerun">↻ New analysis</button>
<a class="rm-foot-btn" href="verifier.html">Run another module →</a>
</div>`;
body.appendChild(footer);
document.body.appendChild(modal);
let isOpen = false, introTimer;
const open = () => {
if (isOpen) return;
isOpen = true;
modal.hidden = false;
// refresh meta on each open
modal.querySelector('[data-rm-id]').textContent = newReportId();
modal.querySelector('[data-rm-date]').textContent = fmtDate(new Date());
modal.querySelector('[data-rm-sig-date]').textContent = fmtDate(new Date());
modal.querySelector('[data-rm-sig-hash]').textContent = newHash();
intro.classList.remove('is-hidden');
requestAnimationFrame(() => modal.classList.add('is-open'));
document.body.classList.add('result-open');
body.scrollTop = 0;
modal.querySelector('.rm-close').focus({ preventScroll: true });
setTimeout(() => { renderDashboard(modal, result); buildToc(modal, result); }, 120);
clearTimeout(introTimer);
introTimer = setTimeout(() => intro.classList.add('is-hidden'), 900);
};
const close = () => {
if (!isOpen) return;
isOpen = false;
modal.classList.remove('is-open');
document.body.classList.remove('result-open');
setTimeout(() => { modal.hidden = true; intro.classList.remove('is-hidden'); }, 420);
};
new MutationObserver(() => { if (hasContent(result)) open(); })
.observe(result, { childList: true });
modal.querySelector('.result-modal__backdrop').addEventListener('click', close);
modal.querySelector('.rm-close').addEventListener('click', close);
modal.querySelector('.rm-print').addEventListener('click', () => window.print());
modal.querySelector('.rm-rerun').addEventListener('click', () => { result.innerHTML = ''; close(); });
modal._rmClose = close;
});
document.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return;
document.querySelectorAll('.result-modal.is-open').forEach(m => m._rmClose && m._rmClose());
});
});
</script>
<script>
// ── While a .process-card is on screen, show an elapsed-time line so the
// wait doesn't feel stuck (the real AI inference can take a while).
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('[id^="process-"]').forEach(host => {
let timer = null;
new MutationObserver(() => {
const card = host.querySelector('.process-card');
if (card && timer == null) {
let badge = card.querySelector('.pc-elapsed');
if (!badge) {
badge = document.createElement('span');
badge.className = 'pc-elapsed';
(card.querySelector('.process-head') || card).appendChild(badge);
}
const t0 = Date.now();
const tick = () => {
const s = Math.round((Date.now() - t0) / 1000);
badge.classList.toggle('warn', s >= 75);
badge.textContent = s >= 75
? `${s} s — le service met du temps à répondre (fréquent sur les vidéos lourdes). On patiente encore un peu…`
: s >= 15
? `${s} s écoulées — une analyse complète peut prendre jusqu'à une minute.`
: `${s} s écoulées…`;
};
tick();
timer = setInterval(tick, 1000);
} else if (!card && timer != null) {
clearInterval(timer); timer = null;
}
}).observe(host, { childList: true });
});
});
</script>
</body>
</html>