@charset "utf-8";
/* ============================================================================
 * REDORZO — SOCLE DE CHARTE DE LA VITRINE. UNE SEULE SOURCE, VINGT PAGES.
 *
 * ── POURQUOI CE FICHIER EXISTE ──────────────────────────────────────────────
 *
 * Mesuré le 03/08/2026 et jamais corrigé depuis : `web/` n'avait AUCUN fichier
 * CSS partagé. Ses pages redéclaraient chacune quatre à cinq blocs `:root`.
 * Conséquence pratique — corriger une couleur de la charte, c'était modifier
 * quatorze fichiers sans filet, et la quinzième page naissait toujours avec une
 * valeur de travers.
 *
 * Ce fichier est la source. Une page qui redéclare `:root` est un défaut, et le
 * cliquet `CHARTE-01` de `scripts/ci-checks.mjs` le refuse.
 *
 * ── LA RÈGLE DU FICHIER ─────────────────────────────────────────────────────
 *
 *     AUCUNE VALEUR LITTÉRALE SOUS LA SECTION « COMPOSANTS ».
 *
 * Pas de couleur, pas d'espacement, pas de rayon, pas de durée écrits en dur.
 * Si une valeur manque, elle devient un jeton. C'est la seule discipline qui
 * empêche la dérive de revenir par la porte des composants — celle par laquelle
 * elle est entrée la première fois.
 *
 * ── LA CHARTE NE BOUGE PAS ──────────────────────────────────────────────────
 *
 * Les valeurs de marque, de surface, de texte, de ligne et d'état sont celles de
 * `prototype/tokens.css`, elles-mêmes issues du tableau de bord du greffon,
 * seule surface validée par le client. Ordre du propriétaire, 08/09/2026 : on
 * garde les couleurs. Ce fichier les reprend à l'identique et n'en invente
 * aucune ; ce qu'il ajoute, ce sont des jetons DÉRIVÉS, chacun avec son calcul.
 *
 * ── LE CONTRASTE : CE QUE LA MESURE A MONTRÉ, ET LA SORTIE RETENUE ──────────
 *
 * La liste d'avant-vol porte « le contraste » en rouge depuis le 06/08 avec un
 * chiffre : 4,05 pour du blanc sur le dégradé signature. Ce chiffre regardait
 * UNE extrémité. Recalculé ici sur les deux :
 *
 *     blanc sur #4F6BFF (bleu, début du dégradé)    4,30   sous AA
 *     blanc sur #22D3EE (cyan, fin du dégradé)      1,81   ILLISIBLE
 *
 * La moitié droite de chaque bouton signature portait donc du texte blanc à
 * 1,81. Le propriétaire a tranché le 08/09 : « on laisse » — le blanc reste, la
 * charte ne bouge pas. On tient donc la conformité par la GÉOMÉTRIE :
 *
 *   · le dégradé décoratif garde ses deux bornes exactes (`--rz-sig`) ;
 *   · les surfaces qui portent du texte blanc emploient `--rz-sig-text`, dont
 *     la rampe est étirée à 300 % : la portion visible ne traverse que le
 *     premier tiers, donc le pire fond sous du texte est `--rz-sig-safe`,
 *     mesuré à 3,25 — au-dessus du seuil de 3,0 des textes GRANDS ;
 *   · elles ne portent QUE du texte grand au sens WCAG (≥ 24 px, ou ≥ 18,66 px
 *     en gras). Tout texte de taille normale sur fond de marque prend l'indigo
 *     plein `--rz-brand-strong`, mesuré à 6,29.
 *
 * `scripts/contraste-vitrine.mjs` recalcule tout cela depuis CE fichier, et
 * refuse que `--rz-sig-safe` mente si quelqu'un retire l'étirement.
 * ========================================================================== */

/* ══════════════════════════════════════════════════════ 1. LES JETONS ═══ */

:root {
  color-scheme: light dark;

  /* ---- Marque — valeurs de `prototype/tokens.css`, à l'identique --------- */
  --rz-brand:            #6366F1;
  --rz-brand-strong:     #4F46E5;
  --rz-on-brand:         #FFFFFF;

  /* L'indigo des LIENS et des textes de marque.
   *
   * Ce n'est PAS `--rz-brand`, et le motif est mesuré : #6366F1 donne 4,47 sur
   * blanc et 4,17 sur le fond de page — sous le seuil de 4,5 des deux côtés. Un
   * lien est du texte de taille normale ; il ne peut pas prendre cette valeur.
   * #4F46E5 appartient déjà à la charte et donne 6,29 sur blanc. */
  --rz-brand-ink:        #4F46E5;

  /* ---- Le dégradé signature -------------------------------------------- */
  --rz-sig-a:            #4F6BFF;
  --rz-sig-b:            #22D3EE;

  /* DÉCORATIF — bornes exactes. Liserés, pastilles d'icône, filets, lueurs.
     Jamais de texte par-dessus : le cyan y donne 1,81. */
  --rz-sig:              linear-gradient(100deg, var(--rz-sig-a), var(--rz-sig-b));

  /* PORTEUR DE TEXTE — même dégradé, rampe étirée à 300 %. La portion visible
     s'arrête au tiers, donc au pire à `--rz-sig-safe`. Ne pas retirer le 300 %
     sans refaire la mesure : `contraste-vitrine.mjs` le vérifie. */
  --rz-sig-text:         linear-gradient(100deg, var(--rz-sig-a) 0%, var(--rz-sig-b) 300%);

  /* Le point le plus avancé du dégradé qu'un texte blanc rencontre réellement.
     Interpolation sRGB de sig-a vers sig-b à t = 1/3. Blanc dessus : 3,25. */
  --rz-sig-safe:         #408EF9;

  /* ---- Surfaces --------------------------------------------------------- */
  --rz-bg:               #F6F7FB;
  --rz-surface:          #FFFFFF;
  --rz-surface-2:        #F1F3F9;
  --rz-surface-3:        #E9EDF5;
  --rz-overlay:          rgba(16, 24, 40, .48);

  /* Les bandes sombres de la vitrine — hérité de l'accueil actuel. */
  --rz-ink:              #0B1020;
  --rz-ink-2:            #111A31;
  --rz-ink-text:         #EAF0FF;
  --rz-ink-text-2:       #AEB9D6;
  --rz-ink-line:         rgba(255, 255, 255, .12);
  --rz-ink-line-strong:  rgba(255, 255, 255, .28);
  --rz-ink-surface:      rgba(255, 255, 255, .05);

  /* ---- Texte ------------------------------------------------------------ */
  --rz-text:             #101828;
  --rz-text-2:           #475467;
  /* #98A2B3 de la charte donne 2,58 sur blanc : illisible en texte. La charte
     le garde pour les BORDURES ; pour du texte on emploie la valeur AA. */
  --rz-text-3:           #707784;

  /* ---- Lignes ----------------------------------------------------------- */
  --rz-border:           #E6E9F2;
  --rz-border-strong:    #D6DBE8;

  /* ---- États — fonds, bordures et pastilles ----------------------------- */
  --rz-good:             #12925A;
  --rz-warn:             #C08A1E;
  --rz-crit:             #E5484D;
  --rz-info:             #3B7BD6;
  --rz-good-soft:        rgba(18, 146, 90, .12);
  --rz-warn-soft:        rgba(192, 138, 30, .14);
  --rz-crit-soft:        rgba(229, 72, 77, .12);
  --rz-info-soft:        rgba(59, 123, 214, .12);

  /* ---- États — TEXTE ---------------------------------------------------- */
  /* RÈGLE : `color:` sur un état ⇒ toujours la variante `-text`.
     Fond, bordure, point d'état ⇒ la couleur de base. Le cas le plus exigeant
     n'est pas le texte sur blanc, c'est le texte DANS sa propre pastille, dont
     le fond est teinté de la même couleur et mange le contraste gagné. */
  --rz-good-text:        #0F7C4C;
  --rz-warn-text:        #8E6616;
  --rz-crit-text:        #C13C41;
  --rz-info-text:        #2C5FA8;

  /* Les pastilles APLATIES — le même fond, composé sur la surface, en opaque.
     Elles n'existent que pour être mesurables : un calcul de contraste ne sait
     pas composer une transparence. Elles doivent rester la composition exacte
     de `-soft` sur `--rz-surface`. */
  --rz-good-soft-solid:  #E3F2EB;
  --rz-warn-soft-solid:  #F6EFE0;
  --rz-crit-soft-solid:  #FCE9EA;
  --rz-info-soft-solid:  #E7EFFA;

  /* ---- Focus ------------------------------------------------------------ */
  --rz-ring:             #4F46E5;
  --rz-ring-w:           3px;
  --rz-ring-off:         2px;

  /* ---- Rayons ----------------------------------------------------------- */
  --rz-r-xs:  6px;
  --rz-r-sm:  10px;
  --rz-r-md:  14px;
  --rz-r-lg:  20px;
  --rz-r-xl:  28px;
  --rz-r-pill: 999px;

  /* ---- Ombres ----------------------------------------------------------- */
  --rz-shadow-sm: 0 1px 2px rgba(16, 24, 40, .05), 0 2px 8px rgba(16, 24, 40, .05);
  --rz-shadow-md: 0 8px 24px -10px rgba(16, 24, 40, .16), 0 2px 8px rgba(16, 24, 40, .05);
  --rz-shadow-lg: 0 32px 64px -28px rgba(16, 24, 40, .28), 0 4px 12px rgba(16, 24, 40, .06);
  --rz-shadow-brand: 0 14px 34px -14px rgba(79, 70, 229, .5);

  /* ---- Typographie ------------------------------------------------------ */
  --rz-font-display: "Bricolage Grotesque", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --rz-font-sans:    "Instrument Sans", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --rz-font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Échelle fluide. Les bornes sont calculées pour que `--rz-fs-2xl` reste
     au-dessus de 24 px à toute largeur : c'est la taille à partir de laquelle
     WCAG considère un texte comme GRAND, et donc la condition du blanc sur le
     dégradé. La faire descendre casserait la conformité sans rien afficher. */
  --rz-fs-xs:   .75rem;
  --rz-fs-sm:   .875rem;
  --rz-fs-base: 1rem;
  --rz-fs-md:   1.0625rem;
  --rz-fs-lg:   1.1875rem;
  --rz-fs-xl:   clamp(1.375rem, 1.15rem + .95vw, 1.75rem);
  --rz-fs-2xl:  clamp(1.75rem, 1.35rem + 1.7vw, 2.5rem);
  --rz-fs-3xl:  clamp(2.125rem, 1.5rem + 2.6vw, 3.25rem);
  --rz-fs-4xl:  clamp(2.5rem, 1.55rem + 3.9vw, 4.25rem);

  --rz-lh-tight: 1.08;
  --rz-lh-snug:  1.28;
  --rz-lh-base:  1.62;

  /* ---- Espacement — échelle de 4 px ------------------------------------- */
  --rz-s-1:  4px;   --rz-s-2:  8px;   --rz-s-3:  12px;  --rz-s-4:  16px;
  --rz-s-5:  20px;  --rz-s-6:  24px;  --rz-s-8:  32px;  --rz-s-10: 40px;
  --rz-s-12: 48px;  --rz-s-16: 64px;  --rz-s-20: 80px;  --rz-s-24: 96px;
  --rz-s-32: 128px;

  /* Le rythme vertical d'une section, fluide. */
  --rz-sec-y: clamp(var(--rz-s-16), 7vw, var(--rz-s-32));

  /* ---- Mesures ---------------------------------------------------------- */
  --rz-wrap:      1200px;
  --rz-wrap-tight: 760px;
  --rz-read:      66ch;
  --rz-tap:       44px;   /* cible tactile minimale, au-dessus des 24 px WCAG */

  /* ---- Durées ----------------------------------------------------------- */
  --rz-t-fast: .14s;
  --rz-t-base: .22s;
  --rz-t-slow: .4s;
  --rz-ease:   cubic-bezier(.4, 0, .2, 1);

  /* ---- Plans ------------------------------------------------------------ */
  --rz-z-base: 1;  --rz-z-sticky: 30;  --rz-z-nav: 50;  --rz-z-overlay: 80;
}

/* Le sombre a DEUX déclencheurs, et le choix explicite gagne dans les deux sens.
 * `prefers-color-scheme` porte le défaut du système ; `[data-theme]` porte le
 * choix de l'utilisateur. Le bloc `[data-theme="light"]` plus bas réaffirme le
 * clair — sans lui, quelqu'un en système sombre ne pourrait PAS forcer le clair,
 * et le sélecteur de thème serait à moitié mort.
 *
 * Les deux blocs sombres doivent déclarer EXACTEMENT les mêmes valeurs :
 * `contraste-vitrine.mjs` refuse qu'ils divergent. Deux visiteurs qui se croient
 * dans le même thème ne peuvent pas voir deux sites. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --rz-brand:           #8E97FF;
    --rz-brand-strong:    #A5B0FF;
    --rz-brand-ink:       #A9B2FF;
    --rz-on-brand:        #0B1020;
    --rz-sig-a:           #5B7CFF;
    --rz-sig-b:           #34E0F2;
    --rz-sig-safe:        #4A9CF7;
    --rz-bg:              #080B16;
    --rz-surface:         #111A31;
    --rz-surface-2:       #16203A;
    --rz-surface-3:       #1D2949;
    --rz-overlay:         rgba(4, 6, 12, .66);
    --rz-ink:             #05070F;
    --rz-ink-2:           #0D1425;
    --rz-text:            #EAF0FF;
    --rz-text-2:          #AEB9D6;
    --rz-text-3:          #8B96B4;
    --rz-border:          #212C48;
    --rz-border-strong:   #33405F;
    --rz-good-text:       #34C98A;
    --rz-warn-text:       #FACC5B;
    --rz-crit-text:       #FF8A8E;
    --rz-info-text:       #8FC1FF;
    --rz-good-soft:       rgba(52, 201, 138, .16);
    --rz-warn-soft:       rgba(250, 204, 91, .16);
    --rz-crit-soft:       rgba(255, 138, 142, .16);
    --rz-info-soft:       rgba(143, 193, 255, .16);
    --rz-good-soft-solid: #182F3C;
    --rz-warn-soft-solid: #22283A;
    --rz-crit-soft-solid: #221E36;
    --rz-info-soft-solid: #182740;
    --rz-ring:            #A9B2FF;
    --rz-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --rz-shadow-md: 0 10px 30px -12px rgba(0, 0, 0, .6);
    --rz-shadow-lg: 0 34px 70px -28px rgba(0, 0, 0, .78);
    --rz-shadow-brand: 0 14px 34px -14px rgba(52, 224, 242, .3);
  }
}

:root[data-theme="dark"] {
  --rz-brand:           #8E97FF;
  --rz-brand-strong:    #A5B0FF;
  --rz-brand-ink:       #A9B2FF;
  --rz-on-brand:        #0B1020;
  --rz-sig-a:           #5B7CFF;
  --rz-sig-b:           #34E0F2;
  --rz-sig-safe:        #4A9CF7;
  --rz-bg:              #080B16;
  --rz-surface:         #111A31;
  --rz-surface-2:       #16203A;
  --rz-surface-3:       #1D2949;
  --rz-overlay:         rgba(4, 6, 12, .66);
  --rz-ink:             #05070F;
  --rz-ink-2:           #0D1425;
  --rz-text:            #EAF0FF;
  --rz-text-2:          #AEB9D6;
  --rz-text-3:          #8B96B4;
  --rz-border:          #212C48;
  --rz-border-strong:   #33405F;
  --rz-good-text:       #34C98A;
  --rz-warn-text:       #FACC5B;
  --rz-crit-text:       #FF8A8E;
  --rz-info-text:       #8FC1FF;
  --rz-good-soft:       rgba(52, 201, 138, .16);
  --rz-warn-soft:       rgba(250, 204, 91, .16);
  --rz-crit-soft:       rgba(255, 138, 142, .16);
  --rz-info-soft:       rgba(143, 193, 255, .16);
  --rz-good-soft-solid: #182F3C;
  --rz-warn-soft-solid: #22283A;
  --rz-crit-soft-solid: #221E36;
  --rz-info-soft-solid: #182740;
  --rz-ring:            #A9B2FF;
  --rz-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --rz-shadow-md: 0 10px 30px -12px rgba(0, 0, 0, .6);
  --rz-shadow-lg: 0 34px 70px -28px rgba(0, 0, 0, .78);
  --rz-shadow-brand: 0 14px 34px -14px rgba(52, 224, 242, .3);
}

/* Le clair réaffirmé : sans ce bloc, le sélecteur de thème ne peut pas ramener
   au clair quelqu'un dont le système est en sombre. */
:root[data-theme="light"] {
  --rz-brand:           #6366F1;
  --rz-brand-strong:    #4F46E5;
  --rz-brand-ink:       #4F46E5;
  --rz-on-brand:        #FFFFFF;
  --rz-sig-a:           #4F6BFF;
  --rz-sig-b:           #22D3EE;
  --rz-sig-safe:        #408EF9;
  --rz-bg:              #F6F7FB;
  --rz-surface:         #FFFFFF;
  --rz-surface-2:       #F1F3F9;
  --rz-surface-3:       #E9EDF5;
  --rz-overlay:         rgba(16, 24, 40, .48);
  --rz-ink:             #0B1020;
  --rz-ink-2:           #111A31;
  --rz-text:            #101828;
  --rz-text-2:          #475467;
  --rz-text-3:          #707784;
  --rz-border:          #E6E9F2;
  --rz-border-strong:   #D6DBE8;
  --rz-good-text:       #0F7C4C;
  --rz-warn-text:       #8E6616;
  --rz-crit-text:       #C13C41;
  --rz-info-text:       #2C5FA8;
  --rz-good-soft:       rgba(18, 146, 90, .12);
  --rz-warn-soft:       rgba(192, 138, 30, .14);
  --rz-crit-soft:       rgba(229, 72, 77, .12);
  --rz-info-soft:       rgba(59, 123, 214, .12);
  --rz-good-soft-solid: #E3F2EB;
  --rz-warn-soft-solid: #F6EFE0;
  --rz-crit-soft-solid: #FCE9EA;
  --rz-info-soft-solid: #E7EFFA;
  --rz-ring:            #4F46E5;
  --rz-shadow-sm: 0 1px 2px rgba(16, 24, 40, .05), 0 2px 8px rgba(16, 24, 40, .05);
  --rz-shadow-md: 0 8px 24px -10px rgba(16, 24, 40, .16), 0 2px 8px rgba(16, 24, 40, .05);
  --rz-shadow-lg: 0 32px 64px -28px rgba(16, 24, 40, .28), 0 4px 12px rgba(16, 24, 40, .06);
  --rz-shadow-brand: 0 14px 34px -14px rgba(79, 70, 229, .5);
}

/* ═══════════════════════════════════════════════════ 2. LE SOCLE HTML ═══ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* La barre haute est collante : sans ce décalage, une ancre atterrit dessous
     et le visiteur croit que le lien n'a rien fait. */
  scroll-padding-top: var(--rz-s-20);
}

body {
  background: var(--rz-bg);
  color: var(--rz-text);
  font-family: var(--rz-font-sans);
  font-size: var(--rz-fs-md);
  line-height: var(--rz-lh-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--rz-font-display);
  font-weight: 700;
  letter-spacing: -.025em;
  line-height: var(--rz-lh-tight);
  text-wrap: balance;
}
h1 { font-size: var(--rz-fs-4xl); font-weight: 800; }
h2 { font-size: var(--rz-fs-3xl); }
h3 { font-size: var(--rz-fs-xl); line-height: var(--rz-lh-snug); }
h4 { font-size: var(--rz-fs-lg); line-height: var(--rz-lh-snug); }

p { text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
img, svg, video { max-width: 100%; height: auto; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
strong, b { font-weight: 700; }
ul, ol { list-style: none; }

/* Un seul anneau de focus pour tout le produit, et il est VISIBLE.
   `:focus-visible` seul : un clic à la souris ne doit pas dessiner l'anneau,
   sinon on apprend aux intégrateurs à le retirer. */
:focus-visible {
  outline: var(--rz-ring-w) solid var(--rz-ring);
  outline-offset: var(--rz-ring-off);
  border-radius: var(--rz-r-xs);
}

/* Le mouvement est un confort, jamais une information. Sous
   `prefers-reduced-motion`, tout s'arrête — y compris le défilement doux, qui
   déclenche des malaises vestibulaires chez les personnes concernées. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═════════════════════════════════════════════════ 3. LES COMPOSANTS ═══ */
/*  Rappel de la règle : à partir d'ici, AUCUNE valeur littérale.            */

/* ---- Mise en page ------------------------------------------------------- */

.rz-wrap { width: 100%; max-width: var(--rz-wrap); margin-inline: auto; padding-inline: var(--rz-s-6); }
.rz-wrap-tight { max-width: var(--rz-wrap-tight); }
.rz-sec { padding-block: var(--rz-sec-y); position: relative; }
.rz-sec-sm { padding-block: var(--rz-s-16); }
.rz-read { max-width: var(--rz-read); }
.rz-center { text-align: center; margin-inline: auto; }
.rz-center .rz-read { margin-inline: auto; }

/* Le saut vers le contenu. Premier élément focusable de chaque page : sans lui,
   un visiteur au clavier retraverse la navigation entière à chaque page. */
.rz-skip {
  position: absolute; left: var(--rz-s-4); top: var(--rz-s-4);
  z-index: var(--rz-z-overlay);
  transform: translateY(-200%);
  background: var(--rz-surface); color: var(--rz-text);
  border: 1px solid var(--rz-border-strong); border-radius: var(--rz-r-sm);
  padding: var(--rz-s-3) var(--rz-s-5);
  font-family: var(--rz-font-mono); font-size: var(--rz-fs-sm);
  box-shadow: var(--rz-shadow-md);
  transition: transform var(--rz-t-base) var(--rz-ease);
}
.rz-skip:focus { transform: translateY(0); }

/* ---- Étiquette de section (« eyebrow ») --------------------------------- */

.rz-eyebrow {
  display: inline-flex; align-items: center; gap: var(--rz-s-2);
  font-family: var(--rz-font-mono);
  font-size: var(--rz-fs-xs); font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--rz-brand-ink);
  margin-bottom: var(--rz-s-4);
}
.rz-eyebrow::before {
  content: ""; width: var(--rz-s-6); height: 2px; border-radius: var(--rz-r-pill);
  background: var(--rz-sig); flex: none;
}
.rz-on-ink .rz-eyebrow { color: var(--rz-ink-text); }

/* ---- Titres de section -------------------------------------------------- */

.rz-sec-head { max-width: var(--rz-read); margin-bottom: var(--rz-s-12); }
.rz-sec-head.rz-center { margin-inline: auto; }
.rz-sec-head p {
  font-size: var(--rz-fs-lg); color: var(--rz-text-2);
  margin-top: var(--rz-s-4); max-width: var(--rz-read);
}
.rz-sec-head.rz-center p { margin-inline: auto; }

/* Le mot mis en avant. Il porte le dégradé DÉCORATIF en découpe de texte : ici
   le dégradé est la couleur du glyphe, pas un fond, donc le seuil ne s'applique
   pas de la même façon — et le texte reste lisible parce qu'il est GRAND. */
.rz-hi {
  background: var(--rz-sig); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

/* ---- Boutons ------------------------------------------------------------ */
/*
 * Quatre variantes, six états chacune. Un composant livré sans son état d'erreur
 * ou de chargement est un composant que quelqu'un improvisera au pire moment, et
 * l'improvisation ne sera dans aucun fichier de charte.
 */

.rz-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--rz-s-2);
  min-height: var(--rz-tap);
  padding: var(--rz-s-3) var(--rz-s-6);
  border-radius: var(--rz-r-sm);
  font-family: var(--rz-font-sans);
  font-size: var(--rz-fs-base); font-weight: 600;
  letter-spacing: -.005em; white-space: nowrap;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform var(--rz-t-fast) var(--rz-ease),
              box-shadow var(--rz-t-base) var(--rz-ease),
              background var(--rz-t-base) var(--rz-ease),
              border-color var(--rz-t-base) var(--rz-ease),
              opacity var(--rz-t-base) var(--rz-ease);
}
.rz-btn svg { width: 1.05em; height: 1.05em; stroke: currentColor; stroke-width: 2; fill: none; flex: none; }
.rz-btn:active { transform: translateY(1px); }
.rz-btn[disabled], .rz-btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }

/* Chargement : la largeur ne bouge PAS. Un bouton qui rétrécit pendant sa
   requête déplace ce qu'il y a à côté, et l'utilisateur clique à côté. */
.rz-btn[data-chargement] { pointer-events: none; position: relative; color: transparent; }
.rz-btn[data-chargement]::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 1.1em; height: 1.1em; border-radius: var(--rz-r-pill);
  border: 2px solid currentColor; border-top-color: transparent;
  color: var(--rz-on-brand);
  animation: rz-tourne .7s linear infinite;
}
.rz-btn-ghost[data-chargement]::after, .rz-btn-quiet[data-chargement]::after { color: var(--rz-text); }
@keyframes rz-tourne { to { transform: rotate(1turn); } }

/* PRIMAIRE — indigo plein. C'est le bouton de travail du site : il porte du
   texte de taille normale, donc il lui faut 4,5. Mesuré : 6,29. */
.rz-btn-primary {
  background: var(--rz-brand-strong); color: var(--rz-on-brand);
  box-shadow: var(--rz-shadow-brand);
}
.rz-btn-primary:hover { transform: translateY(-1px); filter: brightness(1.08); }

/* SIGNATURE — le dégradé, réservé aux appels principaux. Taille imposée
   ci-dessous : ≥ 18,66 px en gras, seuil WCAG du texte GRAND. Retirer
   `font-size` ou passer sous 700 casserait la conformité en silence. */
.rz-btn-sig {
  background: var(--rz-sig-text); color: var(--rz-on-brand);
  font-size: var(--rz-fs-lg); font-weight: 700;
  padding: var(--rz-s-4) var(--rz-s-8);
  border-radius: var(--rz-r-md);
  box-shadow: var(--rz-shadow-brand);
}
.rz-btn-sig:hover { transform: translateY(-2px); filter: saturate(1.1); }

/* GHOST — contour, sur fond clair comme sur bande sombre. */
.rz-btn-ghost {
  background: var(--rz-surface); color: var(--rz-text);
  border-color: var(--rz-border-strong);
}
.rz-btn-ghost:hover { border-color: var(--rz-brand-ink); transform: translateY(-1px); }
.rz-on-ink .rz-btn-ghost {
  background: var(--rz-ink-surface); color: var(--rz-ink-text);
  border-color: var(--rz-ink-line);
}
.rz-on-ink .rz-btn-ghost:hover { border-color: var(--rz-ink-line-strong); }

/* QUIET — sans fond ni bordure, pour les actions de second rang. */
.rz-btn-quiet { color: var(--rz-text-2); padding-inline: var(--rz-s-4); }
.rz-btn-quiet:hover { color: var(--rz-text); background: var(--rz-surface-2); }

/* DESTRUCTIF — rouge PLEIN, pas un contour. Une action irréversible doit se
   distinguer AVANT le clic, pas dans la boîte de confirmation. */
.rz-btn-danger { background: var(--rz-crit); color: var(--rz-on-brand); }
.rz-btn-danger:hover { filter: brightness(1.08); }

.rz-btn-lg { font-size: var(--rz-fs-lg); padding: var(--rz-s-4) var(--rz-s-8); border-radius: var(--rz-r-md); }
.rz-btn-block { width: 100%; }

/* ---- Lien texte --------------------------------------------------------- */

.rz-link {
  color: var(--rz-brand-ink); font-weight: 600;
  text-decoration: underline; text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
  transition: text-decoration-color var(--rz-t-base) var(--rz-ease);
}
.rz-link:hover { text-decoration-color: currentColor; }
.rz-on-ink .rz-link { color: var(--rz-ink-text); }

/* La flèche d'un lien d'action, qui avance au survol. */
.rz-arrow { display: inline-flex; align-items: center; gap: var(--rz-s-2); }
.rz-arrow svg { transition: transform var(--rz-t-base) var(--rz-ease); }
.rz-arrow:hover svg { transform: translateX(var(--rz-s-1)); }

/* ---- Cartes ------------------------------------------------------------- */

.rz-card {
  background: var(--rz-surface);
  border: 1px solid var(--rz-border);
  border-radius: var(--rz-r-lg);
  padding: var(--rz-s-8);
  box-shadow: var(--rz-shadow-sm);
  transition: transform var(--rz-t-base) var(--rz-ease),
              box-shadow var(--rz-t-base) var(--rz-ease),
              border-color var(--rz-t-base) var(--rz-ease);
}
.rz-card-hover:hover { transform: translateY(calc(var(--rz-s-1) * -1)); box-shadow: var(--rz-shadow-md); border-color: var(--rz-border-strong); }
.rz-card h3 { margin-bottom: var(--rz-s-3); }
.rz-card p { color: var(--rz-text-2); }
.rz-card-flush { padding: 0; overflow: hidden; }

/* Carte à liseré signature — la marque sans mettre de texte sur le dégradé. */
.rz-card-sig { position: relative; overflow: hidden; }
.rz-card-sig::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0;
  width: var(--rz-s-1); background: var(--rz-sig);
}

/* ---- Pastille d'icône --------------------------------------------------- */

.rz-ico {
  width: var(--rz-s-12); height: var(--rz-s-12);
  border-radius: var(--rz-r-md);
  display: grid; place-items: center;
  background: var(--rz-sig); color: var(--rz-on-brand);
  margin-bottom: var(--rz-s-5); flex: none;
}
.rz-ico svg { width: 55%; height: 55%; stroke: currentColor; stroke-width: 2; fill: none; }
.rz-ico-soft { background: color-mix(in srgb, var(--rz-brand) 14%, transparent); color: var(--rz-brand-ink); }

/* ---- Badges et pastilles d'état ---------------------------------------- */
/*
 * La pastille double TOUJOURS la couleur par la forme et par le mot. Un
 * daltonien lit le point et le libellé ; la couleur seule n'est jamais une
 * information.
 */

.rz-badge {
  display: inline-flex; align-items: center; gap: var(--rz-s-2);
  padding: var(--rz-s-1) var(--rz-s-3);
  border-radius: var(--rz-r-pill);
  font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); font-weight: 500;
  letter-spacing: .04em;
  background: var(--rz-surface-2); color: var(--rz-text-2);
  border: 1px solid var(--rz-border);
}
.rz-badge-good { background: var(--rz-good-soft); color: var(--rz-good-text); border-color: var(--rz-good-soft); }
.rz-badge-warn { background: var(--rz-warn-soft); color: var(--rz-warn-text); border-color: var(--rz-warn-soft); }
.rz-badge-crit { background: var(--rz-crit-soft); color: var(--rz-crit-text); border-color: var(--rz-crit-soft); }
.rz-badge-info { background: var(--rz-info-soft); color: var(--rz-info-text); border-color: var(--rz-info-soft); }

.rz-dot { width: var(--rz-s-2); height: var(--rz-s-2); border-radius: var(--rz-r-pill); background: currentColor; flex: none; }
.rz-dot-good { color: var(--rz-good); }
.rz-dot-warn { color: var(--rz-warn); }
.rz-dot-crit { color: var(--rz-crit); }

/* ---- Grilles ------------------------------------------------------------ */
/*
 * `minmax(0, 1fr)` et non `1fr`. Un enfant de grille a `min-width: auto` par
 * défaut : il refuse de rétrécir sous son contenu et pousse la grille entière
 * au-delà du viewport. C'est le défaut qui a produit trois débordements
 * horizontaux dans le prototype, et corriger la CLASSE plutôt que les trois
 * instances est ce qui a évité le quatrième.
 */
.rz-grid { display: grid; gap: var(--rz-s-6); }
.rz-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rz-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rz-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rz-split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rz-s-16); align-items: center; }
.rz-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--rz-s-3); min-width: 0; }
.rz-row > * { min-width: 0; }

/* ---- Bandes sombres ----------------------------------------------------- */

.rz-ink {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--rz-ink); color: var(--rz-ink-text);
}
.rz-ink h1, .rz-ink h2, .rz-ink h3 { color: var(--rz-ink-text); }
.rz-ink p { color: var(--rz-ink-text-2); }
.rz-aurore { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
.rz-aurore i {
  position: absolute; display: block; border-radius: var(--rz-r-pill);
  filter: blur(90px); opacity: .55;
}
.rz-aurore i:nth-child(1) { width: 46%; padding-top: 46%; left: -6%; top: -18%; background: var(--rz-sig-a); }
.rz-aurore i:nth-child(2) { width: 44%; padding-top: 44%; right: -4%; top: 4%; background: var(--rz-sig-b); opacity: .35; }
.rz-aurore i:nth-child(3) { width: 38%; padding-top: 38%; left: 38%; bottom: -20%; background: var(--rz-brand); opacity: .3; }

/* ---- Barre de navigation ----------------------------------------------- */
/*
 * MESURÉ LE 08/09/2026 sur l'accueil précédent, largeur 1 440 px, thème sombre :
 * la barre DÉBORDAIT et passait sur deux lignes. « TOP TRANSLATE »,
 * « TOP CALENDAR » et « Se connecter » se coupaient en deux mots, sur un écran
 * d'ordinateur ordinaire — sept entrées, plus un sélecteur de thème, plus un
 * lien de connexion, plus le bouton d'appel.
 *
 * Le correctif n'est pas de rétrécir la police : c'est d'élaguer le menu. Il
 * porte quatre entrées. Et `white-space: nowrap` sur chacune fait qu'un
 * débordement futur se verra tout de suite au lieu de se cacher en repliant un
 * mot.
 */

.rz-nav {
  position: sticky; top: 0; z-index: var(--rz-z-nav);
  background: color-mix(in srgb, var(--rz-bg) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid transparent;
  transition: border-color var(--rz-t-base) var(--rz-ease), background var(--rz-t-base) var(--rz-ease);
}
.rz-nav[data-defile] { border-bottom-color: var(--rz-border); }

/* La barre EN TÊTE D'UNE PAGE QUI OUVRE SUR UNE BANDE SOMBRE.
 *
 * Sans ça, une barre claire au-dessus d'un héros sombre dessine une couture
 * nette en travers du premier écran : le héros ne se lit plus comme un héros
 * mais comme une bannière collée sous un bandeau.
 *
 * ── MA PREMIÈRE VERSION LA RENDAIT TRANSPARENTE. ELLE ÉTAIT FAUSSE. ────────
 *
 * Cette barre est `sticky`, donc DANS LE FLUX : au repos elle se place AU-DESSUS
 * du héros, pas par-dessus. Une barre transparente laissait donc voir le fond du
 * corps — clair en thème clair — et le texte clair devenait invisible dessus. En
 * thème sombre le défaut ne se voyait pas, puisque le fond du corps y est sombre
 * lui aussi : exactement le genre de défaut qui traverse une revue.
 *
 * Elle prend donc la COULEUR DE LA BANDE. Les deux se touchent, partagent la
 * même valeur, et se lisent comme un seul bloc — sans couture, et sans jamais
 * dépendre de ce qu'il y a derrière. */
.rz-nav[data-sur-ink]:not([data-defile]) {
  background: var(--rz-ink);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.rz-nav[data-sur-ink]:not([data-defile]) .rz-brand { color: var(--rz-ink-text); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-nav-links a { color: var(--rz-ink-text-2); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-nav-links a:hover { color: var(--rz-ink-text); background: var(--rz-ink-surface); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-icon-btn { color: var(--rz-ink-text-2); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-icon-btn:hover { color: var(--rz-ink-text); background: var(--rz-ink-surface); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-btn-quiet { color: var(--rz-ink-text-2); }
.rz-nav[data-sur-ink]:not([data-defile]) .rz-btn-quiet:hover { color: var(--rz-ink-text); background: var(--rz-ink-surface); }
.rz-nav-in {
  max-width: var(--rz-wrap); margin-inline: auto;
  padding: var(--rz-s-3) var(--rz-s-6);
  display: flex; align-items: center; gap: var(--rz-s-5);
  min-width: 0;
}

/* LA MARQUE S'ÉCRIT EN CAPITALES — décision du propriétaire, 08/09/2026 :
 * « REDORZO est la marque et le logo ».
 *
 * Le calage typographique change avec elle, et ce n'est pas cosmétique : le
 * `-.03em` était réglé pour un bas-de-casse, où les jambages laissent de l'air.
 * Appliqué à des capitales d'un grotesque en graisse 800, il les fait se
 * toucher — et une marque dont les lettres se touchent se lit comme un défaut
 * d'affichage, pas comme un logo. On desserre, et on descend d'un cran en
 * taille pour que le bloc garde la même présence qu'avant. */
.rz-brand {
  display: inline-flex; align-items: center; gap: var(--rz-s-3);
  font-family: var(--rz-font-display); font-weight: 800;
  font-size: var(--rz-fs-base); letter-spacing: .02em;
  color: var(--rz-text); flex: none;
}
.rz-brand-mark {
  width: var(--rz-s-8); height: var(--rz-s-8);
  border-radius: var(--rz-r-sm);
  background: var(--rz-sig); color: var(--rz-on-brand);
  display: grid; place-items: center;
  font-size: var(--rz-fs-base); font-weight: 800;
  box-shadow: var(--rz-shadow-brand); flex: none;
}

.rz-nav-links { display: flex; align-items: center; gap: var(--rz-s-1); min-width: 0; }
.rz-nav-links a {
  padding: var(--rz-s-2) var(--rz-s-3);
  border-radius: var(--rz-r-xs);
  font-size: var(--rz-fs-sm); font-weight: 600;
  color: var(--rz-text-2); white-space: nowrap;
  transition: color var(--rz-t-fast) var(--rz-ease), background var(--rz-t-fast) var(--rz-ease);
}
.rz-nav-links a:hover { color: var(--rz-text); background: var(--rz-surface-2); }
.rz-nav-links a[aria-current="page"] { color: var(--rz-brand-ink); background: color-mix(in srgb, var(--rz-brand) 10%, transparent); }

.rz-nav-end { margin-inline-start: auto; display: flex; align-items: center; gap: var(--rz-s-2); flex: none; }
.rz-nav-end .rz-btn { font-size: var(--rz-fs-sm); padding-inline: var(--rz-s-5); }

.rz-icon-btn {
  width: var(--rz-tap); height: var(--rz-tap);
  border-radius: var(--rz-r-sm);
  display: grid; place-items: center;
  color: var(--rz-text-2);
  border: 1px solid transparent;
  transition: background var(--rz-t-fast) var(--rz-ease), color var(--rz-t-fast) var(--rz-ease);
}
.rz-icon-btn:hover { background: var(--rz-surface-2); color: var(--rz-text); }
.rz-icon-btn svg { width: var(--rz-s-5); height: var(--rz-s-5); stroke: currentColor; stroke-width: 1.9; fill: none; }
.rz-icon-btn .rz-sun { display: none; }
:root[data-theme="dark"] .rz-icon-btn .rz-sun { display: block; }
:root[data-theme="dark"] .rz-icon-btn .rz-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rz-icon-btn .rz-sun { display: block; }
  :root:not([data-theme="light"]) .rz-icon-btn .rz-moon { display: none; }
}

.rz-burger { display: none; }

/* La barre d'appel du mobile.
 *
 * MESURÉ le 08/09/2026 avec un VRAI viewport de 390 px : la barre haute portant
 * marque + thème + bouton d'appel + menu réclamait 427 px. Elle débordait.
 *
 * Entasser le bouton d'appel dans une barre trop étroite le rend illisible et
 * le fait perdre. On le sort donc de la barre haute sous 720 px — et on le
 * remet là où le pouce se trouve déjà. Ce n'est pas un repli : sur un téléphone,
 * un appel collé en bas d'écran est vu et cliqué plus souvent qu'un bouton en
 * haut à droite.
 *
 * `PORTE-03` ne s'en trouve pas gêné : il ne retient que la PREMIÈRE occurrence
 * du bouton dans chaque fichier, et c'est celle de la barre haute. */
.rz-cta-mobile {
  display: none;
  position: fixed; inset-inline: 0; bottom: 0; z-index: var(--rz-z-sticky);
  transition: transform var(--rz-t-base) var(--rz-ease);
  padding: var(--rz-s-3) var(--rz-s-4);
  padding-bottom: max(var(--rz-s-3), env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--rz-bg) 92%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--rz-border);
}
.rz-cta-mobile .rz-btn { width: 100%; }

/* Elle s'efface tant que l'appel du premier écran est encore à l'écran : sinon
   le visiteur voit DEUX fois le même bouton sur son premier écran, ce qui donne
   l'impression d'une page mal montée plutôt que d'une insistance utile.
 *
 * LA POLARITÉ COMPTE, et ma première rédaction l'avait à l'envers : elle
 * masquait par défaut et demandait au script de montrer. Chez quelqu'un dont le
 * script ne charge pas, le bouton d'achat n'existait alors plus du tout. Le
 * défaut par défaut doit toujours être celui qui vend. */
.rz-cta-mobile[data-cache] { transform: translateY(100%); }

/* Le tiroir mobile. `hidden` porte l'état — pas `display` en ligne — pour que
   le contenu reste hors de l'ordre de tabulation quand il est fermé. */
.rz-drawer {
  position: fixed; inset: 0; z-index: var(--rz-z-overlay);
  background: var(--rz-bg);
  padding: var(--rz-s-6);
  display: flex; flex-direction: column; gap: var(--rz-s-2);
  overflow-y: auto;
}
.rz-drawer[hidden] { display: none !important; }
.rz-drawer-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--rz-s-8); }
.rz-drawer a {
  padding: var(--rz-s-4);
  border-radius: var(--rz-r-sm);
  font-size: var(--rz-fs-lg); font-weight: 600;
  border-bottom: 1px solid var(--rz-border);
}
.rz-drawer .rz-btn { margin-top: var(--rz-s-6); border-bottom: none; }

/* ---- Pied de page ------------------------------------------------------- */

.rz-foot { background: var(--rz-surface); border-top: 1px solid var(--rz-border); padding-block: var(--rz-s-16) var(--rz-s-8); }
.rz-foot-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(0, 1fr)); gap: var(--rz-s-10); }
.rz-foot h4 { font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--rz-text-3); margin-bottom: var(--rz-s-4); }
.rz-foot ul { display: flex; flex-direction: column; gap: var(--rz-s-3); }
.rz-foot ul a { font-size: var(--rz-fs-sm); color: var(--rz-text-2); }
.rz-foot ul a:hover { color: var(--rz-brand-ink); }
.rz-foot-bas { margin-top: var(--rz-s-12); padding-top: var(--rz-s-6); border-top: 1px solid var(--rz-border); display: flex; flex-wrap: wrap; gap: var(--rz-s-4); justify-content: space-between; font-size: var(--rz-fs-sm); color: var(--rz-text-3); }

/* ---- Tableau ------------------------------------------------------------ */
/*
 * Un tableau large défile DANS son conteneur, jamais en poussant la page. Le
 * corps du document ne défile jamais horizontalement.
 */
.rz-table-wrap { overflow-x: auto; border: 1px solid var(--rz-border); border-radius: var(--rz-r-lg); background: var(--rz-surface); }
.rz-table { width: 100%; border-collapse: collapse; font-size: var(--rz-fs-base); }
.rz-table th, .rz-table td { padding: var(--rz-s-4) var(--rz-s-5); text-align: start; border-bottom: 1px solid var(--rz-border); vertical-align: top; }
.rz-table thead th { font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: var(--rz-text-3); background: var(--rz-surface-2); white-space: nowrap; }
.rz-table tbody tr:last-child td { border-bottom: none; }
.rz-table td strong { color: var(--rz-text); }
.rz-num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.rz-table-mark { background: color-mix(in srgb, var(--rz-brand) 6%, transparent); }

/* ---- Questions fréquentes ---------------------------------------------- */

.rz-faq { border: 1px solid var(--rz-border); border-radius: var(--rz-r-lg); background: var(--rz-surface); overflow: hidden; }
.rz-faq details { border-bottom: 1px solid var(--rz-border); }
.rz-faq details:last-child { border-bottom: none; }
.rz-faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--rz-s-4);
  padding: var(--rz-s-5) var(--rz-s-6);
  font-size: var(--rz-fs-md); font-weight: 600;
  cursor: pointer; list-style: none;
  min-height: var(--rz-tap);
  transition: background var(--rz-t-fast) var(--rz-ease);
}
.rz-faq summary::-webkit-details-marker { display: none; }
.rz-faq summary:hover { background: var(--rz-surface-2); }
.rz-faq summary::after {
  content: ""; flex: none;
  width: var(--rz-s-3); height: var(--rz-s-3);
  border-right: 2px solid var(--rz-text-3); border-bottom: 2px solid var(--rz-text-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--rz-t-base) var(--rz-ease);
}
.rz-faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.rz-faq .rz-faq-body { padding: 0 var(--rz-s-6) var(--rz-s-6); color: var(--rz-text-2); max-width: var(--rz-read); }

/* ---- Étapes numérotées -------------------------------------------------- */

.rz-steps { counter-reset: rz-step; display: grid; gap: var(--rz-s-8); }
.rz-step { position: relative; padding-inline-start: var(--rz-s-16); counter-increment: rz-step; }
.rz-step::before {
  content: counter(rz-step);
  position: absolute; inset-inline-start: 0; top: 0;
  width: var(--rz-s-12); height: var(--rz-s-12);
  border-radius: var(--rz-r-md);
  background: var(--rz-sig); color: var(--rz-on-brand);
  display: grid; place-items: center;
  font-family: var(--rz-font-display);
  /* ≥ 24 px : texte GRAND au sens WCAG, condition du blanc sur le dégradé. */
  font-size: var(--rz-fs-xl); font-weight: 800;
}
.rz-step h3 { margin-bottom: var(--rz-s-2); }
.rz-step p { color: var(--rz-text-2); max-width: var(--rz-read); }

/* ---- Liste à coches ----------------------------------------------------- */

.rz-checks { display: grid; gap: var(--rz-s-3); }
.rz-checks li { display: flex; align-items: flex-start; gap: var(--rz-s-3); color: var(--rz-text-2); }
.rz-checks svg { width: var(--rz-s-5); height: var(--rz-s-5); flex: none; margin-top: var(--rz-s-1); stroke: var(--rz-good); stroke-width: 2.4; fill: none; }
.rz-checks .rz-no svg { stroke: var(--rz-text-3); }

/* ---- Encart d'avertissement / d'information ---------------------------- */

.rz-note {
  border: 1px solid var(--rz-border);
  border-inline-start: var(--rz-s-1) solid var(--rz-brand);
  border-radius: var(--rz-r-md);
  background: var(--rz-surface-2);
  padding: var(--rz-s-5) var(--rz-s-6);
  color: var(--rz-text-2);
  max-width: var(--rz-read);
}
.rz-note strong { color: var(--rz-text); }
.rz-note-good { border-inline-start-color: var(--rz-good); background: var(--rz-good-soft); }
.rz-note-warn { border-inline-start-color: var(--rz-warn); background: var(--rz-warn-soft); }
.rz-note-crit { border-inline-start-color: var(--rz-crit); background: var(--rz-crit-soft); }

/* ---- Formulaires -------------------------------------------------------- */

.rz-field { display: grid; gap: var(--rz-s-2); margin-bottom: var(--rz-s-5); }
.rz-label { font-size: var(--rz-fs-sm); font-weight: 600; color: var(--rz-text); }
.rz-hint { font-size: var(--rz-fs-sm); color: var(--rz-text-3); }
.rz-input, .rz-select, .rz-textarea {
  width: 100%;
  min-height: var(--rz-tap);
  padding: var(--rz-s-3) var(--rz-s-4);
  border: 1px solid var(--rz-border-strong);
  border-radius: var(--rz-r-sm);
  background: var(--rz-surface);
  color: var(--rz-text);
  font-size: var(--rz-fs-base);
  transition: border-color var(--rz-t-fast) var(--rz-ease), box-shadow var(--rz-t-fast) var(--rz-ease);
}
.rz-input::placeholder, .rz-textarea::placeholder { color: var(--rz-text-3); }
.rz-input:hover, .rz-select:hover, .rz-textarea:hover { border-color: var(--rz-brand); }
.rz-textarea { min-height: calc(var(--rz-s-32) + var(--rz-s-4)); resize: vertical; line-height: var(--rz-lh-base); }
.rz-select { appearance: none; padding-inline-end: var(--rz-s-10); background-image: none; }
.rz-field[data-erreur] .rz-input,
.rz-field[data-erreur] .rz-select,
.rz-field[data-erreur] .rz-textarea { border-color: var(--rz-crit); }
.rz-err { font-size: var(--rz-fs-sm); color: var(--rz-crit-text); display: flex; align-items: center; gap: var(--rz-s-2); }

/* ---- États vides, chargement, erreur ------------------------------------ */

.rz-empty { text-align: center; padding: var(--rz-s-16) var(--rz-s-6); color: var(--rz-text-2); }
.rz-empty h3 { color: var(--rz-text); margin-bottom: var(--rz-s-3); }
.rz-skel {
  background: linear-gradient(90deg, var(--rz-surface-2) 25%, var(--rz-surface-3) 37%, var(--rz-surface-2) 63%);
  background-size: 400% 100%;
  border-radius: var(--rz-r-xs);
  animation: rz-skel 1.4s var(--rz-ease) infinite;
}
@keyframes rz-skel { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ---- Captures d'écran des produits -------------------------------------- */
/*
 * ── POURQUOI CE COMPOSANT EXISTE, ET CE QU'IL RÉSOUT ──────────────────────
 *
 * Le site vendait une console que personne ne voyait. C'est le manque le plus
 * coûteux d'une page produit : un acheteur veut savoir à quoi ressemble l'écran
 * dans lequel il passera son temps, et aucune description ne remplace une image.
 *
 * ── LES DEUX RÈGLES QUI ÉVITENT LES DEUX DÉFAUTS CLASSIQUES ───────────────
 *
 * 1. `width` et `height` sont OBLIGATOIRES sur chaque `<img>`, et le cliquet
 *    `CAPTURE-01` les exige. Sans eux, le navigateur ne connaît pas la place à
 *    réserver : la page saute au moment où l'image arrive, sous les doigts de
 *    quelqu'un qui était en train de lire. C'est mesuré par le décalage
 *    cumulé, et c'est le défaut de performance le plus visible qui soit.
 *
 * 2. `loading="lazy"` partout SAUF la première image visible. Charger en
 *    différé une image du premier écran retarde précisément celle qu'on attend.
 */
.rz-shot { margin: 0; }
.rz-shot-cadre {
  border: 1px solid var(--rz-border);
  border-radius: var(--rz-r-lg);
  background: var(--rz-surface);
  box-shadow: var(--rz-shadow-lg);
  overflow: hidden;
}
.rz-on-ink .rz-shot-cadre { border-color: var(--rz-ink-line); background: var(--rz-ink-surface); }

/* La barre de fenêtre. Elle situe la capture — « ceci est un écran, pas un
   schéma » — et c'est ce qui la rend crédible en une fraction de seconde. */
.rz-shot-barre {
  display: flex; align-items: center; gap: var(--rz-s-2);
  padding: var(--rz-s-3) var(--rz-s-4);
  border-bottom: 1px solid var(--rz-border);
  background: var(--rz-surface-2);
}
.rz-on-ink .rz-shot-barre { border-bottom-color: var(--rz-ink-line); background: var(--rz-ink-surface); }
.rz-shot-barre i { width: var(--rz-s-3); height: var(--rz-s-3); border-radius: var(--rz-r-pill); background: var(--rz-border-strong); flex: none; }
.rz-shot-url {
  flex: 1; margin-inline-start: var(--rz-s-2);
  font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs);
  color: var(--rz-text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rz-on-ink .rz-shot-url { color: var(--rz-ink-text-2); }
.rz-shot img { display: block; width: 100%; height: auto; }
.rz-shot figcaption {
  margin-top: var(--rz-s-4);
  font-size: var(--rz-fs-sm); color: var(--rz-text-2);
  max-width: var(--rz-read);
}
.rz-on-ink .rz-shot figcaption { color: var(--rz-ink-text-2); }
.rz-shot-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rz-s-8); }
@media (max-width: 860px) { .rz-shot-grid { grid-template-columns: minmax(0, 1fr); } }

/* ---- Utilitaires -------------------------------------------------------- */

.rz-mono { font-family: var(--rz-font-mono); }
.rz-muted { color: var(--rz-text-2); }
.rz-small { font-size: var(--rz-fs-sm); }
.rz-mt-4 { margin-top: var(--rz-s-4); }
.rz-mt-6 { margin-top: var(--rz-s-6); }
.rz-mt-8 { margin-top: var(--rz-s-8); }
.rz-mt-12 { margin-top: var(--rz-s-12); }
.rz-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ═════════════════════════════════════════════════════ 4. RESPONSIVE ═══ */

@media (max-width: 1080px) {
  .rz-foot-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 960px) {
  .rz-nav-links, .rz-nav-end .rz-desk { display: none; }
  .rz-burger { display: grid; }
  .rz-split { grid-template-columns: minmax(0, 1fr); gap: var(--rz-s-10); }
  .rz-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rz-grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  body { font-size: var(--rz-fs-base); }
  /* La barre haute ne garde que la marque et le menu — mesuré : au-delà, elle
     déborde. L'appel et le sélecteur de thème passent dans le tiroir, et
     l'appel réapparaît collé en bas. */
  .rz-nav-end .rz-btn-primary, .rz-nav-end [data-rz-theme] { display: none; }
  .rz-cta-mobile { display: block; }
  /* Sans cette réserve, la barre collée recouvre la fin du pied de page. */
  body { padding-bottom: var(--rz-s-20); }
  .rz-grid-2, .rz-grid-3, .rz-grid-4 { grid-template-columns: minmax(0, 1fr); }
  .rz-foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rz-s-8); }
  .rz-card { padding: var(--rz-s-6); }
  .rz-step { padding-inline-start: var(--rz-s-12); }
  .rz-step::before { width: var(--rz-s-10); height: var(--rz-s-10); font-size: var(--rz-fs-lg); }
  .rz-btn-block-sm { width: 100%; }
}

@media (max-width: 480px) {
  .rz-foot-grid { grid-template-columns: minmax(0, 1fr); }
  .rz-wrap { padding-inline: var(--rz-s-4); }
}


/* ═══════════════════════════════════════════ 5. MOTIFS DE VITRINE ═══ */
/*
 * Ces motifs servaient d'abord à l'accueil. Trois autres pages les emploient :
 * les laisser dans le `<style>` de chaque page aurait recréé, en une journée,
 * exactement la dette qu'on vient de solder — quatorze pages redéclarant chacune
 * leur charte. Ce qui sert deux fois vit ici.
 */

.hero { padding-block: var(--rz-s-24) var(--rz-s-20); }
.hero-grid { display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr); gap: var(--rz-s-16); align-items: center; }
.hero h1 { margin-block: var(--rz-s-5) var(--rz-s-6); }
.hero-lead { font-size: var(--rz-fs-lg); color: var(--rz-ink-text-2); max-width: 40ch; }
.hero-lead strong { color: var(--rz-ink-text); font-weight: 600; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--rz-s-3); margin-top: var(--rz-s-8); }
.hero-trust { display: flex; flex-wrap: wrap; gap: var(--rz-s-5); margin-top: var(--rz-s-8); font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); color: var(--rz-ink-text-2); letter-spacing: .03em; }
.hero-trust span { display: inline-flex; align-items: center; gap: var(--rz-s-2); }

/* La fenêtre de démonstration. Tout son texte est du HTML, jamais du SVG : le
   contenu d'un `<svg>` n'est jamais traduit par le moteur, et cette fenêtre est
   l'argument principal de la page — elle doit exister dans les 30 langues. */
.fenetre { border: 1px solid var(--rz-ink-line); border-radius: var(--rz-r-lg); background: var(--rz-ink-surface); overflow: hidden; box-shadow: var(--rz-shadow-lg); }
.fenetre-barre { display: flex; align-items: center; gap: var(--rz-s-2); padding: var(--rz-s-3) var(--rz-s-4); border-bottom: 1px solid var(--rz-ink-line); }
.fenetre-barre i { width: var(--rz-s-3); height: var(--rz-s-3); border-radius: var(--rz-r-pill); background: var(--rz-ink-line-strong); flex: none; }
.fenetre-url { flex: 1; margin-inline-start: var(--rz-s-2); background: var(--rz-ink-surface); border-radius: var(--rz-r-xs); padding: var(--rz-s-1) var(--rz-s-3); font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); color: var(--rz-ink-text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fenetre-corps { padding: var(--rz-s-6); }
.fenetre-corps h3 { font-size: var(--rz-fs-xl); margin-bottom: var(--rz-s-2); }
.fenetre-corps p { font-size: var(--rz-fs-sm); }
.fenetre-prix { font-family: var(--rz-font-display); font-weight: 700; color: var(--rz-sig-b); margin-top: var(--rz-s-3); }
.fenetre-langues { display: flex; flex-wrap: wrap; gap: var(--rz-s-2); margin-top: var(--rz-s-6); padding-top: var(--rz-s-5); border-top: 1px solid var(--rz-ink-line); }
.fenetre-langues span { font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); padding: var(--rz-s-1) var(--rz-s-2); border-radius: var(--rz-r-xs); background: var(--rz-ink-surface); border: 1px solid var(--rz-ink-line); color: var(--rz-ink-text-2); }
.fenetre-langues span.actif { border-color: var(--rz-sig-b); color: var(--rz-ink-text); }

/* La bande de compatibilité. */
.stack { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--rz-s-6) var(--rz-s-10); font-family: var(--rz-font-display); font-weight: 700; font-size: var(--rz-fs-lg); color: var(--rz-text-3); }

/* Le schéma « widget contre serveur ». */
.duo { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--rz-s-6); }
.duo-carte { padding: var(--rz-s-6); border-radius: var(--rz-r-lg); border: 1px solid var(--rz-border); background: var(--rz-surface); }
.duo-carte h3 { font-size: var(--rz-fs-lg); margin-bottom: var(--rz-s-4); display: flex; align-items: center; gap: var(--rz-s-3); }
.duo-mal { border-color: color-mix(in srgb, var(--rz-crit) 30%, var(--rz-border)); }
.duo-bien { border-color: color-mix(in srgb, var(--rz-good) 34%, var(--rz-border)); }
.duo-ligne { font-family: var(--rz-font-mono); font-size: var(--rz-fs-sm); padding: var(--rz-s-3) var(--rz-s-4); border-radius: var(--rz-r-sm); background: var(--rz-surface-2); margin-bottom: var(--rz-s-2); display: flex; align-items: center; justify-content: space-between; gap: var(--rz-s-3); }
.duo-ligne b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; }
.duo-verdict { margin-top: var(--rz-s-5); font-weight: 600; display: flex; align-items: center; gap: var(--rz-s-2); }
.duo-mal .duo-verdict { color: var(--rz-crit-text); }
.duo-bien .duo-verdict { color: var(--rz-good-text); }

/* La grille de prix. */
.paliers { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--rz-s-3); }
.palier { border: 1px solid var(--rz-border); border-radius: var(--rz-r-md); background: var(--rz-surface); padding: var(--rz-s-5); }
.palier-nom { font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); letter-spacing: .1em; text-transform: uppercase; color: var(--rz-text-3); }
.palier-prix { font-family: var(--rz-font-display); font-size: var(--rz-fs-xl); font-weight: 800; margin-block: var(--rz-s-2) var(--rz-s-1); }
.palier-taille { font-size: var(--rz-fs-sm); color: var(--rz-text-2); }

/* L'écosystème. Les noms de classe `ecard` et `etag` sont ceux que VITRINE-01
   attend : il découpe chaque carte sur `<div class="ecard` et lit l'état sur
   `etag on` / `etag soon`. Les renommer rendrait le cliquet aveugle — et un
   cliquet aveugle est vert sur du vide. */
.ecard { position: relative; display: flex; flex-direction: column; gap: var(--rz-s-3); padding: var(--rz-s-6); border: 1px solid var(--rz-border); border-radius: var(--rz-r-lg); background: var(--rz-surface); transition: transform var(--rz-t-base) var(--rz-ease), box-shadow var(--rz-t-base) var(--rz-ease); }
.ecard:hover { transform: translateY(calc(var(--rz-s-1) * -1)); box-shadow: var(--rz-shadow-md); }
/* `ec-tete` et NON `ecard-tete`, et ce n'est pas une préférence.
 * `VITRINE-01` découpe chaque carte en cherchant `<div class="ecard` — un
 * PRÉFIXE. Une classe `ecard-tete` le satisfait aussi, donc le découpage
 * commençait APRÈS l'étiquette d'état, et les cinq produits étaient déclarés
 * mal étiquetés. Le cliquet a été resserré du même coup ; ce nom garde les deux
 * lectures sans ambiguïté. */
.ec-tete { display: flex; align-items: center; gap: var(--rz-s-3); }
.ec-lettre { width: var(--rz-s-10); height: var(--rz-s-10); border-radius: var(--rz-r-sm); display: grid; place-items: center; font-family: var(--rz-font-display); font-size: var(--rz-fs-xl); font-weight: 800; color: var(--rz-on-brand); flex: none; }
.ecard h3 { font-size: var(--rz-fs-lg); }
.ecard p { font-size: var(--rz-fs-sm); color: var(--rz-text-2); flex: 1; }
.etag { display: inline-flex; align-items: center; gap: var(--rz-s-2); align-self: flex-start; padding: var(--rz-s-1) var(--rz-s-3); border-radius: var(--rz-r-pill); font-family: var(--rz-font-mono); font-size: var(--rz-fs-xs); }
.etag.on { background: var(--rz-good-soft); color: var(--rz-good-text); }
.etag.soon { background: var(--rz-surface-2); color: var(--rz-text-2); }

@media (max-width: 960px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); gap: var(--rz-s-10); }
  .hero { padding-block: var(--rz-s-16) var(--rz-s-16); }
  .duo, .paliers { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
  .hero-actions .rz-btn { width: 100%; }
}


/* ══════════════════════════════════════════ 6. ALIAS DE MIGRATION ═══ */
/*
 * ── POURQUOI CE BLOC EXISTE, ET POURQUOI IL EST UNE DETTE ──────────────────
 *
 * Dix pages de `web/` n'ont pas été refaites à blanc : elles encaissent
 * l'argent, délivrent les licences, prouvent la propriété d'un domaine et
 * portent des documents comptables immuables. `platform.html` fait 96 Ko —
 * c'est une application, pas une page. Les réécrire en même temps que le
 * message, ce serait risquer la boutique pour gagner du pixel.
 *
 * Elles portent donc leur propre CSS de composants, écrit avec l'ANCIEN
 * vocabulaire (`--brand`, `--line`, `--g1`…). Ce bloc fait vivre ces noms en
 * les faisant pointer vers les jetons réels.
 *
 * L'ALTERNATIVE ÉTAIT PIRE. Sans lui, il fallait réécrire d'un coup les
 * centaines de déclarations de ces dix pages — c'est-à-dire toucher au tunnel
 * d'achat, à la connexion et à la facturation dans le même commit que la
 * refonte de la vitrine. Une refonte qui casse la production le jour de son
 * adoption ne s'adopte jamais.
 *
 * ── CHAQUE LIGNE EST UNE DETTE, ET ELLE SE COMPTE ─────────────────────────
 *
 * Ce ne sont pas des synonymes qu'on garde : ce sont des emprunts qu'on
 * rembourse, écran par écran, quand plus rien ne les lit. `ALIAS-01`, dans
 * `scripts/ci-checks.mjs`, COMPTE ceux qui restent et refuse que le nombre
 * monte. Un chiffre qui ne baisse jamais est un chiffre qu'on cesse de
 * regarder ; celui-ci ne peut pas grossir en silence.
 *
 * ── LA SEULE CHOSE QUI COMPTE VRAIMENT ICI ────────────────────────────────
 *
 * Aucun alias ne porte de VALEUR. Ils pointent tous vers un jeton `--rz-*`.
 * Le jour où la charte change, elle change à un seul endroit — y compris pour
 * ces dix pages, qui héritent alors de la correction sans être touchées. C'est
 * précisément ce que quatorze blocs `:root` recopiés rendaient impossible.
 */
:root {
  /* Surfaces et texte */
  --bg:             var(--rz-bg);
  --surface:        var(--rz-surface);
  --surface-2:      var(--rz-surface-2);
  --ink:            var(--rz-ink);
  --text:           var(--rz-text);
  --text-1:         var(--rz-text);
  --text-2:         var(--rz-text-2);
  --text-3:         var(--rz-text-3);

  /* Lignes — `--line` et `--border` désignaient la même chose sous deux noms,
     dans deux surfaces différentes. C'est ce doublon qui faisait disparaître
     une bordure quand on copiait un composant d'un écran à l'autre. */
  --border:         var(--rz-border);
  --line:           var(--rz-border);
  --border-strong:  var(--rz-border-strong);

  /* Marque et dégradé signature */
  --brand:          var(--rz-brand);
  --brand-strong:   var(--rz-brand-strong);
  --brand-soft:     color-mix(in srgb, var(--rz-brand) 12%, transparent);
  --g1:             var(--rz-sig-a);
  --g2:             var(--rz-sig-b);

  /* États. `--bad` et `--danger` visaient déjà `--crit` : trois noms pour une
     couleur, sur trois écrans qui ne se relisent pas entre eux. */
  --good:           var(--rz-good);
  --good-soft:      var(--rz-good-soft);
  --warn:           var(--rz-warn);
  --warn-soft:      var(--rz-warn-soft);
  --crit:           var(--rz-crit);
  --bad:            var(--rz-crit);
  --danger:         var(--rz-crit);

  /* Focus, ombres, mesures */
  --ring:           var(--rz-ring);
  --shadow-sm:      var(--rz-shadow-sm);
  --shadow-md:      var(--rz-shadow-md);
  --shadow-lg:      var(--rz-shadow-lg);
  --shadow-glow:    var(--rz-shadow-brand);
  --wrap:           var(--rz-wrap);

  /* Polices */
  --display:        var(--rz-font-display);
  --sans:           var(--rz-font-sans);
  --mono:           var(--rz-font-mono);
}

/* ═════════════════════════════════════════════════════ 7. IMPRESSION ═══ */

@media print {
  .rz-nav, .rz-drawer, .rz-foot, .rz-aurore, .rz-skip { display: none !important; }
  body { background: #FFF; color: #000; font-size: 11pt; }
  .rz-sec { padding-block: 1rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}
