@font-face{font-family:'Fraunces Variable';font-style:normal;font-display:swap;font-weight:100 900;src:url('fonts/fraunces-latin-wght-normal.woff2') format('woff2')}
@font-face{font-family:'Inter Variable';font-style:normal;font-display:swap;font-weight:100 900;src:url('fonts/inter-latin-wght-normal.woff2') format('woff2')}

/* Jenie — Color tokens
   System: neutral (white→near-black) + a single strong accent.
   Accent "Bleu Jenie" is a deep electric blue inspired by International Klein Blue —
   a distinctly French, premium reference. Confident, trustworthy, ownable.
   Defined in oklch for perceptual consistency across the scale. */

:root {
  /* ----- Base neutrals (very slight cool tint) ----- */
  --gray-0:   #ffffff;
  --gray-50:  oklch(0.985 0.001 264);
  --gray-100: oklch(0.970 0.002 264);
  --gray-150: oklch(0.952 0.003 264);
  --gray-200: oklch(0.928 0.004 264);
  --gray-300: oklch(0.888 0.005 264);
  --gray-400: oklch(0.760 0.007 264);
  --gray-500: oklch(0.612 0.009 264);
  --gray-600: oklch(0.500 0.010 264);
  --gray-700: oklch(0.398 0.009 264);
  --gray-800: oklch(0.278 0.008 264);
  --gray-900: oklch(0.205 0.007 264);
  --gray-950: oklch(0.145 0.006 264);
  --black:    oklch(0.135 0.006 264);
  --white:    #ffffff;

  /* ----- Accent · Bleu Jenie ----- */
  --accent-50:  oklch(0.972 0.013 264);
  --accent-100: oklch(0.936 0.034 264);
  --accent-200: oklch(0.874 0.069 264);
  --accent-300: oklch(0.788 0.118 264);
  --accent-400: oklch(0.676 0.176 264);
  --accent-500: oklch(0.560 0.214 264);  /* primary */
  --accent-600: oklch(0.498 0.214 264);  /* hover */
  --accent-700: oklch(0.438 0.190 264);  /* press */
  --accent-800: oklch(0.372 0.155 264);
  --accent-900: oklch(0.312 0.120 264);

  /* ----- Semantic status (muted, premium) ----- */
  --green-100: oklch(0.94 0.05 158);
  --green-500: oklch(0.640 0.150 158);
  --green-600: oklch(0.560 0.140 158);
  --amber-100: oklch(0.95 0.05 78);
  --amber-500: oklch(0.760 0.150 70);
  --amber-600: oklch(0.680 0.150 62);
  --red-100:   oklch(0.94 0.04 22);
  --red-500:   oklch(0.620 0.210 22);
  --red-600:   oklch(0.548 0.205 22);

  /* ================= Semantic aliases ================= */
  /* Surfaces */
  --surface-page:    var(--gray-50);
  --surface-card:    var(--gray-0);
  --surface-sunken:  var(--gray-100);
  --surface-inset:   var(--gray-150);
  --surface-inverse: var(--black);
  --surface-accent:  var(--accent-500);
  --surface-accent-subtle: var(--accent-50);
  /* Surface accent au survol (E17, BRIEF-43) : un cran plus soutenu que
     --surface-accent → bouton primaire qui « répond » au survol, contraste AA
     conservé (plus foncé = plus de contraste avec --text-on-accent blanc).
     Redéfini par chaque thème/DA (theme.ts) pour rester un cran sous SA surface. */
  --surface-accent-hover: var(--accent-600);
  /* Remplissage du bouton primaire — PILOTABLE par le Style Guide (preset
     « Gradient », BRIEF-51). Défaut = surface accent (aplat) → rendu inchangé ;
     le preset bascule sur --gradient-accent (conceptCssVars, scope client). */
  --btn-fill: var(--surface-accent);

  /* Text */
  --text-strong:  var(--gray-950);
  --text-body:    var(--gray-800);
  --text-muted:   var(--gray-600);
  --text-subtle:  var(--gray-500);
  --text-accent:  var(--accent-600);
  --text-on-accent: var(--white);
  --text-inverse: var(--gray-100);
  /* Texte MUTÉ sur surface inverse (footers sombres) — BRIEF-31. Dérivé du texte
     inverse vers la surface inverse → reste LISIBLE (AA) quelle que soit la
     clarté de la surface inverse du thème (un --text-subtle, pensé pour fond
     CLAIR, échouait sur un footer sombre peu contrasté). ⚠️ Redéclaré dans chaque
     scope de thème (piège var() imbriquée, cf. theme.ts) → capte le
     --text-inverse / --surface-inverse LOCAL. */
  --text-inverse-muted: color-mix(in oklch, var(--text-inverse) 72%, var(--surface-inverse));

  /* Médias (sections v2 à traitement propre, règle 7 du gabarit) */
  /* Voile posé sur les images de FOND — ISO variable Figma « Opacity/Neutral
     Darkest 40 » : le neutre le plus sombre à 40 %. Littéral = DÉFAUT du socle
     (bloc scopé aplati) ; sur le canvas, conceptCssVars RE-ÉMET ce token depuis
     les neutres DU CONCEPT (teinté marque) — idem --surface-media. */
  --overlay-scrim: color-mix(in oklch, oklch(0.145 0.006 264) 40%, transparent);
  /* Aplat « photo grise » : le placeholder plein cadre d'une image de fond
     absente (gris moyen, jamais sombre-sur-sombre). */
  --surface-media: var(--gray-400);

  /* Borders */
  --border-subtle:  oklch(0.928 0.004 264);
  --border-default: oklch(0.888 0.005 264);
  --border-strong:  oklch(0.760 0.007 264);
  --border-accent:  var(--accent-500);
  --ring-accent:    color-mix(in oklch, var(--accent-500) 35%, transparent);

  /* Dégradés sémantiques (BRIEF-30) — DÉFAUT PLAT (= surface unie). Chaque
     « système de DA » (couche thème, cf. theme.ts) les redéfinit en vrais
     dégradés oklch dérivés de la palette. Le défaut pointant vers une surface
     sémantique, le neutre et la DA d'exemple restent rigoureusement inchangés
     (rien ne casse) ; seuls les systèmes de DA introduisent un vrai dégradé. */
  --gradient-accent:  var(--surface-accent);
  --surface-gradient: var(--surface-inverse);

  /* Status aliases */
  --success: var(--green-600);
  --warning: var(--amber-600);
  --danger:  var(--red-600);
}

/* Jenie — Typography tokens
   One family, weight + size + tracking do the work. "Typographie forte":
   large display sizes, heavy weights, tight tracking. Geist for everything,
   Geist Mono for code / technical labels.

   Polices SELF-HOST (woff2 OFL via Fontsource, cf. fonts.css + main.tsx) →
   familles « *Variable » (un seul fichier couvre tous les poids). */

:root {
  /* Families (self-host Variable — souverain, zéro CDN) */
  --font-sans: 'Geist Variable', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'Geist Mono Variable', ui-monospace, 'SF Mono', 'Menlo', monospace;

  /* Weights */
  --weight-light:    300;
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;
  --weight-black:    800;

  /* Multiplicateur d'échelle de type (Style Guide « Size » — Small/Regular/Large).
     Défaut 1 = aucun changement. Le moteur (`conceptCssVars`) le surcharge INLINE
     sur le scope `.jn-canvas` → seul l'aperçu/site client est mis à l'échelle, le
     chrome plateforme (:root = 1) reste intact. Chaque `--text-*` en dépend. */
  --type-scale: 1;

  /* Type scale (1.250 major-third-ish, tuned) — mis à l'échelle par --type-scale */
  --text-2xs: calc(0.6875rem * var(--type-scale));  /* 11px */
  --text-xs:  calc(0.75rem   * var(--type-scale));  /* 12px */
  --text-sm:  calc(0.8125rem * var(--type-scale));  /* 13px */
  --text-base:calc(0.9375rem * var(--type-scale));  /* 15px — UI default */
  --text-md:  calc(1rem      * var(--type-scale));  /* 16px */
  --text-lg:  calc(1.1875rem * var(--type-scale));  /* 19px */
  --text-xl:  calc(1.5rem    * var(--type-scale));  /* 24px */
  --text-2xl: calc(1.9375rem * var(--type-scale));  /* 31px */
  --text-3xl: calc(2.5rem    * var(--type-scale));  /* 40px */
  --text-4xl: calc(3.25rem   * var(--type-scale));  /* 52px */
  --text-5xl: calc(4.25rem   * var(--type-scale));  /* 68px */
  --text-6xl: calc(5.5rem    * var(--type-scale));  /* 88px */

  /* ── Échelle « bibliothèque v2 » (chantier sections — spec Figma Benjamin) ──
     Nom = rôle éditorial ; compagnon `-m` = valeur MOBILE de la maquette
     (bascule au seuil CQ.medium dans le CSS des sections v2). Suit
     `--type-scale` (levier DA) comme l'échelle historique, qui reste servie
     aux sections d'origine jusqu'à la fin de leur remplacement. */
  --heading-1:   calc(3.5rem   * var(--type-scale));  /* 56px */
  --heading-1-m: calc(2.5rem   * var(--type-scale));  /* 40px */
  --heading-2:   calc(3rem     * var(--type-scale));  /* 48px */
  --heading-2-m: calc(2.25rem  * var(--type-scale));  /* 36px */
  --heading-3:   calc(2.5rem   * var(--type-scale));  /* 40px */
  --heading-3-m: calc(2rem     * var(--type-scale));  /* 32px */
  --heading-4:   calc(2rem     * var(--type-scale));  /* 32px */
  --heading-4-m: calc(1.5rem   * var(--type-scale));  /* 24px */
  --heading-5:   calc(1.5rem   * var(--type-scale));  /* 24px */
  --heading-5-m: calc(1.25rem  * var(--type-scale));  /* 20px */
  --heading-6:   calc(1.25rem  * var(--type-scale));  /* 20px */
  --heading-6-m: calc(1.125rem * var(--type-scale));  /* 18px */
  --text-large:    calc(1.25rem  * var(--type-scale)); /* 20px */
  --text-large-m:  calc(1.125rem * var(--type-scale)); /* 18px */
  --text-medium:   calc(1.125rem * var(--type-scale)); /* 18px */
  --text-medium-m: calc(1rem     * var(--type-scale)); /* 16px */
  --text-regular:  calc(1rem     * var(--type-scale)); /* 16px */
  --text-small:    calc(0.875rem * var(--type-scale)); /* 14px */
  --text-tiny:     calc(0.75rem  * var(--type-scale)); /* 12px */

  /* Line heights */
  --leading-tight:   1.05;
  --leading-snug:    1.2;
  --leading-normal:  1.5;
  --leading-relaxed: 1.65;

  /* Letter spacing */
  --tracking-tighter: -0.04em;
  --tracking-tight:   -0.02em;
  --tracking-snug:    -0.01em;
  --tracking-normal:  0em;
  --tracking-wide:    0.02em;
  --tracking-caps:    0.06em;  /* uppercase eyebrows / labels */

  /* Semantic roles */
  --display-font:      var(--font-sans);
  --display-weight:    var(--weight-bold);
  --display-tracking:  var(--tracking-tighter);
  --display-leading:   var(--leading-tight);
  /* Transformation des titres (Style Guide « Style » → Uppercase). Défaut none =
     aucun changement ; surchargé par le moteur sur le scope client uniquement. */
  --display-transform: none;

  --heading-weight:    var(--weight-semibold);
  --heading-tracking:  var(--tracking-tight);

  --body-leading:      var(--leading-relaxed);
  --eyebrow-tracking:  var(--tracking-caps);
}

/* Jenie — Spacing tokens
   Base unit 4px. Generous whitespace is core to the brand — prefer larger steps. */

:root {
  /* Gamme d'espacement — nomenclature VALEUR (BRIEF-139) : le nom du token EST
     sa valeur en pixels, ISO avec les variables Figma « Spacer/space-N » de la
     bibliothèque V2 (correspondance 1:1, aucune conversion). Les VALEURS sont
     celles de la gamme historique, seuls les noms ont changé. */
  --space-0:   0;
  --space-4:   0.25rem;
  --space-8:   0.5rem;
  --space-12:  0.75rem;
  --space-16:  1rem;
  --space-20:  1.25rem;
  --space-24:  1.5rem;
  --space-32:  2rem;
  --space-40:  2.5rem;
  --space-48:  3rem;
  --space-64:  4rem;
  --space-80:  5rem;
  --space-96:  6rem;
  --space-128: 8rem;
  --space-160: 10rem;

  /* Layout — modèle « cap unique + gutter responsive » (BRIEF-26)
     ─────────────────────────────────────────────────────────────────────────
     Le CONTENU d'une section est plafonné par un cap unique `--container-max`,
     et c'est le `--gutter` (espacement des bords) qui crée la marge latérale :
     responsive de ~24px (mobile) à ~80px (desktop) → ~1280px de contenu sur un
     artboard 1440 (80px/côté). Premium, pas edge-to-edge, pas trop vide.

     Les caps `--container-sm/md/lg/xl` restent les caps de TEXTE étroits
     (longueur de ligne lisible) appliqués aux sous-titres/paragraphes/variantes
     centrées — on n'élargit QUE les sections/grilles, pas le texte courant.

     ⚠️ PIÈGE `cqi` (NON négociable) : `--gutter` est en `cqi`, qui se résout sur
     le CONTENEUR ANCÊTRE le plus proche (`container: jn-section / inline-size`,
     posé sur la RACINE de chaque section), PAS sur l'élément qui le consomme.
     → `padding-inline: var(--gutter)` doit donc être porté par un DESCENDANT de
     la racine (le wrapper interne `__inner`), JAMAIS par la racine elle-même
     (sinon `cqi` mesurerait un ancêtre, ou retomberait sur la fenêtre = perte
     de fidélité multi-device, cf. leçon W1-14 / payoff BRIEF-25). Jamais de
     `vw` ni de media query pour la largeur/le gutter : container queries only. */
  --container-sm:  640px;
  --container-md:  860px;
  --container-lg:  1080px;
  --container-xl:  1280px;
  --container-max: 1440px;                  /* plafond de CONTENU (cap unique) */
  --gutter:        clamp(1.5rem, 6cqi, 5rem); /* ~24px → ~80px, suit l'ARTBOARD (cqi), pas la fenêtre */

  /* ── Paddings de section « bibliothèque v2 » (chantier sections — spec Figma
     Benjamin). Contrat : le nom dit la valeur DESKTOP de référence, le
     compagnon `-m` porte la valeur MOBILE de la maquette (bascule CQ.medium
     dans le CSS des sections v2). Cohabite avec `--gutter`/`--section-y`
     (sections d'origine) jusqu'à la fin du remplacement par famille. */
  --padding-global:          4rem;    /* 64 — marge latérale des sections v2 */
  --padding-global-m:        1.25rem; /* 20 */
  --padding-section-large:   7rem;    /* 112 — vertical, sections majeures */
  --padding-section-large-m: 4rem;    /* 64 */
  --padding-section-medium:  5rem;    /* 80 */
  --padding-section-medium-m:3rem;    /* 48 */
  --padding-section-small:   3rem;    /* 48 */
  --padding-section-small-m: 2rem;    /* 32 */
  /* Largeur de colonne de CONTENU centrée (ISO Figma « Max Width/max-width-large ») :
     cap de lecture des heros/intros centrés, plus étroit que --container-xl. */
  --max-width-large:         48rem;   /* 768 */
  /* Hauteurs du CHROME v2 (navbar-01, BRIEF-148) : barre desktop / mobile,
     valeurs de la maquette (72 / 64). */
  --navbar-height:           4.5rem;  /* 72 */
  --navbar-height-m:         4rem;    /* 64 */

  /* Logo client (BRIEF-32) — slot NORMALISÉ : hauteur fixe, largeur libre (jamais
     étiré). Tokens dédiés → placement cohérent quel que soit le ratio/format. */
  --logo-height:    2rem;    /* 32px — hauteur normalisée navbar/footer */
  --logo-max-width: 12rem;   /* 192px — garde-fou pour les logos très larges */

  /* ⚠️ Token DÉFINI MAIS NON UTILISÉ : le rythme vertical des sections est posé
     EN DIRECT dans les composants (`padding-block: var(--space-80/24/16)`).
     `--section-y` ne pilote rien aujourd'hui — ne pas croire qu'il le fait.
     (Standardiser le rythme vertical sur ce token = candidat à un futur lot.) */
  --section-y:     var(--space-128);
}

/* Jenie — Radius tokens
   Soft, modern corners. Cards ~12–16px, controls ~8–10px, pills full. */

:root {
  --radius-xs:   4px;
  --radius-sm:   6px;
  --radius-md:   8px;
  --radius-lg:   10px;
  --radius-xl:   12px;
  --radius-2xl:  16px;
  --radius-3xl:  24px;
  --radius-full: 999px;

  /* Semantic */
  --radius-control: var(--radius-md);
  --radius-card:    var(--radius-xl);
  --radius-panel:   var(--radius-2xl);
  --radius-pill:    var(--radius-full);

  /* Rayon du bouton — PILOTABLE par le Style Guide (presets boutons, BRIEF-51).
     Défaut = rayon de contrôle → rendu actuel inchangé ; surchargé par le moteur
     (`conceptCssVars`) sur le scope client uniquement. */
  --btn-radius: var(--radius-control);
}

/* Jenie — Elevation tokens
   Restrained, premium shadows. Soft, low-spread, cool-tinted. Never harsh.
   Layering relies on borders + tiny shadows rather than heavy drop shadows. */

:root {
  /* Cool shadow color base */
  --shadow-color: 264 25% 12%;

  --shadow-xs:  0 1px 2px hsl(var(--shadow-color) / 0.05);
  --shadow-sm:  0 1px 2px hsl(var(--shadow-color) / 0.06),
                0 1px 1px hsl(var(--shadow-color) / 0.04);
  --shadow-md:  0 2px 4px hsl(var(--shadow-color) / 0.05),
                0 4px 12px hsl(var(--shadow-color) / 0.06);
  --shadow-lg:  0 4px 8px hsl(var(--shadow-color) / 0.05),
                0 12px 28px hsl(var(--shadow-color) / 0.09);
  --shadow-xl:  0 8px 16px hsl(var(--shadow-color) / 0.06),
                0 24px 56px hsl(var(--shadow-color) / 0.12);

  /* Focus ring */
  --ring-width: 3px;
  --shadow-focus: 0 0 0 var(--ring-width) var(--ring-accent);

  /* Hairline border used as 1px elevation */
  --border-hairline: 1px solid var(--border-subtle);

  /* Accent glow (sparing — primary CTA, AI-active states) */
  --glow-accent: 0 1px 2px hsl(var(--shadow-color) / 0.10),
                 0 8px 24px color-mix(in oklch, var(--accent-500) 28%, transparent);

  /* Ombre du bouton primaire — PILOTABLE par le Style Guide (presets boutons,
     BRIEF-51). Défaut = glow accent → rendu actuel inchangé ; le preset « Brick »
     la remplace par une ombre dure (conceptCssVars, scope client). */
  --btn-shadow: var(--glow-accent);
}

/* Jenie — Motion tokens
   Calm, confident, quick. Mostly opacity + small translate/scale. No bounce on UI.
   Easing favors a gentle ease-out; springy only for delightful AI-generation moments. */

:root {
  --ease-out:     cubic-bezier(0.22, 1, 0.36, 1);    /* @kind other */
  --ease-in-out:  cubic-bezier(0.65, 0, 0.35, 1);    /* @kind other */
  --ease-standard:cubic-bezier(0.4, 0, 0.2, 1);      /* @kind other */
  /* delight only — springy entrance for AI-generation moments */
  --ease-spring:  cubic-bezier(0.34, 1.56, 0.64, 1); /* @kind other */

  --dur-fast:   120ms;  /* @kind other */
  --dur-base:   180ms;  /* @kind other */
  --dur-slow:   280ms;  /* @kind other */
  --dur-slower: 480ms;  /* @kind other */

  --transition-control: color var(--dur-fast) var(--ease-out),
                        background-color var(--dur-fast) var(--ease-out),
                        border-color var(--dur-fast) var(--ease-out),
                        box-shadow var(--dur-fast) var(--ease-out),
                        transform var(--dur-fast) var(--ease-out);
}

/* Jenie — Base resets + element defaults.
   Light, opinionated baseline so any page picks up the brand voice immediately. */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--body-leading);
  color: var(--text-body);
  background: var(--surface-page);
  font-feature-settings: 'cv01', 'ss01';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text-strong);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-snug);
}
h1 { font-size: var(--text-3xl); letter-spacing: var(--tracking-tighter); line-height: var(--leading-tight); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }

p { margin: 0; }
a { color: var(--text-accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

::selection {
  background: color-mix(in oklch, var(--accent-500) 22%, transparent);
  color: var(--text-strong);
}

/* Utility primitives */
/* Eyebrow/tagline ALIGNÉE sur la V2 Figma (« Heading/Tagline », décision
   Benjamin 16/7 — BRIEF-143) : 16 semibold, interligne 150 %, casse d'origine,
   couleur = rôle Texte fort. */
.jn-eyebrow {
  font-size: var(--text-regular);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-normal);
  color: var(--text-strong);
}
.jn-mono-label {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-subtle);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

.jn-canvas {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--body-leading);
  color: var(--text-body);
  background: var(--surface-page);
  text-align: left;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
.jn-canvas *,
.jn-canvas *::before,
.jn-canvas *::after { box-sizing: border-box; }
.jn-canvas h1,
.jn-canvas h2,
.jn-canvas h3,
.jn-canvas h4,
.jn-canvas p,
.jn-canvas figure,
.jn-canvas ul,
.jn-canvas ol { margin: var(--space-0); }
.jn-canvas ul,
.jn-canvas ol { padding: var(--space-0); list-style: none; }
.jn-canvas a { color: inherit; text-decoration: none; }
.jn-canvas img { display: block; max-width: 100%; height: auto; }
.jn-canvas button { font: inherit; cursor: pointer; }
/* Wrapper de RYTHME par section (B-SG-4b, SG-8) : le build/showcase enveloppe
   chaque section dans .jn-section portant les tokens de son schéma INLINE
   (conceptCssVars(concept, mode, scheme)). Bande PLEINE LARGEUR : un fond de
   repli au cas où une section ne peindrait pas son propre --surface-page
   (les sections actuelles le font déjà). Sans Concept, aucun .jn-section n'est
   émis -> comportement legacy inchangé.
   ⚠️ La bande est AUSSI un conteneur de requête nommé (BRIEF-140) : les règles
   @container posées sur la RACINE d'un composant (padding-block/min-height
   mobiles des sections v2) s'évaluent contre l'ANCÊTRE — la racine étant
   elle-même le conteneur de ses descendants, sans ceci elles ne matchaient
   JAMAIS. Même nom que les racines : les descendants continuent de mesurer la
   racine (plus proche), la racine mesure la bande (même largeur). */
.jn-canvas .jn-section { display: block; background: var(--surface-page); container: jn-section / inline-size; }

.jn-canvas .jn-section {
  /* Wrapper de schéma (BRIEF-53/60) = bande PLEINE LARGEUR : il porte le FOND et le
     texte du schéma (tokens inline), rien d'autre. Le PADDING (rythme vertical +
     gutter) appartient au COMPOSANT (.jn-c-X et son __inner) : le poser AUSSI ici
     doublait le padding (navbar/hero/footer décalés — régression visuelle pré-B60).
     Le display:block + fond de repli vivent dans le RESET (scope.ts). */
  background: var(--surface-page);
  color: var(--text-body);
}
.jn-canvas .jn-section--sunken { background: var(--surface-sunken); }
.jn-canvas .jn-section--inverse { background: var(--surface-inverse); color: var(--text-inverse); }
.jn-canvas .jn-section--accent { background: var(--surface-accent); color: var(--text-on-accent); }

/* Wrapper interne de section : plafonne le contenu (cap unique --container-max)
   et porte le gutter responsive (cqi). Posé sur un DESCENDANT de la racine-
   conteneur → le cqi du gutter mesure bien la largeur d'artboard (cf. spacing.css). */
.jn-canvas .jn-container { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-container--narrow { max-width: var(--container-md); } /* cap TEXTE étroit (lisibilité) */

/* --- Bibliothèque V2 (chantier sections) — règles HISSÉES (BRIEF-149) -------
   Wrapper interne des modules V2 : plafonne le contenu au conteneur 1280
   (--container-xl) SANS avaler les gutters — box-sizing oblige, le calc()
   ajoute les deux paddings au cap, sinon le contenu ferait 1152 au lieu des
   1280 maquette (bug corrigé au B142). Centre, et porte le gutter global
   (--padding-global, valeur -m en mobile). La RACINE du module garde le fond
   pleine largeur + le padding VERTICAL (piège cqi, cf. spacing.css).
   Chaque module V2 pose « jn-inner » sur son wrapper, à côté de sa classe
   « jn-c-<clé>__inner » qui ne garde que ses spécificités (position, width…). */
.jn-canvas .jn-inner { max-width: calc(var(--container-xl) + var(--padding-global) * 2); margin-inline: auto; padding-inline: var(--padding-global); }

/* Titre de SECTION V2 = style Figma « Heading/H2 » (protocole de passation §2).
   Partagé par les modules dont le titre ouvre une section de page (balise h2,
   règle 3.6 « balise ≠ style »). Les heros (h1) gardent le style display. */
.jn-canvas .jn-sectitle {
  font-size: var(--heading-2);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  color: var(--text-strong);
}

/* Valeurs MOBILES des règles V2 hissées (variante Mobile de la maquette). */
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-inner { padding-inline: var(--padding-global-m); }
  .jn-canvas .jn-sectitle { font-size: var(--heading-2-m); }
}

/* Eyebrow/tagline ALIGNÉE sur la V2 Figma (style « Heading/Tagline », décision
   Benjamin 16/7 — BRIEF-143) : 16 semibold, interligne 150 %, casse d'origine,
   couleur = rôle Texte. (Avant : petites capitales accentuées.) */
.jn-canvas .jn-eyebrow {
  display: block;
  font-size: var(--text-regular);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-normal);
  letter-spacing: var(--tracking-normal);
  color: var(--text-strong);
}

/* Police des TITRES = --display-font (BRIEF-30). Défaut = var(--font-sans) (cf.
   typography.css) → aucun changement aujourd'hui ; un système de DA peut basculer
   les titres sur une autre stack DISPONIBLE (ex. serif premium) sans toucher au
   HTML. Couvre toutes les sections (titres = vraies balises h1–h4). */
.jn-canvas h1, .jn-canvas h2, .jn-canvas h3, .jn-canvas h4 { font-family: var(--display-font); text-transform: var(--display-transform); }

.jn-canvas .jn-title {
  font-size: var(--text-2xl);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
  color: var(--text-strong);
}
.jn-canvas .jn-title--xl { font-size: var(--text-4xl); }
.jn-canvas .jn-lead {
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--text-muted);
}

/* Rayon / remplissage / ombre du bouton = TOKENS PILOTABLES par le Style Guide
   (presets UI Styling : Default · Bubble · Brick · Gradient — BRIEF-51). Les
   fallbacks reproduisent EXACTEMENT le comportement actuel → zéro régression tant
   qu'un Concept ne les surcharge pas (posés par conceptCssVars, DS « B »). */
.jn-canvas .jn-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-12);
  padding: var(--space-12) var(--space-24);
  border-radius: var(--btn-radius);
  font-size: var(--text-regular);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-normal);
  border: var(--border-hairline);
  transition: var(--transition-control);
}
/* Spec Bouton V2 (BRIEF-138, composant Figma Benjamin — protocole de passation) :
   texte 16 normal · padding 12/24 (small 12/16, icône seule 12) · bordure 1px
   sur TOUTES les variantes, couleur du FOND sur la primaire (règle « bordure =
   fond », les hovers ne font jamais sauter la mise en page). */
.jn-canvas .jn-btn--primary {
  background: var(--btn-fill);
  color: var(--text-on-accent);
  border-color: var(--btn-fill);
  box-shadow: var(--btn-shadow);
}
.jn-canvas .jn-btn--secondary {
  background: transparent;
  color: var(--text-strong);
  border-color: var(--border-default);
}
.jn-canvas .jn-btn--ghost {
  background: transparent;
  color: var(--text-strong);
  border-color: transparent;
}
/* Style=Link (spec V2, revue Benjamin 16/7) : lien d'action nu — zéro padding,
   zéro bordure, gap picto-texte = space-8 (SA valeur, modifiée le 16/7),
   chevron 24 « derrière » (Icon/chevron-right), texte = rôle Text du schéma. */
.jn-canvas .jn-btn--link {
  padding: 0;
  border: 0;
  background: transparent;
  gap: var(--space-8);
  color: var(--text-strong);
}
.jn-canvas .jn-btn--link .jn-btn__icon { width: var(--space-24); height: var(--space-24); flex: none; }
.jn-canvas .jn-btn--small { padding: var(--space-12) var(--space-16); }
.jn-canvas .jn-btn--icon-only { padding: var(--space-12); }
.jn-canvas .jn-btn--small.jn-btn--icon-only { padding: var(--space-8); }
/* Valeurs MOBILES de la maquette (modes des spacers V2) — bascule commune.
   (Le Link est identique aux deux tailles : padding 0 réaffirmé.) */
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-btn { padding: var(--space-8) var(--space-20); gap: var(--space-8); }
  .jn-canvas .jn-btn--small { padding: var(--space-8) var(--space-12); }
  .jn-canvas .jn-btn--icon-only, .jn-canvas .jn-btn--small.jn-btn--icon-only { padding: var(--space-8); }
  .jn-canvas .jn-btn--link { padding: 0; }
}
/* États interactifs (E17, BRIEF-43). La transition est déjà déclarée ci-dessus.
   Tokens DS uniquement (test no-hardcode) ; contraste AA conservé dans tous les
   systèmes DA. Hover = la surface « répond » (accent plus soutenu / réaction de
   surface / léger lift) ; focus-visible = anneau accent net (a11y clavier).
   S'applique éditeur ET site publié (CSS de composant partagé). */
.jn-canvas .jn-btn--primary:hover {
  background: var(--surface-accent-hover);
  border-color: var(--surface-accent-hover);
  box-shadow: var(--glow-accent), var(--shadow-md);
}
.jn-canvas .jn-btn--secondary:hover {
  background: var(--surface-sunken);
  border-color: var(--border-strong);
}
.jn-canvas .jn-btn--ghost:hover {
  background: var(--surface-accent-subtle);
}
/* Link : pas de surface qui répond (il n'en a pas) — le texte prend l'accent.
   Défaut moteur en attendant la passe d'états Figma de Benjamin. */
.jn-canvas .jn-btn--link:hover {
  background: transparent;
  color: var(--text-accent);
}
.jn-canvas .jn-btn:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

.jn-canvas .jn-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  color: var(--text-accent);
  font-weight: var(--weight-medium);
}

.jn-canvas .jn-ph {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-card);
  background: var(--surface-sunken);
  border: var(--border-hairline);
  color: var(--text-subtle);
}
.jn-canvas .jn-ph--square { aspect-ratio: 1 / 1; }
.jn-canvas .jn-ph--tall { aspect-ratio: 4 / 5; }
.jn-canvas .jn-ph--wide-flat { aspect-ratio: 16 / 7; }
.jn-canvas .jn-ph--round { border-radius: var(--radius-pill); }
.jn-canvas .jn-ph__icon { width: var(--space-40); height: var(--space-40); opacity: 0.5; }
/* Ajustement d'image (E2, BRIEF-42) : posé sur l'image reelle (le placeholder div
   n'a pas de contenu remplacable). cover recadre pour remplir, contain montre
   l'image entiere sans rogner. */
.jn-canvas img.jn-ph--fit-cover { object-fit: cover; }
.jn-canvas img.jn-ph--fit-contain { object-fit: contain; }

/* Logo client = placeholder wordmark Jenie mono (BRIEF-28, W2-9) : la VRAIE marque
   officielle = glyphe « J » (JenieMark) + « enie » (aligné sur JenieWordmark : Geist
   Bold, tracking serré), en une teinte discrète → mur de logos cohérent, jamais de
   faux logo tiers. currentColor → re-thématisable (neutre/DA). Le « enie » suit la
   cap-height du J (~1.27× ⇒ J = 0.79em du wordmark) ; alignement sur la ligne de base. */
.jn-canvas .jn-logo { display: inline-flex; align-items: baseline; color: var(--text-subtle); font-size: var(--text-xl); }
.jn-canvas .jn-logo__mark { height: 0.79em; width: auto; flex: none; }
.jn-canvas .jn-logo__name { font-weight: var(--weight-bold); letter-spacing: var(--tracking-tighter); }

/* Logo RÉEL du client (BRIEF-32) : slot NORMALISÉ — hauteur fixe (--logo-height),
   largeur libre plafonnée, ratio préservé (object-fit: contain) → JAMAIS étiré,
   quel que soit le format/ratio. Sur surface sombre (footer), le logo est posé sur
   une PASTILLE claire (jn-logo-chip) → toujours lisible, jamais invisible. */
.jn-canvas .jn-logo-img {
  display: block;
  height: var(--logo-height);
  width: auto;
  max-width: var(--logo-max-width);
  object-fit: contain;
}
.jn-canvas .jn-logo-chip {
  display: inline-flex;
  align-items: center;
  background: var(--surface-card);
  padding: var(--space-8) var(--space-12);
  border-radius: var(--radius-md);
}

/* Racine = conteneur + fond pleine largeur. La barre porte .jn-container
   (max-width --container-max + margin auto + gutter cqi, modèle BRIEF-26). */
.jn-canvas .jn-c-navbar { container: jn-section / inline-size; background: var(--surface-page); border-bottom: var(--border-hairline); }
.jn-canvas .jn-c-navbar__bar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-24); row-gap: var(--space-12); padding-block: var(--space-16); }
.jn-canvas .jn-c-navbar__logo { font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-strong); }
.jn-canvas .jn-c-navbar__panel { display: flex; align-items: center; gap: var(--space-32); margin-inline-start: auto; min-width: 0; }
.jn-canvas .jn-c-navbar__list { justify-content: flex-end; }
.jn-canvas .jn-c-navbar__cta { flex: none; }
@container jn-section (max-width: 48rem) {
  /* Tablette + mobile (W2-8) : burger à droite ; panneau pleine largeur sous la barre. */
  .jn-canvas .jn-c-navbar .jn-c-nav-burger { margin-inline-start: auto; }
  .jn-canvas .jn-c-navbar__panel { flex-basis: 100%; margin-inline-start: 0; align-items: stretch; }
}

/* Logo IMAGE sur bande sombre (BRIEF-91) : pastille claire TOKEN-DRIVEN — les
   tokens --logo-chip-* ne sont émis par conceptCssVars QUE sur les bandes
   profondes (fort/contraste/accent), ex. navbar d'ouverture « bande ». Bande
   claire → fallbacks inertes (transparent, 0) = rendu strictement identique.
   Mécanisme du footer (jn-logo-chip) porté par l'<img> elle-même, zéro HTML.
   content-box : le padding de la pastille s'ajoute AUTOUR du logo (hauteur
   normalisée --logo-height préservée, comme le span chip du footer). */
.jn-canvas [data-jn-nav] .jn-logo-img {
  background: var(--logo-chip-bg, transparent);
  padding: var(--logo-chip-pad, 0);
  border-radius: var(--logo-chip-radius, 0);
  box-sizing: content-box;
}
.jn-canvas .jn-c-nav__list { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-8); row-gap: var(--space-4); }
.jn-canvas .jn-c-nav__item { position: relative; max-width: 100%; }
.jn-canvas .jn-c-nav__link {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  gap: var(--space-4);
  padding: var(--space-8) var(--space-12);
  border-radius: var(--radius-control);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--text-body);
  background: transparent;
  border: var(--border-hairline);
  border-color: transparent;
}
.jn-canvas .jn-c-nav__link:hover { color: var(--text-accent); background: var(--surface-accent-subtle); }
/* Libellé : labels longs (noms de page complets) tronqués proprement (W1-7). */
.jn-canvas .jn-c-nav__label { display: block; max-width: 18ch; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.jn-canvas .jn-c-nav__caret { width: var(--space-16); height: var(--space-16); }
.jn-canvas .jn-c-nav__submenu {
  position: absolute;
  inset-inline-start: 0;
  margin-block-start: var(--space-8);
  min-width: var(--container-sm);
  max-width: var(--container-sm);
  display: none;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-8);
  background: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-lg);
}
.jn-canvas .jn-c-nav__item--has-menu:hover .jn-c-nav__submenu,
.jn-canvas .jn-c-nav__item--has-menu:focus-within .jn-c-nav__submenu { display: flex; }
.jn-canvas .jn-c-nav__submenu .jn-c-nav__link { border-radius: var(--radius-control); }

/* --- Burger (mobile) — caché en desktop ; le panneau se replie derrière lui
   UNIQUEMENT quand le JS publié a posé [data-jn-nav-on] (sinon panneau visible
   = progressive enhancement). --- */
.jn-canvas .jn-c-nav-burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--space-40);
  height: var(--space-40);
  border-radius: var(--radius-control);
  border: var(--border-hairline);
  border-color: transparent;
  background: transparent;
  color: var(--text-strong);
  flex: none;
}
.jn-canvas .jn-c-nav-burger:hover { background: var(--surface-accent-subtle); color: var(--text-accent); }
.jn-canvas .jn-c-nav-burger svg { width: var(--space-24); height: var(--space-24); }
/* Burger au seuil MEDIUM (~768px) : repli dès la TABLETTE et en mobile (W2-8) —
   en tablette/mobile la nav passe en burger ; desktop garde les liens inline. */
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-c-nav-burger { display: inline-flex; }
  .jn-canvas [data-jn-nav-menu] { flex-direction: column; align-items: stretch; width: 100%; gap: var(--space-8); }
  .jn-canvas .jn-c-nav__list { flex-direction: column; align-items: stretch; }
  .jn-canvas [data-jn-nav-on] [data-jn-nav-menu] { display: none; }
  .jn-canvas [data-jn-nav-on][data-jn-nav-open] [data-jn-nav-menu] { display: flex; }
  /* Sous-menu en mobile : déplié en place (pas de dropdown flottant). */
  .jn-canvas .jn-c-nav__submenu { position: static; min-width: 0; max-width: none; display: flex; padding-inline-start: var(--space-16); border: none; box-shadow: none; background: transparent; }
}

/* Racine = conteneur + fond pleine largeur ; gutter (cqi) porté par le wrapper interne. */
.jn-canvas .jn-c-footer { container: jn-section / inline-size; padding-block: var(--section-pad-dense, var(--space-64)); background: var(--surface-page); color: var(--text-body); }
.jn-canvas .jn-c-footer__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); display: flex; flex-direction: column; gap: var(--space-48); }
.jn-canvas .jn-c-footer__top { display: grid; grid-template-columns: 2fr 3fr; gap: var(--space-48); }
.jn-canvas .jn-c-footer--simple .jn-c-footer__top { grid-template-columns: 1fr; gap: var(--space-32); }
@container jn-section (max-width: 48rem) { .jn-canvas .jn-c-footer__top { grid-template-columns: 1fr; gap: var(--space-40); } }

.jn-canvas .jn-c-footer__brand { display: flex; flex-direction: column; gap: var(--space-12); }
.jn-canvas .jn-c-footer__logo { font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-strong); }
.jn-canvas .jn-c-footer__tagline { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-body); max-width: var(--container-sm); }

.jn-canvas .jn-c-footer__groups { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-32); }
.jn-canvas .jn-c-footer--simple .jn-c-footer__groups { grid-template-columns: 1fr; }
@container jn-section (max-width: 36rem) { .jn-canvas .jn-c-footer__groups { grid-template-columns: repeat(2, 1fr); } }
.jn-canvas .jn-c-footer__group { display: flex; flex-direction: column; gap: var(--space-12); }
.jn-canvas .jn-c-footer--simple .jn-c-footer__group { flex-direction: row; flex-wrap: wrap; gap: var(--space-20); align-items: center; }
.jn-canvas .jn-c-footer__group-title { font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--eyebrow-tracking); text-transform: uppercase; color: var(--text-muted); }
.jn-canvas .jn-c-footer--simple .jn-c-footer__group-title { display: none; }
.jn-canvas .jn-c-footer__link { font-size: var(--text-base); color: var(--text-body); }
.jn-canvas .jn-c-footer__link:hover { color: var(--text-strong); text-decoration: underline; text-underline-offset: var(--space-4); }

.jn-canvas .jn-c-footer__bottom { display: flex; flex-wrap: wrap; gap: var(--space-16); align-items: center; justify-content: space-between; padding-block-start: var(--space-32); border-top: var(--border-hairline); }
.jn-canvas .jn-c-footer__copyright { font-size: var(--text-sm); color: var(--text-muted); }
.jn-canvas .jn-c-footer__social { display: flex; gap: var(--space-8); }
.jn-canvas .jn-c-footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-40);
  height: var(--space-40);
  border-radius: var(--radius-pill);
  border: var(--border-hairline);
  color: var(--text-body);
}
.jn-canvas .jn-c-footer__social-link:hover { color: var(--text-strong); border-color: var(--border-accent); }
.jn-canvas .jn-c-footer__social-link svg { width: var(--space-20); height: var(--space-20); }

/* Racine = conteneur + fond pleine largeur (PAS de padding-inline : le gutter,
   en cqi, est porté par le wrapper interne — cf. piège cqi, spacing.css). */
.jn-canvas .jn-c-hero { container: jn-section / inline-size; padding-block: var(--section-pad-hero, var(--space-96)); background: var(--surface-page); }
/* Fond plein = token de DÉGRADÉ sémantique (--surface-gradient). Défaut PLAT
   (= --surface-inverse) → neutre/DA-exemple inchangés ; un système de DA y pose
   un vrai dégradé oklch. Jamais de gradient brut ici (dérivé de la palette). */
/* Plein-sombre : fond sombre porté PAR LE COMPOSANT (pas le schéma) → (1) rythme
   vertical resserré (sans image = sinon trop de vide) ; (2) glow ÉTEINT localement
   car le garde moteur ne voit que le schéma de bande, pas ce fond sombre (BRIEF-63).
   B91-1 : sur une bande PROFONDE (fort/contraste/accent), les tokens
   --hero-plein-sombre-* (émis par conceptCssVars) font RETOMBER la variante sur
   le rendu bande standard : aplat + couleurs propres redondants sur une bande,
   titre sinon invisible. Bande claire → tokens absents, fallbacks = rendu legacy. */
.jn-canvas .jn-c-hero--plein-sombre {
  background: var(--hero-plein-sombre-bg, var(--surface-gradient));
  color: var(--hero-plein-sombre-tx, var(--text-inverse));
  padding-block: var(--section-pad-tight, var(--space-64));
  --glow-accent: none;
}
.jn-canvas .jn-c-hero__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-hero__copy { display: flex; flex-direction: column; gap: var(--space-20); }
.jn-canvas .jn-c-hero__title {
  font-size: var(--text-4xl);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: var(--display-leading);
  color: var(--text-strong);
}
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__title { color: var(--hero-plein-sombre-title, var(--text-on-accent)); }
.jn-canvas .jn-c-hero__subtitle { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); max-width: var(--container-sm); }
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__subtitle { color: var(--hero-plein-sombre-tx, var(--text-inverse)); }
/* Eyebrow sur fond plein : --text-accent (pensé pour fond CLAIR) deviendrait
   illisible sur le sombre → on bascule sur --text-inverse (le texte de la surface
   inverse du thème : foncé au neutre clair, clair en DA sombre). AA garanti. */
.jn-canvas .jn-c-hero--plein-sombre .jn-eyebrow { color: var(--hero-plein-sombre-eyebrow, var(--text-inverse)); }
.jn-canvas .jn-c-hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-12); margin-block-start: var(--space-8); }

/* Variante centré */
.jn-canvas .jn-c-hero--centre .jn-c-hero__inner,
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__inner { max-width: var(--container-md); text-align: center; }
.jn-canvas .jn-c-hero--centre .jn-c-hero__copy,
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__copy { align-items: center; }
.jn-canvas .jn-c-hero--centre .jn-c-hero__subtitle,
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__subtitle { max-width: var(--container-sm); }
.jn-canvas .jn-c-hero--centre .jn-c-hero__actions,
.jn-canvas .jn-c-hero--plein-sombre .jn-c-hero__actions { justify-content: center; }
.jn-canvas .jn-c-hero--centre .jn-c-hero__media { margin-block-start: var(--space-48); }

/* Variante 2 colonnes */
.jn-canvas .jn-c-hero--deux-colonnes .jn-c-hero__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-64);
  align-items: center;
}
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-c-hero--deux-colonnes .jn-c-hero__inner { grid-template-columns: 1fr; gap: var(--space-48); }
}

/* Racine = conteneur + fond pleine largeur ; gutter (cqi) porté par le wrapper interne. */
.jn-canvas .jn-c-about { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-page); }
.jn-canvas .jn-c-about__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-about--texte-image .jn-c-about__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-64);
  align-items: center;
}
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-c-about--texte-image .jn-c-about__inner { grid-template-columns: 1fr; gap: var(--space-48); }
}
.jn-canvas .jn-c-about--texte .jn-c-about__inner { max-width: var(--container-md); }
.jn-canvas .jn-c-about__copy { display: flex; flex-direction: column; gap: var(--space-16); }
.jn-canvas .jn-c-about__title { font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-about__text { font-size: var(--text-md); line-height: var(--leading-relaxed); color: var(--text-body); }
.jn-canvas .jn-c-about__stats { display: flex; flex-wrap: wrap; gap: var(--space-32); margin-block-start: var(--space-16); }
.jn-canvas .jn-c-about__stat { display: flex; flex-direction: column; gap: var(--space-4); }
.jn-canvas .jn-c-about__stat-value { font-size: var(--text-3xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tight); color: var(--text-accent); }
.jn-canvas .jn-c-about__stat-label { font-size: var(--text-sm); color: var(--text-muted); }

/* Racine = conteneur + fond pleine largeur ; gutter (cqi) porté par le wrapper interne. */
.jn-canvas .jn-c-proof { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-sunken); }
.jn-canvas .jn-c-proof__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-proof__head { display: flex; flex-direction: column; gap: var(--space-12); align-items: center; text-align: center; max-width: var(--container-md); margin-inline: auto; margin-block-end: var(--space-48); }
.jn-canvas .jn-c-proof__title { font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-proof__grid { display: grid; gap: var(--space-24); grid-template-columns: repeat(3, 1fr); }
@container jn-section (max-width: 48rem) { .jn-canvas .jn-c-proof__grid { grid-template-columns: 1fr; } }
.jn-canvas .jn-c-proof__card {
  display: flex;
  flex-direction: column;
  gap: var(--space-20);
  padding: var(--space-24);
  background: var(--surface-card);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-sm);
}
.jn-canvas .jn-c-proof__quote { font-size: var(--text-md); line-height: var(--leading-relaxed); color: var(--text-body); }
.jn-canvas .jn-c-proof__person { display: flex; align-items: center; gap: var(--space-12); margin-block-start: auto; }
.jn-canvas .jn-c-proof__avatar { width: var(--space-48); height: var(--space-48); }
.jn-canvas .jn-c-proof__author { display: block; font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--text-strong); }
.jn-canvas .jn-c-proof__role { display: block; font-size: var(--text-sm); color: var(--text-muted); }

.jn-canvas .jn-c-chiffres-bento { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-page); }
.jn-canvas .jn-c-chiffres-bento__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-chiffres-bento__head { display: grid; grid-template-columns: 3fr 2fr; gap: var(--space-48); align-items: end; margin-block-end: var(--space-48); }
@container jn-section (max-width: 48rem) { .jn-canvas .jn-c-chiffres-bento__head { grid-template-columns: 1fr; gap: var(--space-24); align-items: start; } }
.jn-canvas .jn-c-chiffres-bento__head-main { display: flex; flex-direction: column; gap: var(--space-12); }
.jn-canvas .jn-c-chiffres-bento__heading { font-size: var(--text-3xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-chiffres-bento__head-aside { display: flex; flex-direction: column; gap: var(--space-20); }
.jn-canvas .jn-c-chiffres-bento__subtitle { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); }
.jn-canvas .jn-c-chiffres-bento__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-16); }
.jn-canvas .jn-c-chiffres-bento__link { display: inline-flex; align-items: center; gap: var(--space-8); color: var(--text-accent); font-weight: var(--weight-medium); }
.jn-canvas .jn-c-chiffres-bento__link svg { width: var(--space-16); height: var(--space-16); }

/* Mosaïque fixe : 3 colonnes × 2 lignes — stat1 haute à gauche, image1+stat2 au
   centre, stat3+image2 à droite. */
.jn-canvas .jn-c-chiffres-bento__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-16); }
.jn-canvas .jn-c-chiffres-bento__cell { border-radius: var(--radius-card); overflow: hidden; }
.jn-canvas .jn-c-chiffres-bento__cell--stat1 { grid-column: 1; grid-row: 1 / 3; }
.jn-canvas .jn-c-chiffres-bento__cell--image1 { grid-column: 2; grid-row: 1; }
.jn-canvas .jn-c-chiffres-bento__cell--stat2 { grid-column: 2; grid-row: 2; }
.jn-canvas .jn-c-chiffres-bento__cell--stat3 { grid-column: 3; grid-row: 1; }
.jn-canvas .jn-c-chiffres-bento__cell--image2 { grid-column: 3; grid-row: 2; }
.jn-canvas .jn-c-chiffres-bento__cell--img { display: flex; }
.jn-canvas .jn-c-chiffres-bento__cell--img .jn-ph { width: 100%; height: 100%; aspect-ratio: auto; }
.jn-canvas .jn-c-chiffres-bento__stat { display: flex; flex-direction: column; justify-content: center; gap: var(--space-8); height: 100%; padding: var(--space-32); background: var(--surface-card); border: var(--border-hairline); }
.jn-canvas .jn-c-chiffres-bento__cell--stat1 .jn-c-chiffres-bento__stat { background: var(--surface-sunken); }
.jn-canvas .jn-c-chiffres-bento__value { font-size: var(--text-5xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-tighter); line-height: var(--leading-tight); color: var(--text-strong); overflow-wrap: anywhere; }
.jn-canvas .jn-c-chiffres-bento__cell--stat1 .jn-c-chiffres-bento__value { font-size: var(--text-5xl); }
.jn-canvas .jn-c-chiffres-bento__label { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-muted); }
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-c-chiffres-bento__grid { grid-template-columns: 1fr; }
  .jn-canvas .jn-c-chiffres-bento__cell { grid-column: auto; grid-row: auto; }
  .jn-canvas .jn-c-chiffres-bento__cell--img .jn-ph { aspect-ratio: 16 / 9; height: auto; }
}

/* Racine = conteneur + fond pleine largeur (pas de padding-inline : piège cqi).
   Cas particulier : __inner est une CARTE (fond/bordure/rayon). Le gutter (cqi)
   et le cap --container-max sont portés par __bounds (descendant de la racine-
   conteneur) qui INSÈRE la carte des bords → la carte reste contenue, jamais
   collée aux bords (pas de full-bleed à coins arrondis edge-to-edge). */
.jn-canvas .jn-c-cta { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-64)); background: var(--surface-page); }
.jn-canvas .jn-c-cta__bounds { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-cta__inner {
  padding: var(--space-48);
  border-radius: var(--radius-panel);
  background: var(--surface-sunken);
  border: var(--border-hairline);
}
/* Carte d'accent = token de DÉGRADÉ sémantique (--gradient-accent). Défaut PLAT
   (= --surface-accent) → neutre/DA-exemple inchangés ; un système de DA y pose un
   vrai dégradé oklch dérivé de la palette (le « whoua » visible). */
.jn-canvas .jn-c-cta--accent .jn-c-cta__inner { background: var(--gradient-accent); border-color: var(--border-accent); box-shadow: var(--glow-accent); }
.jn-canvas .jn-c-cta__copy { display: flex; flex-direction: column; gap: var(--space-12); }
.jn-canvas .jn-c-cta__title { font-size: var(--text-3xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-cta--accent .jn-c-cta__title { color: var(--text-on-accent); }
.jn-canvas .jn-c-cta__subtitle { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); }
.jn-canvas .jn-c-cta--accent .jn-c-cta__subtitle { color: var(--text-on-accent); }
.jn-canvas .jn-c-cta__actions { display: flex; flex-wrap: wrap; gap: var(--space-12); }

/* Pleine largeur : empilé, centré */
.jn-canvas .jn-c-cta--pleine-largeur .jn-c-cta__inner { display: flex; flex-direction: column; gap: var(--space-32); align-items: center; text-align: center; }
.jn-canvas .jn-c-cta--pleine-largeur .jn-c-cta__copy { align-items: center; max-width: var(--container-md); }
.jn-canvas .jn-c-cta--pleine-largeur .jn-c-cta__actions { justify-content: center; }

/* 2 colonnes : texte / actions */
.jn-canvas .jn-c-cta--deux-colonnes .jn-c-cta__inner { display: grid; grid-template-columns: 1fr auto; gap: var(--space-40); align-items: center; }
@container jn-section (max-width: 48rem) { .jn-canvas .jn-c-cta--deux-colonnes .jn-c-cta__inner { grid-template-columns: 1fr; } }

/* Sur fond accent : primaire = surface claire (texte accent), secondaire = contour clair */
.jn-canvas .jn-c-cta--accent .jn-btn--primary { background: var(--surface-card); color: var(--text-accent); border-color: transparent; box-shadow: var(--shadow-sm); }
.jn-canvas .jn-c-cta--accent .jn-btn--secondary { background: transparent; color: var(--text-on-accent); border-color: var(--text-on-accent); }
/* Hover dans CE contexte inversé (E17, BRIEF-43) : on REDÉFINIT le survol ici
   (spécificité 0,3,0) sinon la surcharge contextuelle ci-dessus l'emporterait sur
   le hover de base. AA conservé (texte accent sur surface claire / texte accent
   sur blanc plein). */
.jn-canvas .jn-c-cta--accent .jn-btn--primary:hover { background: var(--surface-sunken); border-color: transparent; }
.jn-canvas .jn-c-cta--accent .jn-btn--secondary:hover { background: var(--text-on-accent); color: var(--text-accent); }

.jn-canvas .jn-c-corps-texte { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-page); }
.jn-canvas .jn-c-corps-texte__inner { margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-corps-texte__inner--lecture { max-width: var(--container-md); }
.jn-canvas .jn-c-corps-texte__inner--large { max-width: var(--container-max); }
.jn-canvas .jn-c-corps-texte__title { font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); margin-block-end: var(--space-24); }
.jn-canvas .jn-c-corps-texte__body { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-body); }
.jn-canvas .jn-c-corps-texte__body > * + * { margin-block-start: var(--space-16); }
.jn-canvas .jn-c-corps-texte__body h3 { font-size: var(--text-xl); font-weight: var(--weight-semibold); letter-spacing: var(--heading-tracking); color: var(--text-strong); margin-block-start: var(--space-32); }
.jn-canvas .jn-c-corps-texte__body h4 { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--text-strong); margin-block-start: var(--space-24); }
.jn-canvas .jn-c-corps-texte__body ul { padding-inline-start: var(--space-20); list-style: disc; }
.jn-canvas .jn-c-corps-texte__body li + li { margin-block-start: var(--space-8); }
.jn-canvas .jn-c-corps-texte__body a { color: var(--text-accent); text-decoration: underline; }
.jn-canvas .jn-c-corps-texte__body strong { font-weight: var(--weight-semibold); color: var(--text-strong); }

/* Racine = conteneur + fond pleine largeur ; gutter (cqi) porté par __inner. */
.jn-canvas .jn-c-process { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-page); }
.jn-canvas .jn-c-process__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-process__head { display: flex; flex-direction: column; gap: var(--space-12); max-width: var(--container-md); margin-block-end: var(--space-48); }
.jn-canvas .jn-c-process__title { font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-process__subtitle { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); }

/* Liste d'étapes — base commune */
.jn-canvas .jn-c-process__steps { display: grid; gap: var(--space-32); }
.jn-canvas .jn-c-process__step { position: relative; display: grid; gap: var(--space-12); }

/* Pastille numéro = élément d'emphase (pas une carte de contenu) */
.jn-canvas .jn-c-process__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-48);
  height: var(--space-48);
  border-radius: var(--radius-pill);
  background: var(--surface-accent-subtle);
  color: var(--text-accent);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  flex: none;
}
.jn-canvas .jn-c-process__step-title { font-size: var(--text-lg); font-weight: var(--weight-semibold); letter-spacing: var(--heading-tracking); color: var(--text-strong); overflow-wrap: anywhere; hyphens: auto; }
.jn-canvas .jn-c-process__desc { font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-muted); }

/* --- VERTICAL : numéro à gauche, texte à droite, connecteur = trait vertical --- */
.jn-canvas .jn-c-process--vertical .jn-c-process__step { grid-template-columns: auto 1fr; column-gap: var(--space-24); align-items: start; }
.jn-canvas .jn-c-process--vertical .jn-c-process__body { display: grid; gap: var(--space-8); }
/* Connecteur : trait sous la pastille reliant à l'étape suivante (pas sur la dernière).
   Épaisseur en 2px brut (non thématique → toléré no-hardcode ; pas de token DS d'épaisseur). */
.jn-canvas .jn-c-process--vertical.jn-c-process--connected .jn-c-process__step:not(:last-child) .jn-c-process__num::after {
  content: "";
  position: absolute;
  inset-block-start: var(--space-48);
  inset-block-end: calc(var(--space-32) * -1);
  inline-size: 2px;
  background: var(--border-default);
}

/* --- HORIZONTAL : étapes en rangée, connecteur = trait horizontal entre pastilles --- */
.jn-canvas .jn-c-process--horizontal .jn-c-process__steps { grid-auto-flow: column; grid-auto-columns: 1fr; gap: var(--space-24); }
.jn-canvas .jn-c-process--horizontal .jn-c-process__step { grid-template-rows: auto 1fr; row-gap: var(--space-16); }
.jn-canvas .jn-c-process--horizontal.jn-c-process--connected .jn-c-process__step:not(:last-child) .jn-c-process__num::after {
  content: "";
  position: absolute;
  inset-inline-start: var(--space-48);
  inset-inline-end: calc(var(--space-24) * -1);
  inset-block-start: calc(var(--space-48) / 2);
  block-size: 2px;
  background: var(--border-default);
}
/* Horizontal → vertical empilé sous CQ.medium (les colonnes deviennent une pile). */
@container jn-section (max-width: 48rem) {
  .jn-canvas .jn-c-process--horizontal .jn-c-process__steps { grid-auto-flow: row; grid-auto-columns: auto; }
  .jn-canvas .jn-c-process--horizontal .jn-c-process__step { grid-template-columns: auto 1fr; grid-template-rows: none; column-gap: var(--space-24); }
  /* en pile, le connecteur horizontal n'a plus de sens → on le neutralise */
  .jn-canvas .jn-c-process--horizontal.jn-c-process--connected .jn-c-process__step:not(:last-child) .jn-c-process__num::after { content: none; }
}

/* Racine = conteneur + fond pleine largeur ; gutter (cqi) porté par le wrapper interne. */
.jn-canvas .jn-c-contact { container: jn-section / inline-size; padding-block: var(--section-pad, var(--space-80)); background: var(--surface-page); }
.jn-canvas .jn-c-contact__inner { max-width: var(--container-max); margin-inline: auto; padding-inline: var(--gutter); }
.jn-canvas .jn-c-contact__head { display: flex; flex-direction: column; gap: var(--space-12); max-width: var(--container-md); margin-block-end: var(--space-48); }
.jn-canvas .jn-c-contact__title { font-size: var(--text-2xl); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: var(--display-leading); color: var(--text-strong); }
.jn-canvas .jn-c-contact__intro { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); }
.jn-canvas .jn-c-contact__cols { display: grid; grid-template-columns: 3fr 2fr; gap: var(--space-48); align-items: start; }
.jn-canvas .jn-c-contact__cols--single { grid-template-columns: 1fr; }
@container jn-section (max-width: 48rem) { .jn-canvas .jn-c-contact__cols { grid-template-columns: 1fr; gap: var(--space-40); } }

.jn-canvas .jn-c-contact__form { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-16); }
.jn-canvas .jn-c-contact__field { display: flex; flex-direction: column; gap: var(--space-8); }
.jn-canvas .jn-c-contact__field--wide { grid-column: 1 / -1; }
.jn-canvas .jn-c-contact__label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-body); }
.jn-canvas .jn-c-contact__input,
.jn-canvas .jn-c-contact__textarea {
  width: 100%;
  padding: var(--space-12) var(--space-16);
  font: inherit;
  font-size: var(--text-base);
  color: var(--text-strong);
  background: var(--surface-card);
  border: var(--border-hairline);
  border-color: var(--border-default);
  border-radius: var(--radius-control);
}
.jn-canvas .jn-c-contact__textarea { min-height: var(--space-128); resize: vertical; }
/* Liste déroulante (E15) : même peau que les inputs (tokens, AA garanti par le moteur). */
.jn-canvas .jn-c-contact__select {
  width: 100%;
  padding: var(--space-12) var(--space-16);
  font: inherit;
  font-size: var(--text-base);
  color: var(--text-strong);
  background: var(--surface-card);
  border: var(--border-hairline);
  border-color: var(--border-default);
  border-radius: var(--radius-control);
}
/* Case à cocher (E15) : rangée horizontale pleine largeur, coche aux couleurs du site. */
.jn-canvas .jn-c-contact__field--check { flex-direction: row; align-items: center; gap: var(--space-12); }
.jn-canvas .jn-c-contact__checkbox { width: var(--space-20); height: var(--space-20); flex: none; accent-color: var(--text-accent); }
/* Widget anti-robots optionnel (inerte sans clé — BRIEF-101). */
.jn-canvas .jn-c-contact__captcha { grid-column: 1 / -1; }
.jn-canvas .jn-c-contact__submit { grid-column: 1 / -1; }

.jn-canvas .jn-c-contact__aside { display: flex; flex-direction: column; gap: var(--space-24); }
.jn-canvas .jn-c-contact__coords { display: flex; flex-direction: column; gap: var(--space-12); }
.jn-canvas .jn-c-contact__coord { display: flex; flex-direction: column; gap: var(--space-4); }
.jn-canvas .jn-c-contact__coord-label { font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--eyebrow-tracking); text-transform: uppercase; color: var(--text-subtle); }
.jn-canvas .jn-c-contact__coord-value { font-size: var(--text-md); color: var(--text-body); }
.jn-canvas .jn-c-contact__hours { display: flex; flex-direction: column; gap: var(--space-8); }
.jn-canvas .jn-c-contact__hour { display: flex; justify-content: space-between; gap: var(--space-16); font-size: var(--text-base); }
.jn-canvas .jn-c-contact__hour-day { color: var(--text-body); }
.jn-canvas .jn-c-contact__hour-time { color: var(--text-muted); }
.jn-canvas .jn-c-contact__map {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  width: 100%;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-card);
  background: var(--surface-sunken);
  border: var(--border-hairline);
  color: var(--text-subtle);
  font-size: var(--text-sm);
}
.jn-canvas .jn-c-contact__map svg { width: var(--space-24); height: var(--space-24); }

.jn-canvas .jn-c-contact__req { color: var(--text-accent); margin-inline-start: var(--space-4); font-weight: var(--weight-semibold); }
/* HONEYPOT (BRIEF-68) : hors écran, jamais display:none (certains bots l'évitent). */
.jn-canvas .jn-c-contact__hp { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }
/* Statut d'envoi (succès/erreur) — hérite des tokens de la section. */
.jn-canvas .jn-c-contact__status { grid-column: 1 / -1; margin: 0; font-size: var(--text-base); line-height: var(--leading-relaxed); color: var(--text-strong); }
.jn-canvas .jn-c-contact__status[data-jn-form-err] { color: var(--text-accent); }

/* === Animation d'entrée au scroll — aperçu/build uniquement (BRIEF-63) === */
/* Repli : sans la classe d'armement (JS absent/échoué), TOUT reste visible. */
@media (prefers-reduced-motion: no-preference) {
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section {
    opacity: 0;
    transform: translateY(1.25rem);
    transition: opacity var(--dur-slower) var(--ease-out),
                transform var(--dur-slower) var(--ease-out);
    transition-delay: calc(var(--jn-i, 0) * 60ms);
    will-change: opacity, transform;
  }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in {
    opacity: 1;
    transform: none;
  }
  /* Stagger INTRA-section (grilles/étapes/paliers) : enfants directs du conteneur.
     Générique → aucun composant à modifier. Léger, plafonné (5 pas). */
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *,
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *,
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *,
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > * {
    animation: jn-rise var(--dur-slow) var(--ease-out) both;
  }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *:nth-child(1),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *:nth-child(1),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *:nth-child(1),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > *:nth-child(1) { animation-delay: 0.04s; }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *:nth-child(2),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *:nth-child(2),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *:nth-child(2),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > *:nth-child(2) { animation-delay: 0.12s; }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *:nth-child(3),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *:nth-child(3),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *:nth-child(3),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > *:nth-child(3) { animation-delay: 0.20s; }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *:nth-child(4),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *:nth-child(4),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *:nth-child(4),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > *:nth-child(4) { animation-delay: 0.28s; }
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__grid"] > *:nth-child(n+5),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__steps"] > *:nth-child(n+5),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__cards"] > *:nth-child(n+5),
  .jn-canvas.jn-anim-armed[data-jn-anim] .jn-section.jn-in [class*="__tiers"] > *:nth-child(n+5) { animation-delay: 0.34s; }

  @keyframes jn-rise {
    from { opacity: 0; transform: translateY(0.75rem); }
    to   { opacity: 1; transform: none; }
  }
}
/* prefers-reduced-motion: reduce → AUCUNE règle ci-dessus n'existe : contenu
   visible, zéro mouvement (pas de fenêtre de flash). */