/* ==========================================================================
   nova-content.css — Rendu PUBLIC du contenu NOVA
   --------------------------------------------------------------------------
   NOVA V3, lot 1 (2026-08-07).

   ⚠️ NE PAS CONFONDRE AVEC nova/nova.css, qui habille l'ÉDITEUR dans le
   back-office. Cette feuille-ci habille ce que voit le VISITEUR (page de vente)
   et l'ÉLÈVE (page de cours). Deux fichiers, deux publics, aucun partage.

   POURQUOI ELLE EXISTE
   Jusqu'ici, includes/nova_renderer.php écrivait ses styles en dur dans des
   attributs style="". Un attribut de style bat toujours une feuille : aucune
   variable, aucun thème, aucune palette ne pouvait donc reprendre la main. Le
   projet demandait « une autre allure pour les pages de vente » et la réponse
   était structurellement impossible, quel que soit le CSS écrit à côté.

   Le renderer produit maintenant des classes, et tout se décide ici.

   DEUX MODES, DÉCIDÉS PAR LA SURFACE (jamais stockés dans le contenu)
     .nova--landing    pages de vente : large, sections pleine largeur, palette
                       propre. Le visiteur n'a pas de préférence de thème chez
                       nous, la page assume son identité.
     .nova--document   pages de cours : largeur de lecture, et surtout AUCUNE
                       couleur à soi — tout est hérité de design-system.css pour
                       que le contenu suive le thème clair/sombre de l'élève.
                       Une couleur en dur ici, c'est du texte noir sur fond noir
                       le soir venu.

   RÈGLE : toute valeur propre à une instance (largeur d'image saisie à la main,
   ratio de colonnes, teinte de bloc) arrive par propriété personnalisée posée
   dans le HTML. C'est un paramètre, pas une règle de style : la décision reste
   ici, le HTML ne fait que renseigner un nombre.
   ========================================================================== */

/* ==========================================================================
   1. SOCLE COMMUN
   ========================================================================== */

.nova {
    --nova-measure:      68ch;      /* largeur de lecture confortable */
    --nova-gap:          32px;
    --nova-radius:       12px;
    --nova-radius-lg:    20px;
    /* Ajouté le 2026-08-09 : il était utilisé par le badge du hero sous la
       forme `var(--nova-radius-full, 999px)` et n'était défini NULLE PART. Ça
       marchait — c'est tout le problème d'une valeur de repli : elle rend le
       jeton invisible, on croit pouvoir le régler et la retouche n'a aucun
       effet. Trouvé par le contrôle « aucun jeton utilisé sans être défini »
       de tools/test-nova-identities.php. */
    --nova-radius-full:  999px;
}

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

/* ⚠️ AUCUN DÉBORDEMENT HORIZONTAL, quel que soit le texte (QA 2026-10-28, M5).
   Un mot de 1 500 caractères sans espace élargissait la page publique jusqu'à
   16 447 px : un mot insécable impose sa largeur, et un enfant de grille ou de
   flex ne descend pas sous la largeur de son contenu (min-width: auto).
   Trois verrous : le mot se coupe quand il ne tient plus ; les enfants des
   grilles et rangées NOVA peuvent rétrécir ; boutons et médias ne dépassent
   jamais leur colonne. */
.nova { overflow-wrap: break-word; }
.nova :is(.nova-columns, .nova-cards, .nova-hero, .nova-quotes, .nova-offer, .nova-trust,
          .nova-timeline, .nova-checks__item, .nova-faq__q, .nova-trust__item, .nova-quote__by) > * {
    min-width: 0;
}
.nova :is(img, video, iframe, table) { max-width: 100%; }
.nova-btn { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }

/* ==========================================================================
   2. MODE LANDING — la page de vente
   --------------------------------------------------------------------------
   Palette locale. Elle ne dépend PAS de design-system.css : une page de vente
   est publique, elle ne doit rien à la préférence de thème de personne, et
   surtout pas basculer en sombre parce que le téléphone du visiteur l'a décidé.
   Le lot 7 ajoutera d'autres palettes en surchargeant ce seul bloc.
   ========================================================================== */

.nova--landing {
    --nova-wrap:         1140px;
    /* 2026-10-23 : était clamp(56px, 8vw, 110px). Ajouté à la marge du dernier
       bloc, cela creusait jusqu'à 254 px entre deux bandes sur un écran large
       (mesuré dans tools/apercu-nova.php) : le visiteur croyait la page finie. */
    --nova-pad-y:        clamp(44px, 5.5vw, 80px);
    --nova-pad-x:        clamp(20px, 5vw, 48px);

    /* Police d'affichage des grands titres.
       ─────────────────────────────────────
       Une seconde voix typographique est ce qui distingue le plus vite une
       landing d'un article : un serif pour les titres, la sans pour le corps.
       On l'obtient ici par une PILE SYSTÈME, sans télécharger de fichier :
         · zéro requête réseau, donc aucun décalage de mise en page au
           chargement — un titre de 56 px qui change de police après coup est le
           défaut le plus visible d'une page ;
         · rien à sous-ensembler, rien à mettre à jour, rien à héberger.
       Le prix : la lettre exacte varie d'un système à l'autre. C'est un
       compromis assumé. Pour une identité stricte, remplacer cette seule
       déclaration par une @font-face self-hostée — comme Inter — sans toucher à
       une autre ligne de cette feuille. */
    --nova-font-display: "Iowan Old Style", "Palatino Linotype", Palatino,
                         "Charter", "Bitstream Charter", Georgia,
                         "Times New Roman", serif;

    /* ⚠️ DERNIER FILET, ET RIEN D'AUTRE. Ces valeurs sont celles que
       nova_identity_tokens() calcule pour l'identité `impulsion` — recopiées à
       l'octet près, et vérifiées par tools/test-nova-identities.php, qui relit
       ce fichier. En fonctionnement normal elles sont TOUTES recouvertes par
       les propriétés personnalisées posées sur l'enveloppe. Elles ne servent
       qu'à deux moments, mais deux moments qui comptent : une page servie entre
       l'upload FTP et l'application de la migration 024, et une page dont
       l'identité a disparu. Dans les deux cas, elle s'affiche juste. */
    --nova-primary:           #6c5ce7;
    --nova-primary-dark:      #594bbd;
    --nova-on-primary:        #ffffff;
    --nova-link:              #6c5ce7;
    --nova-link-hover:        #594bbd;
    --nova-accent:            #ffd700;
    --nova-on-accent:         #14142b;
    --nova-accent-mark:       #ffd700;
    --nova-accent-2:          #0f766e;
    --nova-accent-on-dark:    #ffd700;
    --nova-accent-on-brand:   #fff8d0;
    --nova-accent-on-surface: #ae9300;

    --nova-ink:          #14142b;
    --nova-body:         #3a3a4d;
    --nova-muted:        #71717d;
    --nova-line:         #dedee1;

    --nova-surface:      #ffffff;
    --nova-cream:        #faf7f2;
    --nova-dark:         #14142b;
    --nova-on-dark:      #f1f1f2;
    --nova-muted-dark:   #a1a1aa;

    color: var(--nova-body);
    font-size: 17px;
    line-height: 1.7;
}

/* ==========================================================================
   2 bis. LES IDENTITÉS VISUELLES  (V3, lot 8 — migration 024)
   --------------------------------------------------------------------------
   ⚠️ IL N'Y A PLUS DE BLOC DE PALETTE ICI, ET C'EST VOULU.

   Le lot 7 posait trois palettes en dur — `.nova--landing.nova-palette-forest`
   et `.nova-palette-ink` — parce qu'une palette non vérifiée est une palette
   dangereuse : une page empile des sections claires, nuancées, sombres et de
   marque, soit une vingtaine de paires texte/fond, et deux couleurs saisies au
   hasard en rendent forcément quelques-unes illisibles. Le projet avait payé ce
   piège le 2026-08-02 (blanc sur doré à 1,23:1, 1,12:1 au survol).

   L'argument portait sur ce qu'on ne MESURE pas. Depuis le lot 8,
   includes/nova_colors.php mesure chaque paire selon la formule WCAG et dérive
   toute couleur de texte jusqu'à son seuil. Les identités vivent donc en base
   (table `nova_identities`) et arrivent ici en PROPRIÉTÉS PERSONNALISÉES posées
   sur l'enveloppe :

       <div class="nova nova--landing" style="--nova-primary:#…;--nova-accent:#…">

   Garder EN PLUS les deux anciens blocs aurait fabriqué deux sources pour la
   même identité — la feuille et la base — qui auraient divergé à la première
   retouche, sans lever la moindre erreur. C'est le motif exact des six
   divergences NOVA du 2026-08-07. Ils sont donc retirés, pas commentés.

   ⚠️ Les valeurs de `.nova--landing` ci-DESSUS restent, et changent de rôle :
   elles ne sont plus « la palette Impulsion », elles sont le DERNIER FILET —
   ce que rend une page dont l'identité est introuvable, ou une page servie
   avant que la migration 024 ne soit appliquée. Elles doivent donc rester
   rigoureusement égales aux valeurs que nova_identity_tokens() calcule pour
   l'identité `impulsion` : tools/test-nova-identities.php relit cette feuille
   et refuse tout écart.
   ========================================================================== */

/* ==========================================================================
   3. MODE DOCUMENT — la page de cours
   --------------------------------------------------------------------------
   Aucune couleur propre : tout vient du thème élève. Les jetons ci-dessous ne
   sont que des ALIAS vers design-system.css, pour que les règles communes plus
   bas puissent s'écrire une seule fois.
   ========================================================================== */

.nova--document {
    --nova-wrap:         100%;
    --nova-pad-y:        0;
    --nova-pad-x:        0;

    --nova-primary:      var(--brand);
    --nova-primary-dark: var(--brand-hover);
    --nova-on-primary:   var(--text-on-brand);
    --nova-accent:       var(--gold);
    --nova-on-accent:    #1a1a2e;

    /* Les jetons d'ADAPTATION (2026-10-23) n'ont rien à adapter ici : ils
       suivent la couleur dont ils dérivent. Une identité de formation pose
       les siens par-dessus (`.cid .nova--document`, section 3 bis). */
    --nova-link:         var(--nova-primary);
    --nova-link-hover:   var(--nova-primary-dark);
    --nova-accent-mark:  var(--nova-accent);

    /* Les quatre jetons du lot 8 doivent être aliasés ICI aussi, même si le
       mode document n'a pas d'identité : sans ces lignes, `.nova-eyebrow` et
       `.nova-quote__stars` retomberaient sur une variable non définie dans une
       page de cours. Une var() inexistante ne lève AUCUNE erreur — la
       propriété est simplement ignorée et le texte perd sa couleur, ce que
       CLAUDE.md documente comme le motif à soupçonner en premier devant un
       rendu bizarre. En mode document, la « deuxième voix » n'a pas lieu
       d'être : tout retombe sur la marque du thème élève. */
    --nova-accent-2:          var(--brand);
    --nova-accent-on-dark:    var(--gold);
    --nova-accent-on-brand:   var(--gold);
    --nova-accent-on-surface: var(--gold);

    --nova-ink:          var(--text);
    --nova-body:         var(--text);
    --nova-muted:        var(--text-muted);
    --nova-line:         var(--border);

    --nova-surface:      transparent;
    --nova-cream:        transparent;
    --nova-dark:         transparent;
    --nova-on-dark:      var(--text);
    --nova-muted-dark:   var(--text-muted);

    color: var(--text);
}

/* ==========================================================================
   3 bis. IDENTITÉ DE FORMATION  (2026-10-22 — migration 034)
   --------------------------------------------------------------------------
   La section 3 dit « aucune couleur propre » et elle reste vraie : une
   identité de formation ne choisit AUCUN fond. Elle choisit des couleurs
   d'expression (titres, intertitres, liens et boutons, surlignage, surtitres),
   UNE SÉRIE PAR THÈME, mesurées contre les vrais fonds de /app par
   includes/course_identity_colors.php.

   Le PHP pose les deux séries en propriétés sur l'enveloppe du player :
       <article class="player-main cid" style="--cid-l-heading:#…;--cid-d-heading:#…">
   et c'est ICI que la bonne série devient `--cid-*`, selon le thème de
   l'élève — un attribut style="" ne sait pas lire prefers-color-scheme.
   Mêmes deux déclencheurs que design-system.css : le réglage système tant que
   l'élève n'a rien choisi, puis data-theme sur <html>, qui a le dernier mot.

   L'aperçu du back-office pose directement `--cid-*` (un seul thème) : en
   ligne, elle l'emporte sur la bascule ci-dessous, quel que soit le thème de
   l'admin qui regarde.
   ========================================================================== */

.cid {
    --cid-heading:       var(--cid-l-heading);
    --cid-subheading:    var(--cid-l-subheading);
    --cid-primary:       var(--cid-l-primary);
    --cid-primary-hover: var(--cid-l-primary-hover);
    --cid-on-primary:    var(--cid-l-on-primary);
    --cid-link:          var(--cid-l-link);
    --cid-link-hover:    var(--cid-l-link-hover);
    --cid-accent:        var(--cid-l-accent);
    --cid-on-accent:     var(--cid-l-on-accent);
    --cid-accent-ink:    var(--cid-l-accent-ink);
    --cid-accent2:       var(--cid-l-accent2);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .cid {
        --cid-heading:       var(--cid-d-heading);
        --cid-subheading:    var(--cid-d-subheading);
        --cid-primary:       var(--cid-d-primary);
        --cid-primary-hover: var(--cid-d-primary-hover);
        --cid-on-primary:    var(--cid-d-on-primary);
        --cid-link:          var(--cid-d-link);
        --cid-link-hover:    var(--cid-d-link-hover);
        --cid-accent:        var(--cid-d-accent);
        --cid-on-accent:     var(--cid-d-on-accent);
        --cid-accent-ink:    var(--cid-d-accent-ink);
        --cid-accent2:       var(--cid-d-accent2);
    }
}

:root[data-theme="dark"] .cid {
    --cid-heading:       var(--cid-d-heading);
    --cid-subheading:    var(--cid-d-subheading);
    --cid-primary:       var(--cid-d-primary);
    --cid-primary-hover: var(--cid-d-primary-hover);
    --cid-on-primary:    var(--cid-d-on-primary);
    --cid-link:          var(--cid-d-link);
    --cid-link-hover:    var(--cid-d-link-hover);
    --cid-accent:        var(--cid-d-accent);
    --cid-on-accent:     var(--cid-d-on-accent);
    --cid-accent-ink:    var(--cid-d-accent-ink);
    --cid-accent2:       var(--cid-d-accent2);
}

/* La couleur de marque de /app est REDÉFINIE dans la leçon : le bouton
   « Marquer comme terminé », le bloc de documents et la navigation entre
   leçons prennent la couleur de la formation, pas seulement le contenu NOVA.
   Les trois jetons partent ensemble — un --brand changé sans son texte, c'est
   le blanc sur jaune à 1,2:1 corrigé le 2026-08-02. */
.cid {
    --brand:          var(--cid-primary);
    --brand-hover:    var(--cid-primary-hover);
    --brand-contrast: var(--cid-on-primary);
    --text-on-brand:  var(--cid-on-primary);
}

/* (0,2,0) : l'emporte sur `.nova--document` (0,1,0), qui redéfinit ces jetons
   sur l'enveloppe NOVA elle-même et masquerait sinon ceux hérités de .cid.
   --nova-primary suit déjà, par var(--brand). */
.cid .nova--document {
    --nova-ink:               var(--cid-subheading);
    --nova-link:              var(--cid-link);
    --nova-link-hover:        var(--cid-link-hover);
    --nova-accent:            var(--cid-accent);
    --nova-on-accent:         var(--cid-on-accent);
    --nova-accent-2:          var(--cid-accent2);
    --nova-accent-on-dark:    var(--cid-accent-ink);
    --nova-accent-on-brand:   var(--cid-accent-ink);
    --nova-accent-on-surface: var(--cid-accent-ink);
}

/* Les titres PRINCIPAUX : celui de la leçon, puis H1 et H2 du contenu.
   `--cid-font` n'est posé que si l'identité choisit une voix : sans lui, on
   garde la police héritée — la seule valeur de repli voulue de la section. */
.cid .player-title,
.cid .nova--document .nova-h--1,
.cid .nova--document .nova-h--2 {
    color: var(--cid-heading);
    font-family: var(--cid-font, inherit);
}

/* ==========================================================================
   4. SECTIONS
   --------------------------------------------------------------------------
   La section s'étend sur toute la largeur de l'écran, son contenu est ramené
   au gabarit par __inner. C'est ce couple qui produit les bandes de couleur
   pleine largeur d'une landing moderne, impossibles avec un conteneur unique.
   ========================================================================== */

.nova-section {
    padding: var(--nova-pad-y) var(--nova-pad-x);
}

.nova-section__inner {
    max-width: var(--nova-wrap);
    margin-inline: auto;
}

/* La section porte SEUL le rythme vertical (2026-10-23). Sans ces deux règles,
   la marge du premier et du dernier bloc (2em pour une grille, une frise, un
   bouton…) s'ajoutait au padding : le vide entre deux bandes dépendait du bloc
   posé en dernier, et dépassait 250 px sous une grille de cartes. */
.nova-section__inner > :first-child { margin-top: 0; }
.nova-section__inner > :last-child  { margin-bottom: 0; }

/* Deux sections de même teinte qui se suivent ne doivent pas creuser un vide
   double au milieu d'une bande unie : visuellement c'est UNE section, et la
   coupure se voit. */
.nova-section--light  + .nova-section--light,
.nova-section--cream  + .nova-section--cream,
.nova-section--dark   + .nova-section--dark,
.nova-section--brand  + .nova-section--brand { padding-top: 0; }

.nova--landing .nova-section--light { background: var(--nova-surface); }
.nova--landing .nova-section--cream { background: var(--nova-cream); }

.nova--landing .nova-section--dark {
    background: var(--nova-dark);
    color: var(--nova-on-dark);
}

.nova--landing .nova-section--brand {
    background: var(--nova-primary);
    color: var(--nova-on-primary);
}

/* Sur fond sombre ou de marque, titres et texte discret doivent suivre —
   sinon un H2 reste encre sur encre et disparaît purement et simplement. */
.nova--landing .nova-section--dark .nova-h,
.nova--landing .nova-section--brand .nova-h { color: inherit; }

.nova--landing .nova-section--dark .nova-figure__caption,
.nova--landing .nova-section--dark .nova-video__caption { color: var(--nova-muted-dark); }

.nova--landing .nova-section--brand .nova-figure__caption,
.nova--landing .nova-section--brand .nova-video__caption { color: inherit; opacity: 1; }

/* En mode document, la borne de section n'est plus qu'un séparateur logique :
   pas de fond, pas de pleine largeur. Un bloc de page de vente collé par erreur
   dans un cours se dégrade proprement au lieu de peindre une bande noire au
   milieu d'une leçon. */
.nova--document .nova-section {
    padding: 0;
    background: none;
    color: inherit;
}
.nova--document .nova-section + .nova-section { margin-top: var(--space-7, 48px); }

/* ==========================================================================
   5. TYPOGRAPHIE
   ========================================================================== */

.nova-h {
    color: var(--nova-ink);
    font-weight: 800;
    line-height: 1.15;
    letter-spacing: -.02em;
    margin: 0 0 .5em;
    text-wrap: balance;          /* évite le mot orphelin sur la dernière ligne */
}

.nova-h:not(:first-child) { margin-top: 1.4em; }

/* La police d'affichage n'habille que les GRANDS titres — H1, H2, et les titres
   des blocs de conversion. Au-delà, un serif sur des intertitres de 19 px et sur
   des libellés de carte alourdit la lecture au lieu de la structurer : la
   seconde voix typographique perd son effet dès qu'elle parle partout. */
.nova--landing .nova-h--1,
.nova--landing .nova-h--2,
.nova--landing .nova-hero__title,
.nova--landing .nova-offer__title,
.nova--landing .nova-finalcta__title {
    font-family: var(--nova-font-display);
    font-weight: 700;          /* un serif à 800 devient massif */
    letter-spacing: -.015em;
}

.nova--landing .nova-h--1 { font-size: clamp(34px, 5.2vw, 56px); }
.nova--landing .nova-h--2 { font-size: clamp(27px, 3.6vw, 40px); }
.nova--landing .nova-h--3 { font-size: clamp(21px, 2.4vw, 27px); }
.nova--landing .nova-h--4 { font-size: clamp(18px, 2vw, 21px); }
.nova--landing .nova-h--5,
.nova--landing .nova-h--6 { font-size: 18px; }

.nova--document .nova-h--1 { font-size: clamp(27px, 4vw, 36px); }
.nova--document .nova-h--2 { font-size: clamp(22px, 3vw, 28px); }
.nova--document .nova-h--3 { font-size: clamp(19px, 2.2vw, 22px); }
.nova--document .nova-h--4,
.nova--document .nova-h--5,
.nova--document .nova-h--6 { font-size: 18px; }

.nova-p {
    margin: 0 0 1.1em;
    max-width: var(--nova-measure);
}

/* Un paragraphe centré dont la mesure reste calée à gauche paraît décalé :
   il faut recentrer la BOÎTE, pas seulement le texte. */
.nova-p.nova-align-center { margin-inline: auto; }
.nova-p.nova-align-right  { margin-inline: auto 0; }

.nova-align-left   { text-align: left; }
.nova-align-center { text-align: center; }
.nova-align-right  { text-align: right; }

/* --nova-link et non --nova-primary (2026-10-23) : la principale garde sa
   couleur exacte sur les aplats ; en TEXTE, elle passe par sa variante
   adaptée, identique tant qu'elle se lit. */
.nova a:where(:not([class])) {
    color: var(--nova-link);
    text-underline-offset: 2px;
}

/* ⚠️ a:hover pèse (0,1,1) et bat une classe de bouton (0,1,0) : sans :where(),
   le survol d'un .nova-btn — qui est un <a> — reprendrait cette couleur-ci par-
   dessus la sienne. C'est exactement le défaut corrigé le 2026-08-02 sur le
   back-office, où le texte des boutons prenait la couleur de leur propre fond
   (contraste 1,00:1). :where() ayant une spécificité nulle, la règle ne peut
   plus recouvrir aucune classe. */
.nova a:where(:not([class]):hover) { color: var(--nova-link-hover); }

.nova mark {
    background: var(--nova-accent);
    color: var(--nova-on-accent);
    padding: .1em .25em;
    border-radius: 4px;
}

.nova code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: .9em;
    background: rgba(127, 127, 160, .14);
    padding: .15em .4em;
    border-radius: 4px;
}

/* ==========================================================================
   6. LISTES
   ========================================================================== */

.nova-list {
    margin: 0 0 1.2em;
    padding-left: 1.4em;
    max-width: var(--nova-measure);
}

.nova-list__item { margin: .4em 0; }

.nova-list--unordered { list-style: disc; }
.nova-list--ordered   { list-style: decimal; }

/* Sous-liste (Tab dans l'éditeur, QA 2026-10-28 M1) : collée à son élément,
   puce et numérotation du niveau suivant. */
.nova-list--nested { margin: .3em 0 0; }
.nova-list--unordered.nova-list--nested { list-style: circle; }
.nova-list--unordered .nova-list--nested .nova-list--nested { list-style: square; }
.nova-list--ordered.nova-list--nested { list-style: lower-alpha; }

/* --- Tableau et citation (NOVA 4.5, 2026-10-28) ---------------------------
   Couleurs neutres ou héritées (currentColor, translucides) : lisibles sur les
   quatre fonds de section sans règle --dark / --brand à part. Le tableau
   défile DANS son cadre : jamais il n'élargit la page (M5). */
.nova-table-wrap {
    margin: 0 0 1.4em;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
}
.nova-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .95em;
    line-height: 1.5;
}
.nova-table th,
.nova-table td {
    border: 1px solid rgba(127, 127, 160, .32);
    padding: .6em .8em;
    text-align: left;
    vertical-align: top;
    min-width: 7em;
}
.nova-table th {
    background: rgba(127, 127, 160, .12);
    font-weight: 700;
}
/* Marque typographique (guillemet d'ouverture) plutôt qu'une barre latérale
   colorée : la citation se lit comme une citation, pas comme un encadré. */
.nova-citation {
    position: relative;
    margin: 1.6em 0;
    padding: .3em 0 .2em 2.1em;
    max-width: var(--nova-measure);
}
.nova-citation::before {
    content: "\201C";
    position: absolute;
    left: 0;
    top: -.1em;
    font-family: var(--nova-font-display, Georgia, serif);
    font-size: 3.6em;   /* recette 2026-10-28 : « petit et gris pâle » à 2,6em / .35 */
    line-height: 1;
    opacity: .55;
}
.nova-citation__text {
    margin: 0;
    font-size: 1.15em;
    font-style: italic;
    line-height: 1.55;
}
.nova-citation__text p { margin: 0; }
.nova-citation__by {
    margin-top: .6em;
    font-size: .9em;
    opacity: .75;
}
.nova-citation__by::before { content: "— "; }
.nova s { text-decoration-thickness: .08em; }

/* Checklist DÉCORATIVE (pages de vente). Nom volontairement distinct de
   .nova-checklist, qui est le contrôle cliquable de l'espace élève et porte
   déjà ses propres règles dans design-system.css. */
.nova-checks {
    list-style: none;
    margin: 0 0 1.2em;
    padding: 0;
    max-width: var(--nova-measure);
}

.nova-checks__item {
    display: flex;
    gap: .6em;
    align-items: flex-start;
    margin: .5em 0;
}

.nova-checks__mark {
    flex: 0 0 auto;
    font-size: 1.2em;
    line-height: 1.35;
}

.nova-checks__item.is-checked .nova-checks__text {
    text-decoration: line-through;
    color: var(--nova-muted);
}

/* ==========================================================================
   7. IMAGES
   ========================================================================== */

.nova-figure {
    margin: 2em 0;
}

.nova-figure--left   { text-align: left; }
.nova-figure--center { text-align: center; }
.nova-figure--right  { text-align: right; }

.nova-img {
    max-width: 100%;
    height: auto;
    border-radius: var(--nova-radius);
    vertical-align: middle;
}

/* Largeur choisie à la main dans l'éditeur. Le max-width garde la priorité sur
   petit écran : une image réglée à 900 px ne doit pas déborder d'un téléphone. */
.nova-img[style*="--nova-img-w"] { width: var(--nova-img-w); }

/* Taille choisie (NOVA 4.6.1), même règle que les vidéos : l'image remplit un
   cadre de 480 / 720 px, placé selon l'alignement. Sans classe de taille
   (image d'avant ou « Pleine largeur ») : rien ne change. */
.nova-figure--small  { max-width: 480px; }
.nova-figure--medium { max-width: 720px; }
.nova-figure--small.nova-figure--center,
.nova-figure--medium.nova-figure--center { margin-inline: auto; }
.nova-figure--small.nova-figure--right,
.nova-figure--medium.nova-figure--right  { margin-left: auto; }
:is(.nova-figure--small, .nova-figure--medium) .nova-img { width: 100%; }
.nova-media-grid .nova-figure .nova-img { width: 100%; }

.nova-img--stretched { width: 100%; }
.nova-img--bordered  { border: 1px solid var(--nova-line); }

.nova-img--padded {
    background: rgba(127, 127, 160, .08);
    padding: 20px;
}

.nova-figure__caption {
    margin-top: .7em;
    font-size: 14px;
    color: var(--nova-muted);
    font-style: italic;
}

/* ==========================================================================
   8. COLONNES
   --------------------------------------------------------------------------
   ⚠️ Ces règles remplacent un <style> que le renderer réinjectait à CHAQUE
   bloc colonnes de la page. Il n'était pas décoratif : aucune feuille du projet
   ne définissait .nova-columns, donc c'était lui — et lui seul — qui empilait
   les colonnes sur mobile dans l'espace élève. Le supprimer sans le remplacer
   aurait laissé deux colonnes côte à côte sur téléphone dans tous les cours.
   ========================================================================== */

.nova-columns {
    display: grid;
    /* On retire à la première piste sa part de gouttière : sans ça, « 60 / 40 »
       affiche un peu plus de 60 %, l'écart grandissant avec la taille du gap. */
    grid-template-columns: calc(var(--nova-col-ratio, 50) * 1% - var(--nova-gap) / 2) 1fr;
    gap: var(--nova-gap);
    margin: 2em 0;
    align-items: start;
}

.nova-columns__col > *:first-child { margin-top: 0; }
.nova-columns__col > *:last-child  { margin-bottom: 0; }

/* Depuis la V3, une colonne contient du HTML NU (<p>, <ul>, <h3>) et non des
   blocs classés : ces balises n'ont donc pas de .nova-p ni de .nova-list pour
   les habiller, et resteraient à la mise en forme par défaut du navigateur —
   Times New Roman compris sur certaines. */
.nova-columns__col p {
    margin: 0 0 1em;
    max-width: none;          /* la mesure de lecture n'a pas de sens ici :
                                 la colonne EST déjà la contrainte de largeur */
}

.nova-columns__col h3,
.nova-columns__col h4 {
    color: var(--nova-ink);
    font-weight: 700;
    line-height: 1.25;
    margin: 0 0 .5em;
}

.nova-columns__col h3 { font-size: 21px; }
.nova-columns__col h4 { font-size: 18px; }

.nova--landing .nova-section--dark .nova-columns__col h3,
.nova--landing .nova-section--dark .nova-columns__col h4,
.nova--landing .nova-section--brand .nova-columns__col h3,
.nova--landing .nova-section--brand .nova-columns__col h4 { color: inherit; }

.nova-columns__col ul,
.nova-columns__col ol {
    margin: 0 0 1em;
    padding-left: 1.4em;
}

.nova-columns__col li { margin: .35em 0; }

.nova-columns__col a {
    color: var(--nova-link);
    text-underline-offset: 2px;
}

/* Sur fond sombre, le violet de marque n'a plus assez de contraste : le lien
   reprend la couleur du texte et se signale par son soulignement. */
.nova--landing .nova-section--dark .nova-columns__col a,
.nova--landing .nova-section--brand .nova-columns__col a {
    color: inherit;
    text-decoration-thickness: 2px;
}

@media (max-width: 768px) {
    .nova-columns { grid-template-columns: 1fr; gap: var(--nova-gap); }
}

/* --------------------------------------------------------------------------
   Liste à icônes (NOVA 4.6.2). Grille icône | texte : l'icône est calée sur la
   PREMIÈRE ligne (même hauteur de ligne que le texte), une ligne de deux lignes
   garde son retrait. Jamais de texte barré.
   ⚠️ MÊMES mesures que le bloc Liste (.nova-list / .nova-list__item, §6) : taille
   et hauteur de ligne héritées, marges .4em / 0 0 1.2em — une liste à icônes
   paraissait plus grande (interligne 1,6 au lieu de 1,7, lignes plus espacées,
   icône à 1,05em). Le banc de rendu compare les deux. Seule l'icône change,
   à la taille du texte.
   -------------------------------------------------------------------------- */
.nova-iconlist {
    list-style: none;
    margin: 0 0 1.2em;
    padding: 0;
    max-width: var(--nova-measure);
}
.nova-iconlist__item {
    display: grid;
    grid-template-columns: 1.5em 1fr;
    column-gap: .25em;
    align-items: start;
    margin: .4em 0;
}
.nova-iconlist__icon {
    font-size: 1em;
    line-height: inherit;
    text-align: left;
}
.nova-iconlist__text { min-width: 0; text-decoration: none; }

/* --------------------------------------------------------------------------
   8 bis. IMAGE + TEXTE (NOVA 4.6.2)
   Part de l'image en --nova-mt-ratio (40 / 50 / 60), côté par classe. Sur
   téléphone, une colonne, l'image TOUJOURS au-dessus du texte. Le texte suit
   le fond de section comme les colonnes (règles reprises ci-dessous).
   -------------------------------------------------------------------------- */
.nova-mediatext {
    display: grid;
    grid-template-columns: calc(var(--nova-mt-ratio, 40) * 1% - var(--nova-gap) / 2) 1fr;
    gap: var(--nova-gap);
    align-items: center;
    margin: 2.5em 0;
}
.nova-mediatext--right {
    grid-template-columns: 1fr calc(var(--nova-mt-ratio, 40) * 1% - var(--nova-gap) / 2);
}
.nova-mediatext--right .nova-mediatext__media { order: 2; }
.nova-mediatext--noimage { grid-template-columns: 1fr; }
.nova-mediatext > * { min-width: 0; }

.nova-mediatext__img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--nova-radius-lg);
}
.nova-mediatext__body > :first-child { margin-top: 0; }
.nova-mediatext__body > :last-child  { margin-bottom: 0; }
.nova-mediatext__title { margin: 0 0 .5em; }
.nova-mediatext__text p { margin: 0 0 1em; max-width: none; }
.nova-mediatext__text :is(ul, ol) { margin: 0 0 1em; padding-left: 1.4em; }
.nova-mediatext__text li { margin: .35em 0; }
.nova-mediatext__text :is(h3, h4) {
    color: var(--nova-ink);
    font-weight: 700;
    line-height: 1.25;
    margin: 0 0 .5em;
}
.nova-mediatext__text a { color: var(--nova-link); text-underline-offset: 2px; }
.nova-mediatext__cta { margin: 1.2em 0 0; }

.nova--landing .nova-section--dark .nova-mediatext__text :is(h3, h4),
.nova--landing .nova-section--brand .nova-mediatext__text :is(h3, h4) { color: inherit; }
.nova--landing .nova-section--dark .nova-mediatext__text a,
.nova--landing .nova-section--brand .nova-mediatext__text a {
    color: inherit;
    text-decoration-thickness: 2px;
}

@media (max-width: 768px) {
    .nova-mediatext,
    .nova-mediatext--right { grid-template-columns: 1fr; }
    .nova-mediatext--right .nova-mediatext__media { order: 0; }
}

/* ==========================================================================
   9. BOUTONS
   --------------------------------------------------------------------------
   ⚠️ CES COULEURS SONT CELLES DE nova/tools/button-tool.js, À L'IDENTIQUE.
   L'ancien renderer portait sa propre table : `primary` y valait un bleu quand
   l'éditeur affiche un violet, et `secondary`, `dark` et `light` n'y figuraient
   pas du tout — trois des six choix retombaient donc en bleu. On choisissait
   une couleur et on en obtenait une autre en ligne, sans rien pour l'annoncer.
   Toute retouche ici se porte dans button-tool.js, et réciproquement.
   ========================================================================== */

.nova-btn-wrap { margin: 2em 0; }

.nova-btn {
    display: inline-block;
    font-weight: 700;
    text-decoration: none;
    border-radius: var(--nova-radius);
    transition: transform .18s ease, box-shadow .18s ease, background-color .18s ease;
    /* Cible tactile : 44 px de haut minimum, recommandation Apple comme Google.
       En dessous, on rate le bouton une fois sur trois — sur la page qui vend. */
    min-height: 44px;
}

.nova-btn--normal { padding: 14px 30px; font-size: 17px; }
.nova-btn--large  { padding: 18px 42px; font-size: 19px; }

.nova-btn--primary   { background: #6c5ce7; color: #ffffff; }
.nova-btn--secondary { background: #FFD700; color: #1a1a1a; }
.nova-btn--success   { background: #00846a; color: #ffffff; }
.nova-btn--danger    { background: #d63031; color: #ffffff; }
.nova-btn--dark      { background: #2d3436; color: #ffffff; }
.nova-btn--light     { background: #f0f0f4; color: #2d3436; }

@media (hover: hover) {
    /* Enfermé dans (hover: hover) : sur écran tactile, l'effet reste COLLÉ
       après l'appui jusqu'au prochain toucher ailleurs, et passe pour un bug
       d'affichage. Même règle que les cartes de /app. */
    .nova-btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 10px 24px rgba(20, 20, 43, .18);
    }
}

.nova-btn:focus-visible {
    /* Revue NOVA du 2026-11-10 : l'accent (souvent doré) autour d'un bouton doré, sur
       fond clair, ne se voyait pas. Double anneau blanc puis foncé : visible partout. */
    outline: 3px solid #fff;
    outline-offset: 2px;
    box-shadow: 0 0 0 5px #111;
}

/* Sur une section sombre, un bouton clair doit garder son contraste : c'est le
   seul cas où le fond de la section peut avaler le bouton. */
.nova-section--dark .nova-btn--dark { background: #ffffff; color: #14142b; }

/* Les boutons des blocs de CONVERSION (hero, offre, relance finale) suivent la
   couleur principale de l'identité (2026-10-23). Ils restaient au violet
   d'origine quelle que soit l'identité choisie : une page verte avait des
   boutons violets. Le bloc « Bouton », lui, garde la couleur choisie dans son
   outil — c'est un choix explicite de l'auteur. */
.nova--landing .nova-hero .nova-btn--primary,
.nova--landing .nova-offer .nova-btn--primary,
.nova--landing .nova-finalcta .nova-btn--primary {
    background: var(--nova-primary);
    color: var(--nova-on-primary);
}

/* Sur une section de MARQUE, un bouton principal a la couleur du fond : il
   devenait un simple texte blanc (relance finale, bloc Bouton). Il prend le
   couple accent / texte-sur-accent, mesuré par l'identité. */
.nova--landing .nova-section--brand .nova-btn--primary {
    background: var(--nova-accent);
    color: var(--nova-on-accent);
}
/* ==========================================================================
   10. VIDÉO
   ========================================================================== */

.nova-video { margin: 2em 0; }

.nova-video__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--nova-radius);
    overflow: hidden;
    background: #000;
}

.nova-video__iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.nova-video__caption {
    margin: .7em 0 0;
    text-align: center;
    font-size: 14px;
    color: var(--nova-muted);
}

/* Largeur choisie (NOVA 4.6.0). Sans classe de largeur (contenu d'avant) ou en
   « full » : toute la largeur, comme avant. */
.nova-video--small  { max-width: 480px; margin-inline: auto; }
.nova-video--medium { max-width: 720px; margin-inline: auto; }

/* Médias « small » qui se suivent (vidéos NOVA 4.6.0, images 4.6.1) : grille de
   2 colonnes posée par le rendu (nova_render_sections), jamais mélangée. Chaque
   média remplit sa colonne ; un dernier seul (nombre impair) se centre, à 480 px. */
.nova-media-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
    align-items: start;
    max-width: calc(2 * 480px + 24px);
    margin: 2em auto;
}
.nova-media-grid > * { margin: 0; min-width: 0; }
.nova-media-grid :is(.nova-video, .nova-figure) { max-width: none; margin: 0; }
.nova-media-grid > :last-child:nth-child(odd) {
    grid-column: 1 / -1;
    justify-self: center;
    width: 100%;
    max-width: 480px;
}
@media (max-width: 640px) {
    .nova-media-grid { grid-template-columns: 1fr; gap: 20px; }
    .nova-media-grid > :last-child:nth-child(odd) { max-width: none; }
}

/* ==========================================================================
   10 bis. GRILLE DE CARTES  (V3, lot 2)
   --------------------------------------------------------------------------
   `auto-fit` + `minmax` plutôt qu'un nombre fixe de colonnes : la grille se
   réduit d'elle-même quand la place manque, sans qu'on ait à écrire un
   breakpoint par configuration. Une grille de 4 passe donc à 3, puis 2, puis 1
   selon la largeur réelle — y compris DANS une colonne, cas qu'aucune media
   query basée sur la fenêtre ne saurait traiter correctement.
   ========================================================================== */

.nova-cards {
    display: grid;
    gap: 20px;
    margin: 2em 0;
    /* min(…, 100%) : sur un écran plus étroit que la largeur mini (320 px sous 360 px
       d'écran, marges comprises), la carte débordait à droite (revue NOVA du 2026-11-10). */
    grid-template-columns: repeat(auto-fit, minmax(min(var(--nova-card-min, 240px), 100%), 1fr));
}

/* Une grille dont toutes les cartes ont été écartées ne doit pas laisser sa
   marge : ça produirait un vide inexpliqué au milieu de la page, qu'on
   chercherait dans le CSS. Idem pour une FAQ sans question valide. */
.nova-cards:empty,
.nova-faq:empty { display: none; }

.nova-cards--3 { --nova-card-min: 250px; }
.nova-cards--4 { --nova-card-min: 200px; }

/* Le nombre demandé reste un PLAFOND : sans la largeur maximale, une grille de
   2 s'étalerait en 4 sur un grand écran, et « deux colonnes » ne voudrait plus
   rien dire. */
.nova-cards--2 { --nova-card-min: 320px; max-width: 900px; margin-inline: auto; }

.nova-card {
    background: var(--nova-surface);
    border: 1px solid var(--nova-line);
    border-radius: var(--nova-radius-lg);
    padding: 24px;
}

/* Sur une section sombre, une carte au fond blanc ferait tache et casserait la
   bande. Elle devient une surface légèrement éclaircie, et sa bordure suit. */
.nova--landing .nova-section--dark .nova-card,
.nova--landing .nova-section--brand .nova-card {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .16);
}

/* En mode document, la carte est une surface du thème élève : elle doit donc
   suivre le clair/sombre au lieu de porter sa propre couleur. */
.nova--document .nova-card {
    background: var(--bg-elevated);
    border-color: var(--border);
}

.nova-card__icon {
    font-size: 26px;
    line-height: 1;
    margin-bottom: 12px;
}

.nova-card__title {
    font-size: 18px;
    font-weight: 700;
    color: var(--nova-ink);
    margin: 0 0 8px;
    line-height: 1.3;
}

.nova--landing .nova-section--dark .nova-card__title,
.nova--landing .nova-section--brand .nova-card__title { color: inherit; }

.nova-card__text {
    margin: 0;
    font-size: 15px;
    line-height: 1.6;
    color: var(--nova-muted);
    max-width: none;      /* la mesure de lecture n'a pas de sens dans une carte */
}

.nova--landing .nova-section--dark .nova-card__text { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-card__text { color: inherit; opacity: 1; }

/* Carte à image (NOVA 4.6.1) — portraits, équipe, intervenants. L'image prend
   la place de l'émoji, en haut ; titre et texte centrés sous elle. Une carte
   SANS image n'a pas ces classes : son apparence ne change pas. */
.nova-card--media { text-align: center; }
.nova-card__img {
    display: block;
    object-fit: cover;
    object-position: center 25%;   /* un visage est rarement au centre exact */
    margin: 0 auto 16px;
    background: var(--nova-line);
}
.nova-card--round .nova-card__img {
    width: 128px;
    height: 128px;
    border-radius: 50%;
}
.nova-card--square .nova-card__img {
    width: 100%;
    aspect-ratio: 1;
    height: auto;
    border-radius: var(--nova-radius);
}

/* Sur téléphone, une carte par ligne : chaque photo reste avec son texte. */
@media (max-width: 560px) {
    .nova-cards { grid-template-columns: 1fr; }
}

/* ==========================================================================
   10 ter. FAQ  (V3, lot 2)
   --------------------------------------------------------------------------
   <details>/<summary> natifs : accessibles au clavier sans une ligne de JS, et
   dont le contenu reste dans le HTML — donc indexable, là où un accordéon fait
   main masque souvent ses réponses aux moteurs de recherche.
   ========================================================================== */

.nova-faq {
    /* Centrée (2026-10-23) : sous un titre centré, une FAQ de 780 px calée à
       gauche paraissait décalée sur grand écran. */
    margin: 2em auto;
    max-width: 780px;
}

.nova-faq__item {
    border-bottom: 1px solid var(--nova-line);
}

.nova-faq__item:first-child { border-top: 1px solid var(--nova-line); }

.nova-faq__q {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 4px;
    font-size: 17px;
    font-weight: 600;
    color: var(--nova-ink);
    cursor: pointer;
    list-style: none;           /* retire la flèche par défaut… */
}

.nova-faq__q::-webkit-details-marker { display: none; }   /* …y compris sur Safari */

.nova--landing .nova-section--dark .nova-faq__q,
.nova--landing .nova-section--brand .nova-faq__q { color: inherit; }

/* Le chevron est dessiné en CSS : une icône de plus à charger pour une flèche
   serait absurde, et un caractère unicode ne pivote pas proprement. */
.nova-faq__q::after {
    content: '';
    flex: 0 0 auto;
    width: 9px;
    height: 9px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .2s ease;
    opacity: .55;
}

.nova-faq__item[open] .nova-faq__q::after {
    transform: rotate(-135deg) translate(-2px, -2px);
}

.nova-faq__q:focus-visible {
    /* La couleur principale sur une section de MARQUE (fond = couleur principale)
       était invisible : la couleur du texte se lit par construction (2026-11-10). */
    outline: 3px solid currentColor;
    outline-offset: -3px;
    border-radius: 6px;
}

.nova-faq__a {
    padding: 0 4px 22px;
    color: var(--nova-body);
    line-height: 1.7;
}

.nova--landing .nova-section--dark .nova-faq__a { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-faq__a { color: inherit; opacity: 1; }

/* ==========================================================================
   10 quater. BLOCS DE CONVERSION  (V3, lot 3)
   ========================================================================== */

/* --- Surtitre et mise en valeur ------------------------------------------ */

/* Le surtitre porte la couleur d'accent SECONDAIRE, pas la principale.
   C'est le seul emploi qui donne à ce septième paramètre un vrai travail : la
   principale tient déjà les boutons, les liens et les sections de marque, et
   une identité qui n'aurait que deux voix ne serait qu'un thème de couleur.
   Le surtitre et l'étiquette de déroulé sont des ÉTIQUETTES — la place
   naturelle d'un accent discret. */
.nova-eyebrow {
    margin: 0 0 12px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--nova-accent-2);
}

.nova--landing .nova-section--dark .nova-eyebrow { color: var(--nova-accent-on-dark); }
.nova--landing .nova-section--brand .nova-eyebrow { color: inherit; opacity: 1; }

/* Le mot entouré d'astérisques dans un titre : un trait de pinceau courbe, d'un
   seul tenant, peint SOUS le texte (isolation + z-index -1 : il
   passe derrière les jambages sans disparaître derrière le fond de section).
   Le dessin est un MASQUE et non une image de fond : une image SVG ne lit pas
   les variables CSS, et la couleur doit rester celle de l'identité.
   inline-block : le pseudo-élément suit le mot ; un passage sur plusieurs
   lignes n'a son trait que sous la dernière. */
.nova-accent {
    position: relative;
    display: inline-block;
    max-width: 100%;
    font-style: normal;
    isolation: isolate;
}

.nova-accent::after {
    content: "";
    position: absolute;
    z-index: -1;
    left: -.04em;
    right: -.04em;
    bottom: -.18em;
    height: .3em;
    /* --nova-accent-mark : l'accent éclairci si le texte ne s'y lit pas. */
    background: var(--nova-accent-mark);
    --nova-stroke: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 16' preserveAspectRatio='none'%3E%3Cpath d='M1 4.6C60 11 150 11.6 297 4.6 300.4 4.6 300.4 7.8 297 8.2 190 15 70 15 1 8.2 -.4 7.4 -.4 4.8 1 4.6Z'/%3E%3C/svg%3E");
    -webkit-mask: var(--nova-stroke) center / 100% 100% no-repeat;
    mask: var(--nova-stroke) center / 100% 100% no-repeat;
}

.nova--landing .nova-section--brand .nova-accent::after { background: currentColor; }

/* --- Hero ---------------------------------------------------------------- */

.nova-hero {
    display: grid;
    gap: clamp(28px, 4vw, 56px);
    align-items: center;
}

@media (min-width: 900px) {
    .nova-hero { grid-template-columns: 1.05fr .95fr; }
}

.nova-hero__title {
    font-size: clamp(34px, 5.4vw, 60px);
    font-weight: 800;
    line-height: 1.08;
    letter-spacing: -.025em;
    margin: 0 0 .45em;
    color: var(--nova-ink);
    text-wrap: balance;
}

.nova--landing .nova-section--dark .nova-hero__title,
.nova--landing .nova-section--brand .nova-hero__title { color: inherit; }

.nova-hero__lead {
    font-size: clamp(17px, 1.9vw, 20px);
    line-height: 1.6;
    margin: 0 0 1.4em;
    max-width: 46ch;
    color: var(--nova-muted);
}

.nova--landing .nova-section--dark .nova-hero__lead { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-hero__lead { color: inherit; opacity: 1; }

.nova-hero__cta { margin-top: 8px; }

.nova-hero__media { position: relative; }

.nova-hero__img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: var(--nova-radius-lg);
}

.nova-hero__badge {
    position: absolute;
    top: -14px;
    right: -10px;
    background: var(--nova-accent);
    color: var(--nova-on-accent);
    font-weight: 800;
    font-size: 14px;
    line-height: 1.2;
    padding: 12px 16px;
    border-radius: var(--nova-radius-full, 999px);
    box-shadow: 0 8px 22px rgba(20, 20, 43, .22);
    text-align: center;
    max-width: 40%;
}

/* Le macaron déborde du média : sur mobile, décalé vers l'extérieur il sortirait
   de l'écran et provoquerait un défilement horizontal de toute la page. */
@media (max-width: 560px) {
    .nova-hero__badge { top: -10px; right: 4px; font-size: 13px; padding: 9px 13px; }
}

/* --- Preuves courtes (trust) --------------------------------------------- */

/* ⚠️ UNE PREUVE PAR LIGNE, y compris sur grand écran.
   La version du 2026-08-07 était en `flex-wrap: wrap` : deux preuves courtes
   tenaient alors sur la même ligne du hero, et la liste ne se lisait plus
   comme une liste — le défaut n'apparaissait QUE sur desktop, puisque sur
   mobile la place manquante les empilait déjà. Le champ de l'éditeur s'appelle
   « Preuves courtes (une par ligne) » : la mise en page doit dire la même
   chose que le formulaire. */
.nova-trust {
    list-style: none;
    margin: 0 0 1.6em;
    padding: 0;
    display: grid;
    justify-items: start;
    gap: 10px;
}

.nova-trust__item {
    display: flex;
    /* Une preuve un peu longue passe sur deux lignes dans la colonne étroite
       du hero : la pastille reste alors alignée sur la PREMIÈRE ligne, pas
       centrée sur la hauteur totale. */
    align-items: flex-start;
    gap: 8px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.45;
}

.nova-trust__item::before {
    content: '✓';
    flex: 0 0 auto;
    margin-top: .1em;
    width: 20px;
    height: 20px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--nova-primary);
    color: var(--nova-on-primary);
    font-size: 12px;
}

.nova--landing .nova-section--dark .nova-trust__item::before,
.nova--landing .nova-section--brand .nova-trust__item::before {
    background: var(--nova-accent);
    color: var(--nova-on-accent);
}

/* Hero SANS média (2026-10-23) : colonne unique centrée. Sans cette règle, le
   texte occupait la moitié gauche d'une grille à deux colonnes et le premier
   écran montrait un grand vide à droite. */
@media (min-width: 900px) {
    .nova-hero--solo { grid-template-columns: 1fr; }
}
.nova-hero--solo {
    max-width: 860px;
    margin-inline: auto;
    text-align: center;
}
.nova-hero--solo .nova-hero__lead { margin-inline: auto; }
/* La liste est centrée comme un BLOC, ses lignes restent alignées à gauche :
   centrées une à une, les coches partaient en zigzag. */
.nova-hero--solo .nova-trust { width: fit-content; margin-inline: auto; text-align: left; }

/* La pastille, posée sur le média d'habitude, se met en ligne au-dessus du
   titre quand il n'y a pas de média — elle disparaissait jusque-là. */
.nova-hero__badge--inline {
    position: static;
    display: inline-block;
    max-width: none;
    margin: 0 0 18px;
    box-shadow: none;
}

/* --- Déroulé ------------------------------------------------------------- */

.nova-timeline {
    list-style: none;
    margin: 2em 0;
    padding: 0;
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
    counter-reset: nova-step;
}

.nova-timeline__step {
    position: relative;
    padding: 24px;
    border-radius: var(--nova-radius-lg);
    background: var(--nova-surface);
    border: 1px solid var(--nova-line);
}

.nova--landing .nova-section--dark .nova-timeline__step,
.nova--landing .nova-section--brand .nova-timeline__step {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .16);
}

.nova--document .nova-timeline__step {
    background: var(--bg-elevated);
    border-color: var(--border);
}

/* Le trait qui relie les phases n'apparaît qu'en ligne : empilées, les étapes
   se suivent déjà de haut en bas et un trait horizontal pointerait dans le vide. */
@media (min-width: 820px) {
    .nova-timeline__step:not(:last-child)::after {
        content: '';
        position: absolute;
        top: 50%;
        right: -14px;
        width: 8px;
        height: 8px;
        border-top: 2px solid var(--nova-line);
        border-right: 2px solid var(--nova-line);
        transform: translateY(-50%) rotate(45deg);
    }
}

.nova-timeline__tag {
    display: inline-block;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--nova-accent-2);
    margin-bottom: 10px;
}

/* Les deux fonds sont séparés : l'accent lisible sur un fond sombre ne l'est
   pas forcément sur la couleur principale. Impulsion en est l'exemple — son
   doré tient 12,7:1 sur l'encre et seulement 3,46:1 sur le violet. Une seule
   règle pour les deux, c'est accepter d'avoir tort la moitié du temps. */
.nova--landing .nova-section--dark  .nova-timeline__tag { color: var(--nova-accent-on-dark); }
.nova--landing .nova-section--brand .nova-timeline__tag { color: var(--nova-accent-on-brand); }

.nova-timeline__title {
    font-size: 19px;
    font-weight: 700;
    margin: 0 0 8px;
    color: var(--nova-ink);
}

.nova--landing .nova-section--dark .nova-timeline__title,
.nova--landing .nova-section--brand .nova-timeline__title { color: inherit; }

.nova-timeline__text {
    margin: 0 0 12px;
    font-size: 15px;
    color: var(--nova-muted);
    max-width: none;
}

.nova--landing .nova-section--dark .nova-timeline__text { color: var(--nova-muted-dark); }
/* Manquait (vu le 2026-10-23) : sans elle, le texte d'étape gardait le gris
   des fonds clairs sur la couleur de marque — 1,5:1 environ. */
.nova--landing .nova-section--brand .nova-timeline__text { color: inherit; opacity: 1; }

.nova-timeline__points {
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 14px;
}

.nova-timeline__point {
    padding-left: 16px;
    position: relative;
    margin: 6px 0;
}

.nova-timeline__point::before {
    content: '';
    position: absolute;
    left: 0;
    top: .55em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: .45;
}

/* --- Témoignages --------------------------------------------------------- */

.nova-quotes {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(min(270px, 100%), 1fr));
    margin: 2em 0 1em;
}

.nova-quote {
    margin: 0;
    padding: 24px;
    border-radius: var(--nova-radius-lg);
    background: var(--nova-surface);
    border: 1px solid var(--nova-line);
}

.nova--landing .nova-section--dark .nova-quote,
.nova--landing .nova-section--brand .nova-quote {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .16);
}

.nova--document .nova-quote {
    background: var(--bg-elevated);
    border-color: var(--border);
}

/* ⚠️ Les étoiles ne sont PAS peintes avec l'accent brut. Sur la carte blanche
   d'un témoignage, le doré #ffd700 d'Impulsion mesurait 1,28:1 — pas « un peu
   pâle », invisible. Le défaut était livré depuis le premier jour et n'a été
   trouvé qu'en écrivant le rapport de contraste du lot 8. `accent-on-surface`
   est le même accent poussé jusqu'à 3:1, seuil WCAG des éléments graphiques :
   il reste doré, il se voit. */
.nova--landing .nova-section--dark .nova-quote__stars,
.nova--landing .nova-section--brand .nova-quote__stars {
    /* La carte de témoignage devient sombre dans ces deux sections (fond en
       rgba blanc, quelques lignes plus haut) : l'accent poussé pour du BLANC y
       serait aussi peu lisible que l'accent brut l'était sur du blanc. Chaque
       fond a sa variante, sinon on déplace le défaut au lieu de le corriger. */
    color: var(--nova-accent-on-dark);
}

.nova-quote__stars {
    color: var(--nova-accent-on-surface);
    font-size: 15px;
    letter-spacing: 2px;
    margin-bottom: 12px;
}

.nova-quote__text {
    margin: 0 0 14px;
    font-size: 15px;
    line-height: 1.65;
    font-style: italic;
}

.nova-quote__by {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: 14px;
}

.nova-quote__author { font-weight: 700; }

.nova-quote__meta {
    font-size: 13px;
    color: var(--nova-muted);
}

.nova--landing .nova-section--dark .nova-quote__meta { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-quote__meta { color: inherit; opacity: 1; }   /* même trou, 2026-10-23 */

.nova-disclaimer {
    margin: 0 0 2em;
    font-size: 13px;
    line-height: 1.55;
    color: var(--nova-muted);
    max-width: 70ch;
}

.nova--landing .nova-section--dark .nova-disclaimer { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-disclaimer { color: inherit; opacity: 1; }

/* --- Bloc offre ---------------------------------------------------------- */

.nova-offer {
    display: grid;
    gap: 0;
    border-radius: var(--nova-radius-lg);
    overflow: hidden;
    border: 1px solid var(--nova-line);
    background: var(--nova-surface);
    margin: 2em 0;
}

@media (min-width: 860px) {
    .nova-offer { grid-template-columns: 1.15fr .85fr; }
}

/* Sans produit lié, le panneau de commande est omis : la colonne unique ne doit
   pas rester à 60 % de large avec un vide à droite. */
.nova-offer--nopanel { grid-template-columns: 1fr; }

.nova--landing .nova-section--dark .nova-offer,
.nova--landing .nova-section--brand .nova-offer {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .16);
}

.nova--document .nova-offer {
    background: var(--bg-elevated);
    border-color: var(--border);
}

.nova-offer__copy { padding: clamp(24px, 3.5vw, 40px); }

.nova-offer__title {
    font-size: clamp(24px, 3vw, 32px);
    font-weight: 800;
    margin: 0 0 .5em;
    color: var(--nova-ink);
    line-height: 1.2;
}

.nova--landing .nova-section--dark .nova-offer__title,
.nova--landing .nova-section--brand .nova-offer__title { color: inherit; }

.nova-offer__body { margin: 0 0 1.2em; max-width: none; }

/* Ce qui est inclus. Composant distinct de .nova-checks (la checklist
   décorative) : celle-ci BARRE ses items cochés, ce qui dirait l'inverse de ce
   qu'on veut sur une liste de ce que le client reçoit. */
.nova-includes {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nova-includes__item {
    position: relative;
    padding-left: 30px;
    margin: 10px 0;
    line-height: 1.5;
}

.nova-includes__item::before {
    content: '✓';
    position: absolute;
    left: 0;
    top: .1em;
    width: 20px;
    height: 20px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--nova-primary);
    color: var(--nova-on-primary);
    font-size: 12px;
    font-weight: 700;
}

.nova--landing .nova-section--dark .nova-includes__item::before,
.nova--landing .nova-section--brand .nova-includes__item::before {
    background: var(--nova-accent);
    color: var(--nova-on-accent);
}

.nova-offer__note {
    margin: 1em 0 0;
    font-size: 13px;
    color: var(--nova-muted);
    max-width: none;
}

.nova-offer__panel {
    padding: clamp(24px, 3.5vw, 40px);
    background: var(--nova-dark);
    color: var(--nova-on-dark);
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: center;
}

/* En mode document, le panneau ne doit pas peindre un bloc sombre au milieu
   d'une leçon en thème clair. */
.nova--document .nova-offer__panel {
    background: var(--bg-sunken);
    color: var(--text);
}

.nova-offer__product {
    margin: 0 0 4px;
    font-size: 14px;
    opacity: .75;
    max-width: none;
}

.nova-offer__price {
    margin: 0 0 10px;
    font-size: clamp(34px, 4.5vw, 46px);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -.02em;
    max-width: none;
}

.nova-offer__guarantee {
    margin: 0 0 20px;
    font-size: 13px;
    opacity: .8;
    max-width: none;
}

.nova-offer__cta { align-self: center; }

/* --- Formules (NOVA 4.6.2) ------------------------------------------------
   2 ou 3 cartes côte à côte, chacune liée à une offre. La recommandée porte
   un badge et une bordure ; sur téléphone, les cartes s'empilent et la
   recommandée passe EN PREMIER (order). */
.nova-pricing {
    display: grid;
    gap: 20px;
    align-items: stretch;
    margin: 2.5em auto;
}
.nova-pricing--1 { grid-template-columns: min(480px, 100%); justify-content: center; }
.nova-pricing--2 { grid-template-columns: repeat(2, 1fr); max-width: 900px; }
.nova-pricing--3 { grid-template-columns: repeat(3, 1fr); }

.nova-plan {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 28px 24px 24px;
    background: var(--nova-surface);
    border: 1px solid var(--nova-line);
    border-radius: var(--nova-radius-lg);
    text-align: center;
}
.nova-plan--featured {
    border: 2px solid var(--nova-primary);
    box-shadow: 0 12px 32px rgba(20, 20, 43, .12);
}
.nova-plan__badge {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 4px 14px;
    border-radius: 999px;
    background: var(--nova-primary);
    color: var(--nova-on-primary);
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
}
.nova-plan__title {
    margin: 0 0 4px;
    font-size: 20px;
    font-weight: 800;
    line-height: 1.25;
    color: var(--nova-ink);
}
.nova-plan__name { margin: 0 0 10px; font-size: 14px; color: var(--nova-muted); max-width: none; }
.nova-plan__desc { margin: 0 0 14px; font-size: 15px; line-height: 1.55; color: var(--nova-muted); max-width: none; }
.nova-plan__price {
    margin: 0;
    font-size: clamp(30px, 3.6vw, 40px);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -.02em;
    color: var(--nova-ink);
    max-width: none;
}
.nova-plan__installments { margin: 4px 0 0; font-size: 14px; color: var(--nova-muted); max-width: none; }
.nova-plan__includes { margin: 18px 0 0; text-align: left; }
/* Le ressort pousse le bouton en bas : toutes les cartes alignent leur bouton. */
.nova-plan__spacer { flex: 1 0 22px; }
.nova-plan__cta { align-self: stretch; }
.nova-plan__note { margin: 10px 0 0; font-size: 13px; color: var(--nova-muted); max-width: none; }

.nova--landing .nova-section--dark .nova-plan,
.nova--landing .nova-section--brand .nova-plan {
    background: rgba(255, 255, 255, .07);
    border-color: rgba(255, 255, 255, .16);
}
.nova--landing .nova-section--dark .nova-plan--featured,
.nova--landing .nova-section--brand .nova-plan--featured { border-color: var(--nova-accent); }
.nova--landing .nova-section--dark .nova-plan__badge,
.nova--landing .nova-section--brand .nova-plan__badge {
    background: var(--nova-accent);
    color: var(--nova-on-accent);
}
.nova--landing .nova-section--dark :is(.nova-plan__title, .nova-plan__price),
.nova--landing .nova-section--brand :is(.nova-plan__title, .nova-plan__price) { color: inherit; }
.nova--landing .nova-section--dark :is(.nova-plan__name, .nova-plan__desc, .nova-plan__installments, .nova-plan__note) { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand :is(.nova-plan__name, .nova-plan__desc, .nova-plan__installments, .nova-plan__note) { color: inherit; opacity: 1; }
.nova--document .nova-plan { background: var(--bg-elevated); border-color: var(--border); }

@media (max-width: 860px) {
    .nova-pricing--3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
    .nova-pricing--2,
    .nova-pricing--3 { grid-template-columns: 1fr; gap: 28px; }
    .nova-plan--featured { order: -1; }
}

/* --- Relance finale ------------------------------------------------------ */

.nova-finalcta {
    text-align: center;
    max-width: 760px;
    margin-inline: auto;
}

.nova-finalcta__title {
    font-size: clamp(26px, 3.6vw, 40px);
    font-weight: 800;
    line-height: 1.15;
    margin: 0 0 .5em;
    color: var(--nova-ink);
    text-wrap: balance;
}

.nova--landing .nova-section--dark .nova-finalcta__title,
.nova--landing .nova-section--brand .nova-finalcta__title { color: inherit; }

.nova-finalcta__lead {
    margin: 0 auto 1.6em;
    font-size: 17px;
    color: var(--nova-muted);
    max-width: 52ch;
}

.nova--landing .nova-section--dark .nova-finalcta__lead { color: var(--nova-muted-dark); }
.nova--landing .nova-section--brand .nova-finalcta__lead { color: inherit; opacity: 1; }

/* ==========================================================================
   11. SÉPARATEUR, ESPACEMENT ET TEINTE DE BLOC
   ========================================================================== */

/* Espacement volontaire. Trois tailles seulement : un vide saisi en pixels
   donne, au bout de dix pages, dix-sept valeurs différentes et plus aucun
   rythme vertical. */
.nova-spacer--sm { height: 16px; }
.nova-spacer--md { height: 40px; }
.nova-spacer--lg { height: 80px; }


.nova-delimiter {
    margin: 2.5em auto;
    max-width: 120px;
    border-top: 2px solid var(--nova-line);
    opacity: .7;
}

/* Fond de bloc choisi à la main (tune). La couleur est libre : elle arrive donc
   en propriété personnalisée, pas en classe. */
.nova-tint {
    background: var(--nova-tint, transparent);
    border-radius: var(--nova-radius);
    padding: 20px 24px;
    margin: 1em 0;
}

.nova-tint > *:first-child { margin-top: 0; }
.nova-tint > *:last-child  { margin-bottom: 0; }

/* Fond sombre choisi à la main : le renderer pose --dark après avoir MESURÉ
   quelle encre contraste le plus (2026-10-23). Le texte restait foncé sur
   noir, rouge ou violet. Les titres portent leur propre couleur : ils
   suivent explicitement. */
.nova-tint--dark { color: #ffffff; }
.nova-tint--dark .nova-h,
.nova-tint--dark .nova-card__title,
.nova-tint--dark .nova-faq__q { color: inherit; }
.nova-tint--dark a:where(:not([class])) { color: inherit; text-decoration: underline; }

/* ==========================================================================
   11 bis. AVERTISSEMENT D'APERÇU  (V3 — visible par l'auteur SEULEMENT)
   --------------------------------------------------------------------------
   Signale un bloc qui n'a rien produit : offre sans produit lié, image sans
   fichier, grille vide. Le renderer a raison de ne rien afficher — la page
   publique reste correcte — mais il ne le disait à personne, et le symptôme
   côté auteur était « j'ai mis un bloc, il n'y a rien ».

   ⚠️ DÉLIBÉRÉMENT ÉTRANGER À LA PAGE. Ni la palette, ni les polices, ni les
   rayons du contenu : hachures, mono, ambre. On ne doit jamais pouvoir le
   confondre avec un élément de la page — ni croire qu'il partira en ligne.
   Il n'est rendu qu'en aperçu, lequel exige déjà une session admin valide.
   ========================================================================== */

.nova-notice {
    display: block;
    margin: 20px 0;
    padding: 14px 16px;
    border: 2px dashed #d97706;
    border-radius: 10px;
    background: repeating-linear-gradient(
        45deg, #fffbeb, #fffbeb 10px, #fef3c7 10px, #fef3c7 20px);
    color: #7c2d12;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.5;
    font-style: normal;
    text-align: left;
    /* La page peut être en section sombre : sans cette reprise, l'encart
       hériterait d'une couleur claire et deviendrait illisible sur son propre
       fond ambre — l'avertissement serait invisible, ce qui serait comique. */
    text-shadow: none;
}

.nova-notice__title {
    display: block;
    font-weight: 700;
}

.nova-notice__title::before {
    content: '⚠ ';
}

.nova-notice__hint {
    display: block;
    margin-top: 5px;
    opacity: .85;
}

.nova-notice__only {
    display: block;
    margin-top: 8px;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .06em;
    opacity: .6;
}

/* ==========================================================================
   12. MOUVEMENT
   ========================================================================== */

/* Apparition au défilement — SANS UNE LIGNE DE JAVASCRIPT.
   ─────────────────────────────────────────────────────────
   `animation-timeline: view()` lie l'animation à l'entrée de l'élément dans la
   zone visible. Là où le navigateur ne le connaît pas, la règle est ignorée et
   le contenu s'affiche normalement : c'est une amélioration progressive au sens
   strict.

   ⚠️ C'est ce qui la rend acceptable ici. Un IntersectionObserver aurait exigé
   que les éléments partent en `opacity: 0` — donc qu'une page dont le script ne
   se charge pas soit INVISIBLE. Sur la page qui encaisse, c'est une panne
   totale pour gagner un fondu. Ici, le pire cas est l'absence d'effet.

   Réservé au mode landing : dans une leçon, on relit et on revient en arrière,
   et du texte qui s'anime à chaque passage devient vite pénible. */
@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .nova--landing .nova-section > .nova-section__inner > * {
            animation: nova-reveal linear both;
            animation-timeline: view();
            animation-range: entry 0% cover 22%;
        }
    }
}

@keyframes nova-reveal {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
}

/* Défilement doux vers les ancres (#offre). Posé sur la racine, pas sur .nova :
   c'est la PAGE qui défile, pas le contenu. Et enfermé dans la requête de
   préférence — un défilement animé peut provoquer un vrai malaise chez les
   personnes sensibles au mouvement. */
@media (prefers-reduced-motion: no-preference) {
    html:has(.nova--landing) { scroll-behavior: smooth; }
}

@media (prefers-reduced-motion: reduce) {
    .nova * {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
}

/* Revue NOVA du 2026-11-10 : sur une section de MARQUE, un texte en transparence
   passait sous 4,5:1 (fond = couleur principale, texte = sa couleur lisible).
   Hiérarchie par la taille et la graisse, pas par la transparence. */
.nova--landing .nova-section--brand .nova-offer__product,
.nova--landing .nova-section--brand .nova-offer__guarantee,
.nova--landing .nova-section--brand .nova-citation__by { opacity: 1; }