/* ==========================================================================
   NUMERI — SYSTEME DE DESIGN
   numeri-video.com · edite par Odratta · marche international (EN)

   Style : « Prisme » — la maquette de Joseph (Claude Design, 30/08/2026)
   portee en ultra-tech : papier blanc, halos de degrade, angles ronds,
   bandeaux de rendus qui defilent, et LA VIDEO COMME MATIERE DE FOND.

   TOUT est pilote par des variables --n-*. Changer la charte = changer les
   valeurs du bloc :root, jamais le reste du fichier.

   ⚠️ CSP SANS 'unsafe-inline' : aucun style en ligne nulle part dans les
   pages. Un style="" y est ignore SANS erreur — la page se decompose en
   silence et le defaut ne se voit qu'en production. Tout ce qui aurait ete
   ecrit en ligne est une classe, section 21 comprise.

   Sommaire
     01  Polices (Poppins + IBM Plex Mono, auto-hebergees)
     02  Jetons — theme CLAIR (defaut)
     03  Jetons — theme SOMBRE (secours)
     04  Reset
     05  Typographie
     06  Grille & conteneurs
     07  Bouton
     08  Champ de formulaire
     09  En-tete collant
     10  Heros & fond video
     11  Bandeaux de rendus qui defilent
     12  Etapes
     13  Formats
     14  Mur de rendus
     15  Panneau video documente
     16  Specifications
     17  Paliers
     18  Appel final
     19  Pied de page
     20  Composants de l'application (/app)
     21  Animations & prefers-reduced-motion
     22  Utilitaires (le remplacement des styles en ligne)
     26  La forge — le composeur pose dans le heros
   ========================================================================== */

/* == 01 · POLICES ==========================================================
   Poppins pour le texte — c'est le choix de Joseph, redit deux fois.
   IBM Plex Mono pour les etiquettes techniques, les identifiants et les
   chiffres — c'est la mono de sa maquette, et c'est elle qui donne le ton
   « instrument » sans que le reste devienne froid.

   14 fichiers woff2, 208 Ko au total, decoupes par plage Unicode : un
   visiteur francais ou anglais ne telecharge que « latin ».

   ⚠️ Jamais de Google Fonts en CDN. La maquette d'origine les appelait ;
   la CNIL y voit un transfert de donnees non consenti, et la CSP du vhost
   les bloquerait de toute facon. Zero requete tierce = aucun bandeau.
   ========================================================================== */

@font-face { font-family:"Poppins"; font-style:normal; font-weight:300; font-display:swap;
  src:url("../fonts/poppins-300-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/poppins-400-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/poppins-500-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:600; font-display:swap;
  src:url("../fonts/poppins-600-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:700; font-display:swap;
  src:url("../fonts/poppins-700-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

@font-face { font-family:"Poppins"; font-style:normal; font-weight:300; font-display:swap;
  src:url("../fonts/poppins-300-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/poppins-400-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/poppins-500-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:600; font-display:swap;
  src:url("../fonts/poppins-600-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:"Poppins"; font-style:normal; font-weight:700; font-display:swap;
  src:url("../fonts/poppins-700-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }

@font-face { font-family:"IBM Plex Mono"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/plexmono-400-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"IBM Plex Mono"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/plexmono-500-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:"IBM Plex Mono"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/plexmono-400-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:"IBM Plex Mono"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/plexmono-500-latinext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }

/* Police de secours calee sur les metriques de Poppins : pendant le swap le
   texte est deja a la bonne largeur, la bascule ne fait pas sauter la page. */
@font-face {
  font-family: "Poppins secours";
  src: local("Helvetica Neue"), local("Arial"), local("Segoe UI"), local("Roboto");
  size-adjust: 112%; ascent-override: 93.75%; descent-override: 31.25%; line-gap-override: 0%;
}

/* == 02 · JETONS — LE SOCLE, ET LA PALETTE CLAIRE =========================
   ⚠️ CE BLOC N'EST PLUS LE DEFAUT. Depuis le 30/08/2026 la charte est le
   NOIR (« version black de base », Joseph) : la section 03 recouvre toutes
   les couleurs d'ici, sans @media, par specificite. Ce bloc reste le socle
   — il porte tout ce qui n'a pas de couleur (rayons, ombres, durees,
   courbes, espacement, familles, echelle, grille, plans) — et il porte la
   palette CLAIRE, qui ne reparait que si le visiteur clique la bascule.
   Ne pas y toucher en croyant changer ce que les gens voient.

   Les valeurs viennent de la maquette. Deux corrections, mesurees :

   1. --n-faint etait #7A7A85 (4,24:1) → sous le minimum AA. Passe a #71717C.
   2. LA RAMPE. Celle de la maquette (#FF6E7F → #C58BF2 → #7A6CF0) ne tient
      PAS sous du texte : blanc sur #C58BF2 = 2,52:1, et le titre en degrade
      tombe a 2,52 lui aussi. Un degrade se juge sur son arret le plus pale,
      jamais sur sa moyenne.
      → --n-grad garde les teintes EXACTES de la maquette et ne sert qu'au
        DECOR : halos, rectangles de format, pastilles, filets, lueurs.
      → --n-grad-ink est la meme rampe descendue d'un cran, verifiee arret
        par arret (5,46 · 4,79 · 5,54). C'est elle qui porte le texte en
        degrade et les aplats a libelle blanc. Meme identite a l'oeil.
   ========================================================================= */

:root {
  color-scheme: light;

  /* --- Fonds ------------------------------------------------------------ */
  --n-bg:            #FFFFFF;
  --n-bg-soft:       #FBFAFF;   /* bande de section, degrade tres pale */
  --n-bg-deep:       #0B0B0F;   /* le puits : interieur d'un caisson video */
  --n-well:          #08080B;   /* le noir de salle */
  --n-bg-overlay:    rgba(255, 255, 255, 0.72); /* voile de l'en-tete */

  /* --- Surfaces --------------------------------------------------------- */
  --n-surface-1:     #FFFFFF;
  --n-surface-2:     #F7F6FC;
  --n-surface-3:     #F1EFF9;
  --n-surface-4:     #E6E3F2;

  /* --- Encre ------------------------------------------------------------ */
  --n-text:          #0B0B0F;   /* 19.64:1  (AAA) */
  --n-text-strong:   #000000;   /* 21.00:1  (AAA) */
  --n-text-muted:    #55555F;   /*  7.37:1  (AAA) */
  --n-text-faint:    #6B6B76;   /*  5.26:1  (AA)  */
  --n-text-dim:      #71717C;   /*  4.82:1  (AA)  — corrige de #7A7A85 */
  --n-text-disabled: #A3A3AE;   /* desactive seulement, exempte 1.4.3 */
  --n-text-on-accent:#FFFFFF;

  /* --- L'accent, en trois etats ---------------------------------------- */
  --n-accent:        #6152E0;   /*  5.54:1 — liens, focus, petit texte */
  --n-accent-hi:     #5140CF;   /*  7.04:1 — survol */
  --n-accent-lo:     #7A6CF0;   /*  4.01:1 — LE violet exact de la maquette,
                                   bordures et decor seulement, jamais texte */
  --n-accent-up:     #B9AEFF;   /* la seule version lisible sur le puits noir */
  --n-accent-soft:   rgba(97, 82, 224, 0.08);
  --n-accent-veil:   rgba(97, 82, 224, 0.04);

  /* --- Les deux rampes -------------------------------------------------- */
  --n-grad:      linear-gradient(115deg, #FF6E7F 0%, #C58BF2 52%, #7A6CF0 100%);
  --n-grad-ink:  linear-gradient(115deg, #C92646 0%, #9E4AD4 52%, #6152E0 100%);
  --n-grad-ink-hi: linear-gradient(115deg, #B81A3A 0%, #8A38C4 52%, #5140CF 100%);
  --n-grad-text: linear-gradient(105deg, #C92646 0%, #9E4AD4 48%, #6152E0 100%);

  /* --- Halos : le fond vivant de la maquette --------------------------- */
  --n-blob-a:    #FFC9CF;
  --n-blob-b:    #D9C8FF;

  /* --- Etats ------------------------------------------------------------ */
  --n-ok:            #0E7A46;   --n-ok-soft:     rgba(14, 122, 70, 0.10);
  --n-warn:          #8A5B00;   --n-warn-soft:   rgba(138, 91, 0, 0.10);
  --n-danger:        #C01F3F;   --n-danger-soft: rgba(192, 31, 63, 0.10);
  --n-info:          #175680;   --n-info-soft:   rgba(23, 86, 128, 0.10);

  /* --- Filets ------------------------------------------------------------
     Deux familles. Les DECORATIFS peuvent s'effacer sans coût ; le
     FONCTIONNEL (--n-line-strong) borde un controle et doit tenir 3:1 sur
     les quatre surfaces du systeme, pas seulement sur blanc. */
  --n-line:          rgba(11, 11, 15, 0.07);
  --n-line-2:        rgba(11, 11, 15, 0.12);
  --n-line-3:        rgba(11, 11, 15, 0.16);
  --n-line-strong:   #78787F;   /* 4.08 sur blanc · 3.24 sur surface-4 */
  --n-line-accent:   rgba(122, 108, 240, 0.42);
  --n-line-bevel:    rgba(255, 255, 255, 0.85);
  --n-line-grid:     rgba(11, 11, 15, 0.045);

  /* --- Focus : jamais discret ------------------------------------------- */
  --n-focus:         #6152E0;
  --n-focus-w:       2px;
  --n-focus-offset:  2px;

  /* --- Rayons : ceux de la maquette, ronds et assumes ------------------- */
  --n-r-xs:    6px;
  --n-r-sm:    9px;
  --n-r-md:   12px;
  --n-r-lg:   16px;
  --n-r-xl:   18px;
  --n-r-2xl:  22px;
  --n-r-3xl:  28px;
  --n-r-pill: 999px;

  /* --- Ombres : basses et colorees, jamais grises ---------------------- */
  --n-shadow-1: 0 1px 2px rgba(11, 11, 15, 0.04);
  --n-shadow-2: 0 6px 18px -12px rgba(97, 82, 224, 0.45);
  --n-shadow-3: 0 20px 50px -34px rgba(97, 82, 224, 0.55);
  --n-shadow-4: 0 34px 70px -50px rgba(97, 82, 224, 0.90);
  --n-bevel:    inset 0 1px 0 var(--n-line-bevel);
  --n-glow:     0 12px 30px -16px rgba(97, 82, 224, 0.85);

  /* --- Durees ------------------------------------------------------------ */
  --n-dur-1: 120ms; --n-dur-2: 180ms; --n-dur-3: 300ms;
  --n-dur-4: 480ms; --n-dur-5: 800ms; --n-dur-6: 1200ms;

  /* --- Courbes ---------------------------------------------------------- */
  --n-ease-out:   cubic-bezier(0.2, 0.7, 0.2, 1);
  --n-ease-in:    cubic-bezier(0.55, 0.06, 0.68, 0.19);
  --n-ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --n-ease-emph:  cubic-bezier(0.2, 0.7, 0.2, 1);

  /* --- Espacement -------------------------------------------------------- */
  --n-sp-0:0; --n-sp-1:2px; --n-sp-2:4px; --n-sp-3:6px; --n-sp-4:8px;
  --n-sp-5:12px; --n-sp-6:16px; --n-sp-7:20px; --n-sp-8:24px; --n-sp-9:32px;
  --n-sp-10:40px; --n-sp-11:48px; --n-sp-12:64px; --n-sp-13:80px;
  --n-sp-14:96px; --n-sp-15:128px; --n-sp-16:160px;
  /* Une section paye son rembourrage EN HAUT ET EN BAS : entre deux
     sections l'espace vaut donc le double. A 7,5rem cela faisait 240 px de
     blanc entre deux titres sur un grand ecran — la page ne respirait pas,
     elle se vidait. Descendu a 5,5rem, soit 176 px entre deux sections. */
  --n-sp-section: clamp(3.75rem, 2.6rem + 5.2vw, 5.5rem);
  --n-sp-gutter:  clamp(1.25rem, 0.75rem + 2.2vw, 2rem);
  --n-sp-stack:   clamp(2.5rem, 1.83rem + 2.96vw, 4.5rem);

  /* --- Familles ---------------------------------------------------------- */
  --n-font-sans: "Poppins", "Poppins secours", ui-sans-serif, system-ui,
                 -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --n-font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono",
                 Menlo, Consolas, "Liberation Mono", monospace;

  --n-fw-light:300; --n-fw-normal:400; --n-fw-medium:500;
  --n-fw-semi:600; --n-fw-bold:700;

  /* --- Echelle typographique (fluide 360 → 1440) ------------------------ */
  --n-fs-3xs: clamp(0.625rem,  0.615rem + 0.046vw, 0.6875rem);
  --n-fs-2xs: clamp(0.6875rem, 0.677rem + 0.046vw, 0.71875rem);
  --n-fs-xs:  clamp(0.75rem,   0.729rem + 0.093vw, 0.8125rem);
  --n-fs-sm:  clamp(0.8125rem, 0.792rem + 0.093vw, 0.875rem);
  --n-fs-md:  clamp(0.9375rem, 0.917rem + 0.093vw, 1rem);
  --n-fs-lg:  clamp(1rem,      0.969rem + 0.139vw, 1.0938rem);
  --n-fs-xl:  clamp(1.0625rem, 1.021rem + 0.185vw, 1.1875rem);
  --n-fs-2xl: clamp(1.25rem,   1.167rem + 0.37vw,  1.5625rem);
  --n-fs-3xl: clamp(1.5rem,    1.354rem + 0.65vw,  1.9375rem);
  --n-fs-4xl: clamp(1.875rem,  1.625rem + 1.11vw,  2.625rem);
  --n-fs-5xl: clamp(2.25rem,   1.833rem + 1.85vw,  3.5rem);
  --n-fs-6xl: clamp(2.5rem,    1.75rem + 3.33vw,   4.75rem);
  --n-fs-7xl: clamp(3.2rem,    1.6rem + 7.1vw,     8.6rem);

  --n-lh-tight:0.9; --n-lh-snug:1.04; --n-lh-normal:1.4;
  --n-lh-body:1.6; --n-lh-loose:1.7;
  --n-ls-display:-0.05em; --n-ls-title:-0.04em; --n-ls-h3:-0.03em;
  --n-ls-normal:0; --n-ls-wide:0.1em; --n-ls-caps:0.16em; --n-ls-caps-lg:0.18em;

  /* --- Grille ------------------------------------------------------------ */
  --n-container:      1320px;
  --n-container-wide: 1440px;
  --n-container-text: 68ch;
  --n-grid-gap:       clamp(1rem, 0.6rem + 1.8vw, 1.25rem);
  --n-header-h:       67px;

  /* --- Plans -------------------------------------------------------------- */
  --n-z-base:0; --n-z-raised:10; --n-z-sticky:20; --n-z-nav:50;
  --n-z-overlay:60; --n-z-modal:70; --n-z-toast:80;
}

/* == 03 · JETONS — LE NOIR, QUI EST LA CHARTE =============================
   « Version black de base » — Joseph, 30/08/2026. Le noir n'est plus une
   preference systeme honoree : c'est CE QUE TOUT LE MONDE VOIT, quel que
   soit le reglage de la machine. Le clair reste accessible d'un clic sur la
   bascule, et lui seul est conditionnel.

   COMMENT LA BASCULE EST FAITE, et pourquoi elle est faite comme ca :
   le bloc :root ci-dessus porte toujours les valeurs CLAIRES — c'est le
   socle, et il porte aussi tout ce qui n'a pas de couleur (rayons, durees,
   espacement, echelle). Le bloc ci-dessous les recouvre avec la palette
   sombre et il gagne PAR SA SPECIFICITE : `:root:not([data-theme="light"])`
   pese (0,2,0) contre (0,1,0) pour `:root`. Il n'y a donc AUCUNE @media, et
   c'est tout l'interet : un visiteur dont le systeme est en clair voit quand
   meme le noir. Le jour ou il clique la bascule, l'attribut data-theme vaut
   "light", le :not() cesse de mordre, et le socle clair reparait seul.

   Reecrire les 150 lignes du socle aurait fait la meme chose et casse deux
   fois plus de choses. La rampe remonte : sur du noir, ce sont les teintes
   CLAIRES qui deviennent lisibles.
   ========================================================================= */

:root:not([data-theme="light"]) {
    color-scheme: dark;
    --n-bg:#0B0B0F; --n-bg-soft:#101017; --n-bg-deep:#07070A; --n-well:#050508;
    --n-bg-overlay:rgba(11,11,15,0.72);
    --n-surface-1:#141420; --n-surface-2:#1A1A28; --n-surface-3:#222232; --n-surface-4:#2C2C40;
    --n-text:#F2F1F8; --n-text-strong:#FFFFFF; --n-text-muted:#B3B2C2;
    --n-text-faint:#9A99AA; --n-text-dim:#8E8D9E; --n-text-disabled:#5A5A68;
    /* ⚠️ RETOURNE LE 30/08/2026, quand le noir est devenu la charte.
       Il valait #FFFFFF, herite du clair sans etre relu. Or la rampe du
       sombre est CLAIRE (#FF8A99 / #D3A5F7 / #9E92FF) : du blanc dessus
       tombe a 2,00:1 sur l'arret du milieu — un bouton primaire illisible,
       et personne ne l'avait vu parce que le sombre n'etait qu'une option.
       L'encre sombre y tient 8,47 · 9,51 · 7,26 sur les trois arrets. */
    --n-text-on-accent:#0B0B0F;
    --n-accent:#B9AEFF; --n-accent-hi:#D2CBFF; --n-accent-lo:#7A6CF0; --n-accent-up:#B9AEFF;
    --n-accent-soft:rgba(185,174,255,0.14); --n-accent-veil:rgba(185,174,255,0.06);
    --n-grad:linear-gradient(115deg,#FF8A99 0%,#D3A5F7 52%,#9E92FF 100%);
    --n-grad-ink:linear-gradient(115deg,#FF8A99 0%,#D3A5F7 52%,#9E92FF 100%);
    --n-grad-ink-hi:linear-gradient(115deg,#FFA3AE 0%,#DFBAFA 52%,#B3A9FF 100%);
    /* ⚠️ REMONTEE LE 30/08/2026, quand le noir est devenu la charte.
       Elle valait #FF8A99/#D3A5F7/#9E92FF. Le titre du heros se pose sur un
       clip : on le juge sur son PIRE cadre, un plan entierement blanc. Sous
       le voile plat a 0,68 ce cadre compose un #59595C, ou l'arret le plus
       sombre #9E92FF ne tenait que 2,66:1 — sous le 3:1 du grand texte.
       Remontee aux arrets de grad-ink-hi : le pire tient 3,34:1, et sur un
       clip sombre (la majorite) le rapport est bien plus haut. */
    --n-grad-text:linear-gradient(105deg,#FFA3AE 0%,#DFBAFA 48%,#B3A9FF 100%);
    --n-blob-a:#5B2740; --n-blob-b:#2E2A62;
    --n-ok:#4ED396; --n-warn:#F0B95C; --n-danger:#FF8480; --n-info:#8FBEE6;
    --n-line:rgba(255,255,255,0.09); --n-line-2:rgba(255,255,255,0.14);
    --n-line-3:rgba(255,255,255,0.20); --n-line-strong:#8E8DA0;
    --n-line-accent:rgba(185,174,255,0.45); --n-line-bevel:rgba(255,255,255,0.05);
    --n-line-grid:rgba(255,255,255,0.045);
    --n-focus:#B9AEFF;
    --n-shadow-1:0 1px 2px rgba(0,0,0,0.5);
    --n-shadow-2:0 6px 18px -12px rgba(0,0,0,0.7);
    --n-shadow-3:0 20px 50px -34px rgba(0,0,0,0.8);
    --n-shadow-4:0 34px 70px -50px rgba(0,0,0,0.9);
    --n-glow:0 12px 30px -16px rgba(185,174,255,0.4);

    /* Les quatre lavis d'etat manquaient au sombre : ils restaient sur les
       valeurs claires, ou un rgba(14,122,70,.10) sur #0B0B0F ne se voit
       simplement pas. Remontes sur les teintes sombres correspondantes. */
    --n-ok-soft:rgba(78,211,150,0.14); --n-warn-soft:rgba(240,185,92,0.14);
    --n-danger-soft:rgba(255,132,128,0.14); --n-info-soft:rgba(143,190,230,0.14);
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --n-bg:#0B0B0F; --n-bg-soft:#101017; --n-bg-deep:#07070A; --n-well:#050508;
  --n-bg-overlay:rgba(11,11,15,0.72);
  --n-surface-1:#141420; --n-surface-2:#1A1A28; --n-surface-3:#222232; --n-surface-4:#2C2C40;
  --n-text:#F2F1F8; --n-text-strong:#FFFFFF; --n-text-muted:#B3B2C2;
  --n-text-faint:#9A99AA; --n-text-dim:#8E8D9E; --n-text-disabled:#5A5A68;
  --n-text-on-accent:#0B0B0F;   /* voir la note du bloc ci-dessus */
  --n-accent:#B9AEFF; --n-accent-hi:#D2CBFF; --n-accent-lo:#7A6CF0; --n-accent-up:#B9AEFF;
  --n-accent-soft:rgba(185,174,255,0.14); --n-accent-veil:rgba(185,174,255,0.06);
  --n-grad:linear-gradient(115deg,#FF8A99 0%,#D3A5F7 52%,#9E92FF 100%);
  --n-grad-ink:linear-gradient(115deg,#FF8A99 0%,#D3A5F7 52%,#9E92FF 100%);
  --n-grad-ink-hi:linear-gradient(115deg,#FFA3AE 0%,#DFBAFA 52%,#B3A9FF 100%);
  /* ⚠️ REMONTEE LE 30/08/2026, quand le noir est devenu la charte.
       Elle valait #FF8A99/#D3A5F7/#9E92FF. Le titre du heros se pose sur un
       clip : on le juge sur son PIRE cadre, un plan entierement blanc. Sous
       le voile plat a 0,68 ce cadre compose un #59595C, ou l'arret le plus
       sombre #9E92FF ne tenait que 2,66:1 — sous le 3:1 du grand texte.
       Remontee aux arrets de grad-ink-hi : le pire tient 3,34:1, et sur un
       clip sombre (la majorite) le rapport est bien plus haut. */
    --n-grad-text:linear-gradient(105deg,#FFA3AE 0%,#DFBAFA 48%,#B3A9FF 100%);
  --n-blob-a:#5B2740; --n-blob-b:#2E2A62;
  --n-ok:#4ED396; --n-warn:#F0B95C; --n-danger:#FF8480; --n-info:#8FBEE6;
  --n-line:rgba(255,255,255,0.09); --n-line-2:rgba(255,255,255,0.14);
  --n-line-3:rgba(255,255,255,0.20); --n-line-strong:#8E8DA0;
  --n-line-accent:rgba(185,174,255,0.45); --n-line-bevel:rgba(255,255,255,0.05);
  --n-line-grid:rgba(255,255,255,0.045);
  --n-focus:#B9AEFF;
  --n-shadow-1:0 1px 2px rgba(0,0,0,0.5);
  --n-shadow-2:0 6px 18px -12px rgba(0,0,0,0.7);
  --n-shadow-3:0 20px 50px -34px rgba(0,0,0,0.8);
  --n-shadow-4:0 34px 70px -50px rgba(0,0,0,0.9);
  --n-glow:0 12px 30px -16px rgba(185,174,255,0.4);
  --n-ok-soft:rgba(78,211,150,0.14); --n-warn-soft:rgba(240,185,92,0.14);
  --n-danger-soft:rgba(255,132,128,0.14); --n-info-soft:rgba(143,190,230,0.14);
}
/* Le clair : plus un defaut, une option. Le socle :root le porte deja en
   entier — cette regle ne fait que desarmer le :not() ci-dessus. */
:root[data-theme="light"] { color-scheme: light; }

/* == 04 · RESET =========================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--n-header-h) + 24px);
}
html, body { max-inline-size: 100%; overflow-x: clip; }

body {
  margin: 0;
  background: var(--n-bg);
  color: var(--n-text);
  font-family: var(--n-font-sans);
  font-size: var(--n-fs-md);
  line-height: var(--n-lh-body);
  font-weight: var(--n-fw-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }
img, video, svg, canvas { display: block; max-inline-size: 100%; }
img, video { block-size: auto; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }
table { border-collapse: collapse; inline-size: 100%; }
::selection { background: #F2D9FF; color: #0B0B0F; }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--n-focus-w) solid var(--n-focus);
  outline-offset: var(--n-focus-offset);
  border-radius: var(--n-r-xs);
}

.n-skip {
  position: absolute; inset-block-start: -100%; inset-inline-start: var(--n-sp-6);
  z-index: var(--n-z-toast);
  padding: var(--n-sp-5) var(--n-sp-8);
  background: var(--n-text); color: var(--n-bg);
  border-radius: var(--n-r-pill); font-size: var(--n-fs-sm); font-weight: var(--n-fw-medium);
}
.n-skip:focus { inset-block-start: var(--n-sp-6); }

.n-sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* == 05 · TYPOGRAPHIE =====================================================
   Poppins est large : plus le corps grandit, plus l'interlettrage se
   resserre. Le display descend a -0,05em, comme dans la maquette.
   ========================================================================= */

.n-display, .n-h1, .n-h2, .n-h3, .n-h4 {
  font-family: var(--n-font-sans);
  color: var(--n-text);
  font-weight: var(--n-fw-medium);
  text-wrap: balance;
  font-synthesis-weight: none;
}
.n-display { font-size: var(--n-fs-7xl); line-height: var(--n-lh-tight);
             letter-spacing: var(--n-ls-display); }
.n-h1      { font-size: var(--n-fs-6xl); line-height: 0.98;
             letter-spacing: var(--n-ls-display); }
.n-h2      { font-size: var(--n-fs-5xl); line-height: var(--n-lh-snug);
             letter-spacing: var(--n-ls-title); }
.n-h3      { font-size: var(--n-fs-2xl); line-height: 1.12;
             letter-spacing: var(--n-ls-h3); }
.n-h4      { font-size: var(--n-fs-lg);  line-height: var(--n-lh-normal);
             letter-spacing: var(--n-ls-normal); font-weight: var(--n-fw-semi); }

.n-lead { font-size: var(--n-fs-xl); line-height: 1.55; color: var(--n-text-muted);
          max-inline-size: 54ch; text-wrap: pretty; }
.n-body { font-size: var(--n-fs-md); line-height: var(--n-lh-body);
          color: var(--n-text-muted); max-inline-size: var(--n-container-text);
          text-wrap: pretty; }
.n-small{ font-size: var(--n-fs-sm); line-height: 1.6; color: var(--n-text-muted); }
.n-tiny { font-size: var(--n-fs-xs); line-height: 1.65; color: var(--n-text-dim); }

/* Deux paragraphes qui se suivent respirent. La marge est posee sur la
   SUITE : un premier paragraphe ne doit pas pousser le titre qui le precede. */
.n-body + .n-body, .n-body + .n-small, .n-small + .n-body,
.n-lead + .n-body, .n-tiny + .n-tiny { margin-block-start: var(--n-sp-6); }

/* La mono : toutes les etiquettes techniques du systeme passent par la. */
.n-meta, .n-eyebrow, .n-tag, .n-mono {
  font-family: var(--n-font-mono);
  font-variant-numeric: tabular-nums;
}
.n-eyebrow {
  display: block;
  font-size: var(--n-fs-2xs); font-weight: var(--n-fw-normal);
  letter-spacing: var(--n-ls-caps-lg); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-meta { font-size: var(--n-fs-2xs); letter-spacing: var(--n-ls-caps);
          text-transform: uppercase; color: var(--n-text-faint); }
.n-num  { font-family: var(--n-font-mono); font-variant-numeric: tabular-nums; }

/* Le texte en degrade : LA signature de la maquette.
   Il utilise --n-grad-text, la rampe assombrie — la rampe d'origine tombe a
   2,52:1 et un titre illisible n'est pas un titre. Repli en couleur pleine
   pour les navigateurs sans background-clip. */
.n-grad-text {
  color: var(--n-accent);
  background: var(--n-grad-text);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  /* Safari perd le degrade en impression : on lui rend une encre. */
}
@media print { .n-grad-text { -webkit-text-fill-color: currentColor; color: var(--n-text); } }
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .n-grad-text { -webkit-text-fill-color: currentColor; color: var(--n-accent); }
}

.n-link {
  color: var(--n-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: var(--n-line-accent);
  transition: color var(--n-dur-1) var(--n-ease-out),
              text-decoration-color var(--n-dur-1) var(--n-ease-out);
}
.n-link:hover { color: var(--n-accent-hi); text-decoration-color: currentColor; }

/* == 06 · GRILLE & CONTENEURS ============================================= */

.n-container {
  inline-size: 100%;
  max-inline-size: calc(var(--n-container) + 2 * var(--n-sp-gutter));
  margin-inline: auto;
  padding-inline: var(--n-sp-gutter);
}
.n-container--wide { max-inline-size: calc(var(--n-container-wide) + 2 * var(--n-sp-gutter)); }
.n-container--text { max-inline-size: calc(var(--n-container-text) + 2 * var(--n-sp-gutter)); }
.n-container--full { max-inline-size: none; }

.n-section { padding-block: var(--n-sp-section); position: relative; }
.n-section--line { border-block-start: 1px solid var(--n-line); }
.n-section--soft { background: linear-gradient(180deg, var(--n-bg-soft) 0%, var(--n-bg) 100%); }
.n-section--soft-mid {
  background: linear-gradient(180deg, var(--n-bg) 0%, var(--n-bg-soft) 60%, var(--n-bg) 100%);
}

.n-stack > * + * { margin-block-start: var(--n-sp-6); }
.n-stack-lg > * + * { margin-block-start: var(--n-sp-stack); }
.n-cluster { display: flex; flex-wrap: wrap; gap: var(--n-sp-5); align-items: center; }
.n-rule { border-block-start: 1px solid var(--n-line); }

/* L'en-tete de section de la maquette : titre a gauche, phrase a droite,
   alignes sur leur ligne de base, qui passent l'un sous l'autre au besoin. */
.n-shead {
  display: flex; align-items: end; justify-content: space-between;
  gap: var(--n-sp-10); flex-wrap: wrap;
}
.n-shead__side { max-inline-size: 38ch; margin: 0; }

/* Les deux colonnes a colonne collante (« comment ca marche », « specs ») */
.n-split { display: grid; gap: var(--n-sp-11); }
@media (min-width: 960px) {
  .n-split { grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
             gap: clamp(3rem, 5vw, 5rem); }
  .n-split__sticky { position: sticky; inset-block-start: calc(var(--n-header-h) + 32px);
                     align-self: start; }
}
.n-split--specs { }
@media (min-width: 960px) {
  .n-split--specs { grid-template-columns: minmax(260px, .8fr) minmax(0, 1.2fr); }
}

/* Deux colonnes egales, centrees (« pourquoi la montre ») */
.n-duo { display: grid; gap: var(--n-sp-11); align-items: center; }
@media (min-width: 960px) { .n-duo { grid-template-columns: 1fr 1fr;
                                     gap: clamp(3rem, 4.5vw, 4.4rem); } }

/* == 07 · BOUTON ==========================================================
   Pastille, comme la maquette. Cinq etats, cible tactile 44 px.
   La variante primaire porte --n-grad-ink : blanc lisible d'un bout a
   l'autre de la rampe (4,79 au pire arret).
   ========================================================================= */

.n-btn {
  --n-btn-h: 44px;
  --n-btn-px: var(--n-sp-8);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--n-sp-4);
  min-block-size: var(--n-btn-h);
  padding-inline: var(--n-btn-px);
  border: 1px solid transparent;
  border-radius: var(--n-r-pill);
  font-size: var(--n-fs-sm);
  font-weight: var(--n-fw-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer; user-select: none; text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--n-dur-1) var(--n-ease-out),
              border-color var(--n-dur-1) var(--n-ease-out),
              color var(--n-dur-1) var(--n-ease-out),
              box-shadow var(--n-dur-2) var(--n-ease-out),
              transform var(--n-dur-1) var(--n-ease-out);
}
.n-btn > svg { inline-size: 16px; block-size: 16px; flex: none; }
.n-btn--sm { --n-btn-h: 38px; --n-btn-px: var(--n-sp-7); font-size: var(--n-fs-xs); }
.n-btn--lg { --n-btn-h: 52px; --n-btn-px: var(--n-sp-10); font-size: var(--n-fs-md); }
/* Le GROS bouton, demande par Joseph le 30/08/2026 : « juste un bouton gros
   creer ma video ». 60 px de haut, 48 px de respiration de chaque cote — au
   dela, un bouton cesse d'etre un bouton et devient une banniere. */
.n-btn--xl { --n-btn-h: 60px; --n-btn-px: var(--n-sp-11); font-size: var(--n-fs-lg);
             font-weight: var(--n-fw-medium); letter-spacing: -0.01em; }
.n-btn--block { display: flex; inline-size: 100%; }

.n-btn--primary {
  background-image: var(--n-grad-ink);
  color: var(--n-text-on-accent);
  box-shadow: var(--n-glow);
}
.n-btn--primary:hover  { background-image: var(--n-grad-ink-hi); }
.n-btn--primary:active { transform: translateY(1px); box-shadow: var(--n-shadow-2); }

.n-btn--ghost {
  background: transparent; color: var(--n-text);
  border-color: var(--n-line-3);
}
.n-btn--ghost:hover  { border-color: var(--n-accent-lo); color: var(--n-accent-hi);
                       background: var(--n-accent-veil); }
.n-btn--ghost:active { transform: translateY(1px); }

.n-btn--quiet {
  background: transparent; color: var(--n-text-muted);
  --n-btn-px: var(--n-sp-6);
}
.n-btn--quiet:hover  { color: var(--n-text); background: var(--n-surface-2); }
.n-btn--quiet:active { transform: translateY(1px); }

.n-btn--danger { background: transparent; color: var(--n-danger); border-color: var(--n-danger); }
.n-btn--danger:hover { background: var(--n-danger-soft); }

.n-btn:disabled, .n-btn[aria-disabled="true"] {
  background: var(--n-surface-3); background-image: none;
  color: var(--n-text-disabled); border-color: var(--n-line-2);
  cursor: not-allowed; transform: none; box-shadow: none;
}
.n-btn[data-loading="true"] { color: transparent; pointer-events: none; }
.n-btn[data-loading="true"]::after {
  content: ""; position: absolute;
  inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 16px; block-size: 16px; margin: -8px 0 0 -8px;
  border: 1.5px solid currentColor; border-block-start-color: transparent;
  border-radius: 50%; color: var(--n-text-on-accent);
  animation: n-spin 700ms linear infinite;
}
.n-btn--ghost[data-loading="true"]::after,
.n-btn--quiet[data-loading="true"]::after { color: var(--n-text); }
.n-btn--icon { --n-btn-px: 0; inline-size: var(--n-btn-h); }

/* == 08 · CHAMP =========================================================== */

.n-field { display: flex; flex-direction: column; gap: var(--n-sp-4); }
.n-field__label { font-size: var(--n-fs-xs); font-weight: var(--n-fw-medium);
                  color: var(--n-text-muted); }
.n-field__label .n-req { color: var(--n-accent); margin-inline-start: 2px; }

.n-input, .n-textarea, .n-select {
  inline-size: 100%; min-block-size: 44px;
  padding: var(--n-sp-5) var(--n-sp-7);
  background: var(--n-surface-1); color: var(--n-text);
  border: 1px solid var(--n-line-3);
  border-radius: var(--n-r-md);
  font-size: var(--n-fs-sm); line-height: 1.4;
  transition: border-color var(--n-dur-1) var(--n-ease-out),
              box-shadow var(--n-dur-2) var(--n-ease-out);
}
.n-textarea { min-block-size: 120px; resize: vertical; }
.n-select {
  appearance: none; padding-inline-end: var(--n-sp-11);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%236B6B76' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right var(--n-sp-6) center;
}
.n-input::placeholder, .n-textarea::placeholder { color: var(--n-text-dim); }
.n-input:hover, .n-textarea:hover, .n-select:hover { border-color: var(--n-line-strong); }
.n-input:focus-visible, .n-textarea:focus-visible, .n-select:focus-visible {
  outline: none; border-color: var(--n-accent);
  box-shadow: 0 0 0 3px var(--n-accent-soft);
}
.n-input:disabled, .n-textarea:disabled, .n-select:disabled {
  background: var(--n-surface-2); color: var(--n-text-disabled);
  border-color: var(--n-line-2); cursor: not-allowed;
}
.n-field__hint  { font-size: var(--n-fs-2xs); color: var(--n-text-dim); }
.n-field__error { font-size: var(--n-fs-2xs); color: var(--n-danger);
                  display: flex; align-items: center; gap: var(--n-sp-3); }
/* ⚠️ display:flex ECRASE l'attribut hidden : sans cette ligne, un message
   d'erreur vide et masque affiche quand meme sa pastille rouge sous le
   champ — vu sur la forge le 30/08/2026. Le meme piege est deja paye trois
   fois dans ce fichier (.n-tile, .n-act, .n-forge__shot). */
.n-field__error[hidden] { display: none !important; }
.n-field__error::before {
  content: ""; inline-size: 12px; block-size: 12px; flex: none;
  border: 1px solid currentColor; border-radius: 50%;
  /* la couleur n'est jamais le seul indicateur : pastille + texte */
}
.n-field[data-invalid="true"] .n-input,
.n-field[data-invalid="true"] .n-textarea,
.n-field[data-invalid="true"] .n-select { border-color: var(--n-danger); }

/* == 09 · EN-TETE COLLANT =================================================
   Fixe, voile translucide, filet en bas. Comme la maquette.
   ========================================================================= */

.n-nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: var(--n-z-nav);
  background: var(--n-bg-overlay);
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border-block-end: 1px solid var(--n-line);
}
.n-nav__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-8);
  min-block-size: var(--n-header-h);
  padding-block: var(--n-sp-5);
}
.n-nav__brand { display: inline-flex; align-items: center; gap: 11px; flex: none; }
.n-nav__brand img, .n-nav__brand .n-brandmark {
  inline-size: 30px; block-size: 30px; border-radius: var(--n-r-sm);
  display: block; box-shadow: 0 1px 0 rgba(11,11,15,.06); flex: none;
}
.n-nav__brand span {
  font-size: var(--n-fs-sm); font-weight: var(--n-fw-semi);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text);
}
.n-nav__links { display: none; align-items: center; gap: var(--n-sp-9);
                font-size: var(--n-fs-xs); }
@media (min-width: 900px) { .n-nav__links { display: flex; } }
.n-nav__link {
  position: relative; color: var(--n-text-muted); padding-block: var(--n-sp-4);
  transition: color var(--n-dur-1) var(--n-ease-out);
}
.n-nav__link:hover, .n-nav__link[aria-current="page"] { color: var(--n-accent-hi); }
.n-nav__link::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: 2px;
  block-size: 1.5px; border-radius: 2px; background-image: var(--n-grad);
  transform: scaleX(0); transform-origin: left center;
  transition: transform var(--n-dur-3) var(--n-ease-emph);
}
.n-nav__link:hover::after, .n-nav__link[aria-current="page"]::after { transform: scaleX(1); }
.n-nav__side { display: flex; align-items: center; gap: var(--n-sp-5); }
.n-nav__login { display: none; font-size: var(--n-fs-xs); color: var(--n-text-muted);
                padding: var(--n-sp-4) var(--n-sp-2); }
@media (min-width: 640px) { .n-nav__login { display: inline-flex; } }
.n-nav__login:hover { color: var(--n-accent-hi); }
.n-nav__toggle { display: grid; place-items: center; inline-size: 44px; block-size: 44px;
                 color: var(--n-text); border-radius: var(--n-r-sm); }
@media (min-width: 900px) { .n-nav__toggle { display: none; } }

.n-navpanel {
  position: fixed; inset: 0; z-index: var(--n-z-overlay);
  display: flex; flex-direction: column; gap: var(--n-sp-6);
  padding: var(--n-sp-13) var(--n-sp-gutter) var(--n-sp-9);
  background: var(--n-bg);
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity var(--n-dur-3) var(--n-ease-out),
              transform var(--n-dur-3) var(--n-ease-out),
              visibility 0s linear var(--n-dur-3);
}
.n-navpanel[data-open="true"] {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity var(--n-dur-3) var(--n-ease-out),
              transform var(--n-dur-3) var(--n-ease-emph), visibility 0s;
}
.n-navpanel__link {
  display: flex; align-items: center; justify-content: space-between;
  min-block-size: 56px; font-size: var(--n-fs-2xl); font-weight: var(--n-fw-medium);
  letter-spacing: var(--n-ls-h3); color: var(--n-text);
  border-block-end: 1px solid var(--n-line);
}
.n-navpanel__close {
  position: absolute; inset-block-start: var(--n-sp-5); inset-inline-end: var(--n-sp-gutter);
  inline-size: 44px; block-size: 44px; display: grid; place-items: center; color: var(--n-text);
}
.n-themetoggle {
  display: grid; place-items: center; inline-size: 38px; block-size: 38px;
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-pill);
  color: var(--n-text-muted); background: transparent;
}
.n-themetoggle:hover { color: var(--n-accent-hi); border-color: var(--n-accent-lo); }
.n-themetoggle svg { inline-size: 16px; block-size: 16px; }

/* == 10 · HEROS & FOND VIDEO ==============================================
   La demande de Joseph : « toutes les videos en fond ». Le heros porte donc
   un clip plein cadre, en boucle et muet, sous TROIS couches :
     1. le clip lui-meme, legerement desature ;
     2. un voile blanc — c'est lui qui rend le texte lisible. Sans voile, du
        texte encre sur une video claire tombe sous 2:1 par endroits, et le
        contraste d'un texte sur image mouvante se juge sur son pire cadre,
        jamais sur son affiche ;
     3. les halos de degrade de la maquette, qui redonnent la couleur.
   Le clip ne peint jamais le premier rendu : c'est l'affiche qui le fait,
   et la video ne se charge qu'a l'entree dans le champ.
   ========================================================================= */

.n-hero {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  min-block-size: 100svh;
  padding: calc(var(--n-header-h) + var(--n-sp-14)) var(--n-sp-gutter) var(--n-sp-13);
  isolation: isolate;
  overflow: clip;
}
.n-hero__bg { position: absolute; inset: 0; z-index: -3; overflow: hidden; }

/* LE CLIP DE FOND. Un seul plan, plein cadre, en object-fit: cover. La
   mosaique tenait cette place tant qu'il n'y avait que des rendus de 5 s a
   montrer : douze vignettes remplissaient n'importe quel format d'ecran la
   ou un clip unique se serait recadre en detail agrandi. Le montage recu le
   30/08 est fait pour ca — il enchaine lui-meme ses plans, donc le cadre
   change tout seul et le recadrage ne se lit plus comme une erreur.
   L'affiche est en dessous et ne bouge jamais : c'est elle qui peint le
   premier rendu, et c'est elle qui reste si la lecture automatique est
   refusee (mouvement reduit, mode econome, refus du navigateur). */
.n-herovid { position: absolute; inset: 0; }
.n-herovid > img,
.n-herovid > video {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%; object-fit: cover;
  filter: saturate(1.06);
}
.n-herovid > video { opacity: 0;
                     transition: opacity var(--n-dur-5) var(--n-ease-out); }
.n-herovid[data-playing="true"] > video { opacity: 1; }

/* LA MOSAIQUE. Elle a tenu le fond du heros jusqu'au 30/08 ; elle est
   maintenant le fond de l'appel final. Le principe ne change pas : une
   grille de clips garde chaque plan a sa proportion et remplit n'importe
   quel format d'ecran, et elle derive tres lentement pour rester vivante
   sans attirer l'oeil. Ce qui change, c'est la place : plus large que haute,
   donc plus de colonnes qu'avant, sinon les cellules s'ecrasent en bandes. */
.n-mosaic {
  position: absolute; inset: -10% -6%;
  display: grid; gap: 0;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 1fr;
  transform: scale(1.06);
  animation: n-drift 90s linear infinite alternate;
  will-change: transform;
}
@media (min-width: 700px)  { .n-mosaic { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1100px) { .n-mosaic { grid-template-columns: repeat(6, 1fr); } }
/* Pas de gouttiere, pas de coins ronds : avec les deux, douze clips se
   lisaient comme une planche-contact posee derriere le titre — un catalogue,
   pas un fond. Sans eux, c'est UNE image en mouvement, et le titre reprend
   la premiere place. Les jointures sont ensuite mangees par le voile. */
.n-mos {
  position: relative; overflow: hidden;
  background: var(--n-surface-3);
}
.n-mos > img, .n-mos > video {
  inline-size: 100%; block-size: 100%; object-fit: cover;
  filter: saturate(1.06);
}
.n-mos > video { position: absolute; inset: 0; opacity: 0;
                 transition: opacity var(--n-dur-5) var(--n-ease-out); }
.n-mos[data-playing="true"] > video { opacity: 1; }
/* les cellules qui debordent en bas ne servent qu'a remplir : on les cache
   sur les petits ecrans plutot que de faire decoder douze clips pour rien */
@media (max-width: 699.98px) { .n-mos:nth-child(n+9) { display: none; } }
/* LE VOILE, et le calcul qui le fixe.
   Un texte pose sur une image qui bouge se juge sur son PIRE cadre, jamais
   sur son affiche. Le pire cadre possible est un plan noir. Un voile blanc
   a 0,55 sur du noir compose un #8C8C8C : l'encre #0B0B0F y tient 5,84:1.
   C'est donc le reglage le plus GENEREUX qui reste demontrable — la video
   se voit a 45 %, et la lisibilite est garantie quel que soit le clip.
   Conséquence assumee : dans le heros TOUT le texte est en encre pleine,
   la hierarchie se fait a l'echelle et au poids, jamais au gris. */
.n-hero__veil {
  position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background:
    /* LE HALO CENTRAL, elargi le 30/08 pour couvrir TOUTE la colonne de
       texte — pastille comprise, invite de defilement comprise. C'est lui
       qui porte la lisibilite ; le voile plat, en dessous, ne fait plus que
       calmer les bords. */
    radial-gradient(66% 58% at 50% 46%, rgba(255,255,255,.74) 0%,
                                        rgba(255,255,255,.42) 62%, transparent 100%),
    /* LE VOILE PLAT. Il etait a 0,55 partout : la mosaique en sortait
       laiteuse et morte, et un fond video delave n'a plus de raison d'etre.
       Descendu a 0,42.
       LE CALCUL TIENT TOUJOURS, et c'est la seule chose qui compte : sous le
       texte les deux couches se composent a 1-(1-,74)(1-,42) = 0,85 au
       centre et 0,66 au pire endroit ou du texte se pose. Sur le pire cadre
       possible — un plan entierement noir — 0,66 donne un #A6A6A6 : l'encre
       #0B0B0F y tient 7,7:1, loin au-dessus du minimum AA. On a donc gagne
       treize points de video visible sans rien lacher. */
    linear-gradient(180deg, rgba(255,255,255,.42) 0%, rgba(255,255,255,.42) 58%,
                            rgba(255,255,255,.80) 84%, var(--n-bg) 100%),
    /* une vignette, pour que le regard tombe au centre et pas dans un coin */
    radial-gradient(120% 96% at 50% 44%, transparent 52%, rgba(11,11,15,.10) 100%);
}
.n-hero .n-lead,
.n-hero__hint,
.n-hero__pill { color: var(--n-text); }
.n-hero .n-lead { font-weight: var(--n-fw-normal); }
:root[data-theme="dark"] .n-hero__veil,
.n-hero__veil { }
/* LE VOILE NOIR — celui que tout le monde voit depuis le 30/08/2026.

   ⚠️ IL A ETE RECALCULE, et le chiffre a bouge. Tant que le noir n'etait
   qu'une preference minoritaire, le voile plat a 0,46 passait sans qu'on y
   regarde. Devenu la charte, il ne passe plus : sur le PIRE cadre possible
   — un plan entierement blanc — 0,46 compose un #8F8F8F ou l'encre claire
   #F2F1F8 ne tient que 2,88:1. Sous le minimum, et invisible tant qu'aucun
   clip blanc ne passe. C'est exactement le piege du voile clair, retourne.

   0,68 compose un #59595C. Mesures a cet endroit, sur un cadre BLANC :
     --n-text #F2F1F8 ............. 6,22:1  ✓ (corps de texte, AA)
     titre en degrade, pire arret .. 3,34:1  ✓ (grand texte, AA)
   La garantie est portee par le voile PLAT, jamais par le halo : un halo se
   deplace avec la taille de l'ecran, un aplat non. Sur un ecran large le
   titre commence AVANT le bord gauche du halo — c'est pour ca que le chiffre
   qui compte est celui du voile seul. Le halo n'ajoute que du confort : au
   centre les deux couches composent 0,90, soit 14,5:1. */
:root:not([data-theme="light"]) .n-hero__veil {
  background:
    radial-gradient(66% 58% at 50% 46%, rgba(11,11,15,.72) 0%,
                                        rgba(11,11,15,.42) 62%, transparent 100%),
    linear-gradient(180deg, rgba(11,11,15,.68) 0%, rgba(11,11,15,.68) 58%,
                            rgba(11,11,15,.90) 84%, var(--n-bg) 100%);
}
:root:not([data-theme="light"]) .n-hero .n-lead,
:root:not([data-theme="light"]) .n-hero__hint { color: var(--n-text); }
:root:not([data-theme="light"]) .n-hero__pill { background: rgba(20,20,32,.72); }
:root[data-theme="dark"] .n-hero__veil {
  background:
    radial-gradient(66% 58% at 50% 46%, rgba(11,11,15,.72) 0%,
                                        rgba(11,11,15,.42) 62%, transparent 100%),
    linear-gradient(180deg, rgba(11,11,15,.68) 0%, rgba(11,11,15,.68) 58%,
                            rgba(11,11,15,.90) 84%, var(--n-bg) 100%);
}
:root[data-theme="dark"] .n-hero .n-lead,
:root[data-theme="dark"] .n-hero__hint { color: var(--n-text); }

/* Les halos de la maquette : deux degrades radiaux flous qui respirent. */
.n-blob {
  position: absolute; z-index: -1; pointer-events: none;
  border-radius: 50%; filter: blur(90px); opacity: .5;
  background:
    radial-gradient(45% 55% at 35% 45%, var(--n-blob-a) 0%, transparent 70%),
    radial-gradient(45% 55% at 68% 55%, var(--n-blob-b) 0%, transparent 70%);
  animation: n-float 18s var(--n-ease-inout) infinite;
}
.n-blob--top { inset-block-start: -260px; inset-inline-start: 50%;
               inline-size: min(1100px, 130vw); block-size: 700px;
               margin-inline-start: min(-550px, -65vw); }
.n-blob--bottom { inset-block-end: -340px; inset-inline-start: 50%;
                  inline-size: min(1200px, 140vw); block-size: 700px;
                  margin-inline-start: min(-600px, -70vw); filter: blur(100px); opacity: .55; }

/* La trame technique du heros : une grille de 32 px, a peine la. C'est elle
   qui fait basculer la maquette du cote « instrument ». */
.n-hero__grid {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right,  var(--n-line-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--n-line-grid) 1px, transparent 1px);
  background-size: 32px 32px;
  /* Le masque etait inverse : la trame etait pleine AU CENTRE, donc pile
     par-dessus le clip et le titre, ou elle se lisait comme de la salissure.
     Elle sert a border, pas a couvrir : on la garde sur les marges et on la
     retire du centre. */
  -webkit-mask-image: radial-gradient(96% 76% at 50% 44%, transparent 42%, #000 100%);
          mask-image: radial-gradient(96% 76% at 50% 44%, transparent 42%, #000 100%);
  opacity: .8;
}

.n-hero__pill {
  display: inline-flex; align-items: center; gap: var(--n-sp-5);
  padding: 7px 8px 7px 14px;
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-pill);
  background: rgba(255,255,255,.6);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-muted);
}
:root[data-theme="dark"] .n-hero__pill { background: rgba(20,20,32,.6); }
.n-hero__pill b {
  padding: 3px 9px; border-radius: var(--n-r-pill);
  color: var(--n-text-on-accent); background-image: var(--n-grad-ink);
  font-weight: var(--n-fw-medium); letter-spacing: var(--n-ls-wide);
}
.n-hero__title { margin-block-start: var(--n-sp-9); max-inline-size: 15ch; }
.n-hero__lead  { margin-block-start: var(--n-sp-9); max-inline-size: 54ch;
                 margin-inline: auto; }

/* Le point de conversion du heros : un seul bouton, plein contraste. Il
   remplace la barre de depot d'e-mail — la demande d'acces vit sur la page
   des tarifs, la ou elle a un contexte. */
.n-hero__cta { margin-block-start: var(--n-sp-10); }

.n-hero__hint {
  display: flex; flex-direction: column; align-items: center; gap: var(--n-sp-4);
  margin-block-start: auto; padding-block-start: var(--n-sp-12);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--n-text-faint);
}
.n-hero__hint span { animation: n-hint 2s var(--n-ease-inout) infinite; }

/* La reglette de telemetrie sous le heros : ce que le clip de fond EST. */
.n-telemetry {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-6); flex-wrap: wrap;
  padding-block: var(--n-sp-6) var(--n-sp-7);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-telemetry b { color: var(--n-text-muted); font-weight: var(--n-fw-normal); }
.n-telemetry__live { display: inline-flex; align-items: center; gap: var(--n-sp-4); }
.n-telemetry__live::before {
  content: ""; inline-size: 6px; block-size: 6px; border-radius: 50%;
  background: var(--n-ok); animation: n-pulse 1.8s var(--n-ease-inout) infinite;
}

/* == 11 · BANDEAUX DE RENDUS QUI DEFILENT =================================
   Le coeur de la demande : deux bandes de clips qui traversent la page,
   l'une vers la gauche, l'autre vers la droite. Chaque tuile porte une
   VIDEO, pas une image — l'affiche tient la place, la boucle prend le
   relais quand la bande entre dans le champ.
   Le masque en degrade fait disparaitre les bords : la bande n'a ni debut
   ni fin, elle passe.
   ========================================================================= */

.n-band { overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent); }
.n-band + .n-band { margin-block-start: var(--n-sp-6); }
.n-band__rail {
  display: flex; gap: var(--n-sp-6); inline-size: max-content;
  animation: n-marquee 64s linear infinite;
  will-change: transform;
}
.n-band--rev .n-band__rail { animation-name: n-marquee-rev; animation-duration: 78s; }
/* la bande s'arrete quand on la survole : on veut pouvoir regarder un clip */
.n-band:hover .n-band__rail, .n-band:focus-within .n-band__rail { animation-play-state: paused; }

.n-slab {
  position: relative; flex: none; margin: 0;
  inline-size: 340px; aspect-ratio: 16 / 9;
  overflow: hidden; border-radius: var(--n-r-lg);
  background: var(--n-bg-deep);
  border: 1px solid var(--n-line-2);
}
.n-slab--tall { inline-size: 200px; aspect-ratio: 9 / 16; }
.n-slab > img, .n-slab > video {
  inline-size: 100%; block-size: 100%; object-fit: cover;
}
.n-slab > video { position: absolute; inset: 0; opacity: 0;
                  transition: opacity var(--n-dur-3) var(--n-ease-out); }
.n-slab[data-playing="true"] > video { opacity: 1; }
.n-slab__id {
  position: absolute; inset-block-end: 11px; inset-inline-start: 12px;
  padding: 5px 10px; border-radius: var(--n-r-pill);
  background: rgba(255,255,255,.88);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); color: #33333B;
}

/* == 12 · ETAPES ========================================================== */

.n-steps-list { display: flex; flex-direction: column; gap: var(--n-sp-6); }
.n-move {
  display: grid; grid-template-columns: 1fr; gap: var(--n-sp-6);
  padding: var(--n-sp-10);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-2xl);
  background: var(--n-surface-1);
  transition: border-color var(--n-dur-3) var(--n-ease-out),
              box-shadow var(--n-dur-3) var(--n-ease-out);
}
@media (min-width: 640px) { .n-move { grid-template-columns: 82px minmax(0,1fr);
                                      gap: var(--n-sp-9); } }
.n-move:hover { border-color: var(--n-line-accent); box-shadow: var(--n-shadow-4); }
.n-move__num {
  font-family: var(--n-font-mono); font-size: var(--n-fs-xs);
  letter-spacing: var(--n-ls-wide); line-height: 1.7;
  color: var(--n-accent);
  background-image: var(--n-grad-text);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  text-transform: uppercase;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .n-move__num { -webkit-text-fill-color: currentColor; }
}
.n-move__title { font-size: var(--n-fs-2xl); font-weight: var(--n-fw-medium);
                 letter-spacing: var(--n-ls-h3); color: var(--n-text); }
.n-move__body  { margin-block-start: var(--n-sp-5); font-size: var(--n-fs-sm);
                 line-height: 1.62; color: var(--n-text-muted); text-wrap: pretty; }

/* == 13 · FORMATS =========================================================
   Six cartes, chacune montrant son ratio A SA VRAIE PROPORTION. Le
   rectangle porte la rampe de DECOR — aucun texte ne se pose dessus.
   ========================================================================= */

.n-formats {
  display: grid; gap: var(--n-sp-6);
  grid-template-columns: repeat(2, minmax(0,1fr));
  align-items: end;
}
@media (min-width: 560px) { .n-formats { grid-template-columns: repeat(3, minmax(0,1fr)); } }
@media (min-width: 960px) { .n-formats { grid-template-columns: repeat(6, minmax(0,1fr)); } }
.n-format {
  padding: var(--n-sp-7);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-xl);
  background: var(--n-surface-1);
  transition: transform var(--n-dur-3) var(--n-ease-out),
              border-color var(--n-dur-3) var(--n-ease-out);
}
.n-format:hover { transform: translateY(-6px); border-color: var(--n-line-accent); }
.n-format__box { block-size: 96px; display: flex; align-items: center; justify-content: center; }
.n-format__box i {
  display: block; border-radius: var(--n-r-xs);
  background-image: var(--n-grad); opacity: .9;
  inline-size: var(--n-fw, 88px); block-size: var(--n-fh, 50px);
}
.n-format b { display: block; margin-block-start: var(--n-sp-6);
              font-size: var(--n-fs-lg); font-weight: var(--n-fw-medium);
              letter-spacing: -0.02em; color: var(--n-text); }
.n-format small { display: block; margin-block-start: 5px;
                  font-size: var(--n-fs-2xs); color: var(--n-text-dim); }

/* == 14 · MUR DE RENDUS ===================================================
   Deux grilles, comme la maquette : neuf 16:9 puis six 9:16. Chaque tuile
   joue sa boucle au survol, au focus clavier et a l'appui.
   ========================================================================= */

.n-wall { display: grid; gap: var(--n-sp-6); grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width: 720px) { .n-wall { grid-template-columns: repeat(3, minmax(0,1fr)); } }
.n-wall--tall { grid-template-columns: repeat(3, minmax(0,1fr)); margin-block-start: var(--n-sp-6); }
@media (min-width: 720px) { .n-wall--tall { grid-template-columns: repeat(6, minmax(0,1fr)); } }

.n-tile {
  position: relative; display: block; inline-size: 100%;
  margin: 0; aspect-ratio: 16 / 9;
  overflow: hidden; border-radius: var(--n-r-xl);
  background: var(--n-bg-deep);
  border: 1px solid var(--n-line-2);
  cursor: pointer;
  transition: border-color var(--n-dur-2) var(--n-ease-out),
              box-shadow var(--n-dur-3) var(--n-ease-out);
}
.n-tile--tall { aspect-ratio: 9 / 16; }
.n-tile > img, .n-tile > video { inline-size: 100%; block-size: 100%; object-fit: cover; }
.n-tile > img { transition: transform var(--n-dur-5) var(--n-ease-emph); }
.n-tile > video { position: absolute; inset: 0; opacity: 0;
                  transition: opacity var(--n-dur-3) var(--n-ease-out); }
.n-tile[data-playing="true"] > video { opacity: 1; }
.n-tile:hover, .n-tile:focus-visible { border-color: var(--n-accent-lo);
                                        box-shadow: var(--n-shadow-4); }
.n-tile:hover > img { transform: scale(1.06); }
.n-tile__cap {
  position: absolute; inset: auto 12px 12px 12px;
  display: flex; align-items: center; justify-content: space-between; gap: var(--n-sp-5);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); color: #33333B;
  pointer-events: none;
}
.n-tile__cap span {
  padding: 5px 10px; border-radius: var(--n-r-pill);
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.n-tile--tall .n-tile__cap { inset: auto 10px 10px 10px; }
.n-tile--tall .n-tile__cap span:last-child { display: none; }
.n-tile[hidden] { display: none; }

.n-filters { display: flex; flex-wrap: wrap; gap: var(--n-sp-4); border: 0; padding: 0; margin: 0; }
.n-filters legend { position: absolute; inline-size: 1px; block-size: 1px;
                    overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.n-filter { position: relative; }
.n-filter input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.n-filter span {
  display: inline-flex; align-items: center; gap: var(--n-sp-3);
  min-block-size: 36px; padding-inline: var(--n-sp-7);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-pill);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-muted); background: var(--n-surface-1);
  transition: color var(--n-dur-1) var(--n-ease-out),
              border-color var(--n-dur-1) var(--n-ease-out);
}
.n-filter input:hover + span { border-color: var(--n-line-strong); color: var(--n-text); }
.n-filter input:focus-visible + span { outline: var(--n-focus-w) solid var(--n-focus);
                                        outline-offset: var(--n-focus-offset); }
.n-filter input:checked + span {
  color: var(--n-text-on-accent); background-image: var(--n-grad-ink); border-color: transparent;
}
.n-filter b { font-weight: var(--n-fw-normal); opacity: .75; }

/* == 15 · PANNEAU VIDEO DOCUMENTE =========================================
   Le grand cadre de la section « pourquoi la montre ». La maquette y met
   une image ; on y met le clip, avec son cartouche technique — c'est la
   piece qui dit « ceci est un rendu, pas une photo de stock ».
   ========================================================================= */

.n-panel {
  position: relative; margin: 0;
  aspect-ratio: 16 / 10; overflow: hidden;
  border-radius: var(--n-r-3xl);
  background: var(--n-bg-deep);
  border: 1px solid var(--n-line-2);
  box-shadow: var(--n-shadow-4);
}
.n-panel--portrait { aspect-ratio: 9 / 16; max-inline-size: 420px; margin-inline: auto; }
.n-panel > img, .n-panel > video { inline-size: 100%; block-size: 100%; object-fit: cover; }
.n-panel > video { position: absolute; inset: 0; opacity: 0;
                   transition: opacity var(--n-dur-4) var(--n-ease-out); }
.n-panel[data-playing="true"] > video { opacity: 1; }

/* les quatre equerres : le cadre du plateau, pose sur le clip */
.n-panel__marks { position: absolute; inset: 16px; pointer-events: none; }
.n-panel__marks span {
  position: absolute; inline-size: 16px; block-size: 16px;
  border: 0 solid rgba(255,255,255,.7);
}
.n-panel__marks span:nth-child(1){inset-block-start:0;inset-inline-start:0;border-block-start-width:1.5px;border-inline-start-width:1.5px}
.n-panel__marks span:nth-child(2){inset-block-start:0;inset-inline-end:0;border-block-start-width:1.5px;border-inline-end-width:1.5px}
.n-panel__marks span:nth-child(3){inset-block-end:0;inset-inline-start:0;border-block-end-width:1.5px;border-inline-start-width:1.5px}
.n-panel__marks span:nth-child(4){inset-block-end:0;inset-inline-end:0;border-block-end-width:1.5px;border-inline-end-width:1.5px}

.n-panel__cap {
  position: absolute; inset: auto 16px 16px 16px;
  display: flex; justify-content: space-between; gap: var(--n-sp-5); flex-wrap: wrap;
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); color: #33333B;
}
.n-panel__cap span {
  padding: 5px 10px; border-radius: var(--n-r-pill);
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.n-panel__play {
  position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  transform: translate(-50%,-50%);
  inline-size: 64px; block-size: 64px;
  display: grid; place-items: center;
  border-radius: 50%; background: rgba(255,255,255,.94);
  color: #0B0B0F; cursor: pointer;
  box-shadow: var(--n-shadow-3);
  transition: transform var(--n-dur-2) var(--n-ease-out), opacity var(--n-dur-3) var(--n-ease-out);
}
.n-panel__play svg { inline-size: 20px; block-size: 20px; margin-inline-start: 3px; }
.n-panel__play:hover { transform: translate(-50%,-50%) scale(1.07); }
.n-panel[data-sound="true"] .n-panel__play { opacity: 0; pointer-events: none; }

/* == 16 · SPECIFICATIONS ================================================== */

.n-spec { margin: 0; display: grid; grid-template-columns: 1fr; }
.n-spec__row {
  display: grid; grid-template-columns: 1fr; gap: var(--n-sp-3);
  padding-block: var(--n-sp-7);
  border-block-start: 1px solid var(--n-line-2);
}
@media (min-width: 600px) {
  .n-spec__row { grid-template-columns: minmax(0,.7fr) minmax(0,1.3fr); gap: var(--n-sp-8);
                 align-items: baseline; }
}
.n-spec__label {
  font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint); margin: 0;
}
.n-spec__value { margin: 0; font-size: var(--n-fs-lg); letter-spacing: -0.015em;
                 color: var(--n-text); overflow-wrap: anywhere; }
/* ce qui n'est pas mesure se voit : c'est une dette, pas un ornement */
.n-spec__value[data-todo] {
  color: var(--n-warn); font-family: var(--n-font-mono);
  font-size: var(--n-fs-sm); border-block-end: 1px dashed var(--n-warn);
  display: inline-block;
}
.n-todo {
  display: inline-flex; align-items: baseline; gap: var(--n-sp-3);
  padding: 2px var(--n-sp-4); border: 1px dashed var(--n-warn);
  border-radius: var(--n-r-xs); background: var(--n-warn-soft);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); color: var(--n-warn);
}

/* == 17 · PALIERS =========================================================
   Quatre cartes, comme la maquette. Le drapeau du palier vedette est pose
   en absolu : il ne doit pas pousser sa colonne, sinon les quatre prix ne
   s'alignent plus et la grille cesse d'etre comparable.
   ========================================================================= */

.n-plans { display: grid; gap: var(--n-sp-6); grid-template-columns: 1fr; }
@media (min-width: 620px)  { .n-plans { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (min-width: 1080px) { .n-plans { grid-template-columns: repeat(4, minmax(0,1fr)); } }

.n-card-plan {
  position: relative; display: flex; flex-direction: column;
  padding: var(--n-sp-13) var(--n-sp-9) var(--n-sp-9);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-2xl);
  background: var(--n-surface-1);
  transition: border-color var(--n-dur-3) var(--n-ease-out),
              box-shadow var(--n-dur-3) var(--n-ease-out);
}
.n-card-plan:hover { border-color: var(--n-line-accent); box-shadow: var(--n-shadow-4); }
.n-card-plan--featured { border-color: var(--n-line-accent); }
.n-card-plan__flag {
  position: absolute; inset-block-start: var(--n-sp-9); inset-inline-start: var(--n-sp-9);
  padding: 4px 9px; border-radius: var(--n-r-pill);
  color: var(--n-text-on-accent); background-image: var(--n-grad-ink);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase;
}
.n-card-plan__name  { font-size: var(--n-fs-lg); font-weight: var(--n-fw-medium);
                      letter-spacing: -0.02em; color: var(--n-text); }
.n-card-plan__price { display: flex; align-items: baseline; gap: var(--n-sp-4);
                      margin-block: var(--n-sp-7) var(--n-sp-2); }
.n-card-plan__amount{ font-size: var(--n-fs-4xl); font-weight: var(--n-fw-medium);
                      letter-spacing: -0.045em; line-height: 1; color: var(--n-text); }
.n-card-plan__cycle { font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
                      letter-spacing: var(--n-ls-wide); text-transform: uppercase;
                      color: var(--n-text-faint); }
.n-card-plan__pitch { margin-block: var(--n-sp-7) var(--n-sp-8);
                      font-size: var(--n-fs-sm); line-height: 1.6;
                      color: var(--n-text-muted); text-wrap: pretty; }
.n-card-plan__features { display: flex; flex-direction: column; gap: var(--n-sp-5);
                         list-style: none; padding: 0; margin: 0 0 var(--n-sp-9); }
.n-card-plan__feature { display: flex; gap: var(--n-sp-5); align-items: flex-start;
                        font-size: var(--n-fs-sm); color: var(--n-text); }
.n-card-plan__feature svg { inline-size: 14px; block-size: 14px; flex: none;
                            margin-block-start: 4px; color: var(--n-accent); }
.n-card-plan__feature[data-included="false"] { color: var(--n-text-dim); }
.n-card-plan__feature[data-included="false"] svg { color: var(--n-text-disabled); }
.n-card-plan__cta { margin-block-start: auto; }
/* la jauge : ce que le palier achete, d'un coup d'oeil */
.n-quota { display: flex; flex-direction: column; gap: var(--n-sp-4);
           margin-block-end: var(--n-sp-8); }
.n-quota__label { display: flex; justify-content: space-between; gap: var(--n-sp-5);
                  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
                  letter-spacing: var(--n-ls-wide); text-transform: uppercase;
                  color: var(--n-text-faint); }
.n-quota__label b { color: var(--n-text); font-weight: var(--n-fw-medium); }
.n-quota__track { block-size: 3px; border-radius: 2px; background: var(--n-surface-3); }
.n-quota__bar   { block-size: 100%; border-radius: 2px; inline-size: var(--n-quota, 25%);
                  background-image: var(--n-grad); }
.n-quota--open .n-quota__bar {
  inline-size: 100%;
  background: repeating-linear-gradient(135deg, var(--n-line-3) 0 2px, transparent 2px 6px);
}

/* == 18 · APPEL FINAL & 19 · PIED DE PAGE ================================= */

.n-cta { position: relative; overflow: hidden; text-align: center;
         padding-block: var(--n-sp-15) var(--n-sp-16); isolation: isolate; }
/* LE FOND DE L'APPEL FINAL. Une section n'a pas les bords d'un heros : en
   haut elle touche les prix, en bas le pied de page. Une mosaique posee a
   plat y ferait deux traits nets — le premier essai, en masque radial, en
   laissait justement un bord net en bas, parce qu'un radial dimensionne pour
   couvrir les coins est encore a 77 % d'opacite au milieu d'un bord.
   Le masque est donc VERTICAL : la mosaique nait sous les prix et meurt
   au-dessus du pied de page, et elle se raccorde a n'importe quel fond de
   section sans qu'on ait a en connaitre la couleur. Les bords gauche et
   droit, eux, sont ceux de l'ecran : ils n'ont rien a fondre. */
.n-cta__bg {
  position: absolute; inset: 0; z-index: -3; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 16%,
                                              #000 80%, transparent 100%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 16%,
                                              #000 80%, transparent 100%);
}
/* Deux points de flou, et c'est tout ce qui separe une tapisserie d'une
   planche-contact. Dans le heros la mosaique etait nette, et c'etait juste :
   elle y demontrait la qualite des rendus. Ici elle ne demontre plus rien —
   le mur au-dessus l'a fait, en grand et net. Ce qui reste est un fond, et
   un fond ne doit pas donner a lire douze vignettes bord a bord : le flou
   mange les jointures que le voile ne mange plus, sans rien couter puisque
   la couche est deja composee a part (masque + z-index). */
.n-cta__bg .n-mosaic { filter: blur(2px) saturate(.94); }
/* LE VOILE, et le meme calcul qu'au heros : le texte se juge sur son PIRE
   cadre, un plan entierement noir. Le voile PLAT porte la garantie — 0,60,
   jamais moins, nulle part : sur du noir il compose un #999999 ou l'encre
   #0B0B0F tient 6,6:1, partout, quel que soit le clip qui passe dessous. Le
   halo n'ajoute que du confort au centre, ou la composition monte a 0,81.
   Le premier essai posait toute la lisibilite sur le halo : le fond en
   sortait clair au milieu et sature aux bords, et le halo se lisait comme
   une tache blanche. Un voile plat ne se voit pas, c'est tout son merite. */
.n-cta__veil {
  position: absolute; inset: 0; z-index: -2; pointer-events: none;
  background:
    radial-gradient(80% 74% at 50% 50%, rgba(255,255,255,.52) 0%,
                    rgba(255,255,255,.18) 62%, transparent 100%),
    linear-gradient(rgba(255,255,255,.60), rgba(255,255,255,.60));
}
/* Le lead du heros est en encre pleine et pas en gris, pour la meme raison :
   un gris sur une image qui bouge ne tient plus son rapport. Ici aussi. */
.n-cta .n-lead { color: var(--n-text); font-weight: var(--n-fw-normal); }
/* Meme retournement qu'au heros, meme calcul : le voile PLAT porte la
   garantie. 0,62 sur un cadre blanc compose un #686868 ou l'encre claire
   tient 4,96:1 ; le halo monte le centre a 0,83, soit 10,9:1. */
:root:not([data-theme="light"]) .n-cta__veil {
  background:
    radial-gradient(80% 74% at 50% 50%, rgba(11,11,15,.54) 0%,
                    rgba(11,11,15,.20) 62%, transparent 100%),
    linear-gradient(rgba(11,11,15,.62), rgba(11,11,15,.62));
}
:root:not([data-theme="light"]) .n-cta .n-lead { color: var(--n-text); }
:root[data-theme="dark"] .n-cta__veil {
  background:
    radial-gradient(80% 74% at 50% 50%, rgba(11,11,15,.54) 0%,
                    rgba(11,11,15,.20) 62%, transparent 100%),
    linear-gradient(rgba(11,11,15,.62), rgba(11,11,15,.62));
}
:root[data-theme="dark"] .n-cta .n-lead { color: var(--n-text); }
.n-cta__inner { position: relative; max-inline-size: 900px; margin-inline: auto; }

.n-footer { padding-block: var(--n-sp-12) var(--n-sp-11);
            border-block-start: 1px solid var(--n-line); background: var(--n-bg); }
.n-footer__grid { display: grid; gap: var(--n-sp-10); grid-template-columns: 1fr; }
@media (min-width: 640px)  { .n-footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .n-footer__grid { grid-template-columns: minmax(0,1.4fr) repeat(3, minmax(0,.6fr)); } }
.n-footer__brand { display: flex; flex-direction: column; align-items: flex-start;
                   gap: var(--n-sp-6); }
.n-footer__pitch { max-inline-size: 38ch; font-size: var(--n-fs-xs); line-height: 1.6;
                   color: var(--n-text-dim); }
.n-footer__title { font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
                   letter-spacing: var(--n-ls-caps); text-transform: uppercase;
                   color: var(--n-text-faint); margin-block-end: var(--n-sp-6); }
.n-footer__list  { display: flex; flex-direction: column; gap: var(--n-sp-5); }
.n-footer__link  { font-size: var(--n-fs-xs); color: var(--n-text-muted); min-block-size: 24px;
                   transition: color var(--n-dur-1) var(--n-ease-out); }
.n-footer__link:hover { color: var(--n-accent-hi); }
.n-footer__bottom {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-8); flex-wrap: wrap;
  margin-block-start: var(--n-sp-11); padding-block-start: var(--n-sp-8);
  border-block-start: 1px solid var(--n-line);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase;
  color: var(--n-text-faint);
}
/* La signature de la maison : Numeri est un LOGICIEL edite par Odratta,
   donc « Developed by », jamais « Realise par ». */
.n-footer__by {
  display: inline-flex; align-items: baseline; gap: .45em;
  color: var(--n-text-faint); text-transform: none; letter-spacing: var(--n-ls-wide);
  transition: color var(--n-dur-1) var(--n-ease-out);
}
.n-footer__by:hover { color: var(--n-text); }
.n-footer__by svg { block-size: .85em; inline-size: auto; flex: none; opacity: .85; }
.n-footer__by:hover svg { opacity: 1; }

/* == 20 · COMPOSANTS DE L'APPLICATION (/app) ==============================
   Ils ne servent pas au vitrine mais app.css importe cette feuille et
   compte dessus. Les retirer casserait l'application.
   ========================================================================= */

.n-card { position: relative; background: var(--n-surface-1);
          border: 1px solid var(--n-line-2); border-radius: var(--n-r-2xl); overflow: hidden; }

.n-typeselect { border: 0; margin: 0; padding: 0; }
.n-typeselect__legend { padding: 0; margin-block-end: var(--n-sp-7);
  font-size: var(--n-fs-xs); font-weight: var(--n-fw-medium); color: var(--n-text-muted);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase; }
.n-typeselect__grid { display: grid; gap: var(--n-sp-5); grid-template-columns: repeat(2, minmax(0,1fr)); }
@media (min-width: 768px) { .n-typeselect__grid { grid-template-columns: repeat(4, minmax(0,1fr)); } }
.n-typeopt { position: relative; }
.n-typeopt input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
                   opacity: 0; margin: 0; cursor: pointer; }
.n-typeopt__face { position: relative; display: flex; flex-direction: column; gap: var(--n-sp-5);
  padding: var(--n-sp-8) var(--n-sp-7) var(--n-sp-7); min-block-size: 44px;
  background: var(--n-surface-1); border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-xl);
  transition: border-color var(--n-dur-2) var(--n-ease-out),
              background-color var(--n-dur-2) var(--n-ease-out); }
.n-typeopt__icon { inline-size: 28px; block-size: 28px; color: var(--n-text-faint); }
.n-typeopt__name { font-size: var(--n-fs-sm); font-weight: var(--n-fw-medium); color: var(--n-text); }
.n-typeopt__note { font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
                   letter-spacing: var(--n-ls-wide); color: var(--n-text-faint);
                   text-transform: uppercase; }
.n-typeopt input:hover + .n-typeopt__face { border-color: var(--n-line-strong); }
.n-typeopt input:focus-visible + .n-typeopt__face { outline: var(--n-focus-w) solid var(--n-focus);
                                                    outline-offset: var(--n-focus-offset); }
.n-typeopt input:checked + .n-typeopt__face { border-color: var(--n-accent);
  box-shadow: inset 0 0 0 1px var(--n-accent); background: var(--n-accent-veil); }
.n-typeopt input:checked + .n-typeopt__face .n-typeopt__icon,
.n-typeopt input:checked + .n-typeopt__face .n-typeopt__note { color: var(--n-accent); }
.n-typeopt input:disabled + .n-typeopt__face { opacity: .45; cursor: not-allowed; }
/* la coche est un trait, pas une pastille : la selection ne repose jamais
   sur la seule couleur */
.n-typeopt input:checked + .n-typeopt__face::after {
  content: ""; position: absolute;
  inset-block-start: var(--n-sp-6); inset-inline-end: var(--n-sp-6);
  inline-size: 10px; block-size: 6px;
  border-inline-start: 1.5px solid var(--n-accent);
  border-block-end: 1.5px solid var(--n-accent);
  transform: rotate(-45deg);
}

.n-drop { position: relative; display: grid; place-items: center; gap: var(--n-sp-6);
  min-block-size: 260px; padding: var(--n-sp-11) var(--n-sp-7); text-align: center;
  background: var(--n-surface-1); border: 1px dashed var(--n-line-3);
  border-radius: var(--n-r-3xl);
  transition: border-color var(--n-dur-2) var(--n-ease-out),
              background-color var(--n-dur-2) var(--n-ease-out); }
.n-drop__input { position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
                 opacity: 0; cursor: pointer; }
.n-drop__icon  { inline-size: 32px; block-size: 32px; color: var(--n-text-faint); }
.n-drop__title { font-size: var(--n-fs-lg); font-weight: var(--n-fw-medium); color: var(--n-text); }
.n-drop__hint  { font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
                 color: var(--n-text-dim); letter-spacing: var(--n-ls-wide); }
.n-drop:hover, .n-drop:focus-within { border-color: var(--n-accent-lo);
                                       background: var(--n-accent-veil); }
.n-drop[data-state="over"]  { border-color: var(--n-accent); background: var(--n-accent-soft); }
.n-drop[data-state="over"] .n-drop__icon { color: var(--n-accent); }
.n-drop[data-state="error"] { border-color: var(--n-danger); }
.n-drop[data-state="filled"]{ padding: var(--n-sp-6); min-block-size: 0; border-style: solid; }
.n-drop__preview { display: flex; gap: var(--n-sp-6); align-items: center;
                   inline-size: 100%; text-align: start; }
.n-drop__thumb { inline-size: 72px; block-size: 72px; flex: none; object-fit: cover;
                 border-radius: var(--n-r-md); background: var(--n-bg-deep);
                 border: 1px solid var(--n-line-2); }

.n-progress { display: flex; flex-direction: column; gap: var(--n-sp-5); }
.n-progress__head { display: flex; justify-content: space-between; align-items: baseline;
                    gap: var(--n-sp-6); }
.n-progress__step { font-size: var(--n-fs-sm); color: var(--n-text); }
.n-progress__pct  { font-family: var(--n-font-mono); font-size: var(--n-fs-sm);
                    color: var(--n-accent); font-variant-numeric: tabular-nums; }
.n-progress__track { position: relative; block-size: 3px; inline-size: 100%;
                     background: var(--n-surface-3); border-radius: 2px; overflow: hidden; }
.n-progress__bar { position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 100%;
                   background-image: var(--n-grad); transform-origin: left center;
                   transform: scaleX(var(--n-progress, 0));
                   transition: transform var(--n-dur-4) var(--n-ease-out); }
.n-progress[data-state="indeterminate"] .n-progress__bar {
  inline-size: 32%; transform: none; animation: n-sweep var(--n-dur-6) var(--n-ease-inout) infinite; }
.n-progress[data-state="done"]   .n-progress__bar { background: var(--n-ok); background-image: none; }
.n-progress[data-state="failed"] .n-progress__bar { background: var(--n-danger); background-image: none; }
.n-progress[data-state="done"]   .n-progress__pct { color: var(--n-ok); }
.n-progress[data-state="failed"] .n-progress__pct { color: var(--n-danger); }
.n-progress__foot { display: flex; justify-content: space-between; gap: var(--n-sp-6); }

.n-steps { display: flex; gap: var(--n-sp-5); flex-wrap: wrap; }
.n-step { display: flex; align-items: center; gap: var(--n-sp-4);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase; color: var(--n-text-faint); }
.n-step::before { content: ""; inline-size: 6px; block-size: 6px; border-radius: 50%;
                  border: 1px solid currentColor; }
.n-step[data-state="active"] { color: var(--n-accent); }
.n-step[data-state="active"]::before { background: currentColor; }
.n-step[data-state="done"] { color: var(--n-ok); }
.n-step[data-state="done"]::before { background: currentColor; }

.n-player { position: relative; background: var(--n-bg-deep);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-2xl);
  overflow: hidden; aspect-ratio: 16 / 9; isolation: isolate; }
.n-player--portrait { aspect-ratio: 9 / 16; max-inline-size: 420px; }
.n-player--square   { aspect-ratio: 1 / 1; }
.n-player video { inline-size: 100%; block-size: 100%; object-fit: contain;
                  background: var(--n-bg-deep); }

.n-skeleton { position: relative; overflow: hidden; background: var(--n-surface-2);
              border-radius: var(--n-r-md); }
.n-skeleton::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(11,11,15,.05), transparent);
  transform: translateX(-100%); animation: n-sweep 1.4s var(--n-ease-inout) infinite; }

/* == 21 · ANIMATIONS ======================================================
   Regle unique : transform et opacity, rien d'autre. Une animation de
   width, top ou box-shadow ne passe pas par le compositeur et fait tomber
   sous 60 fps sur telephone.
   ========================================================================= */

@keyframes n-spin { to { transform: rotate(360deg); } }
@keyframes n-sweep { 0% { transform: translateX(-110%); } 100% { transform: translateX(360%); } }
@keyframes n-rise { from { opacity: 0; transform: translate3d(0,26px,0); } to { opacity: 1; transform: none; } }
@keyframes n-float { 0%,100% { transform: translate3d(0,0,0) scale(1); }
                     50% { transform: translate3d(0,-24px,0) scale(1.05); } }
@keyframes n-hint { 0%,100% { transform: translateY(0); opacity: .55; }
                    50% { transform: translateY(7px); opacity: 1; } }
@keyframes n-pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
@keyframes n-drift {
  from { transform: scale(1.06) translate3d(0, 0, 0); }
  to   { transform: scale(1.06) translate3d(0, -3.5%, 0); }
}
@keyframes n-marquee { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
@keyframes n-marquee-rev { from { transform: translate3d(-50%,0,0); } to { transform: translate3d(0,0,0); } }

/* Apparition au defilement. Le h1 du heros n'est JAMAIS anime : un titre
   anime plombe le LCP — mesure une fois a 1,3 s au lieu de 0,14 s. */
.n-reveal { opacity: 0; }
.n-reveal.is-in { animation: n-rise var(--n-dur-5) var(--n-ease-emph) both; }
.n-reveal[data-delay="1"].is-in { animation-delay: 70ms; }
.n-reveal[data-delay="2"].is-in { animation-delay: 140ms; }
.n-reveal[data-delay="3"].is-in { animation-delay: 210ms; }
.n-reveal[data-delay="4"].is-in { animation-delay: 280ms; }
.n-reveal[data-delay="5"].is-in { animation-delay: 350ms; }
.n-hero .n-h1, h1.n-reveal { opacity: 1; animation: none; }
/* l'entree du heros, elle, se joue en CSS pur : rien a attendre du JS */
.n-hero__pill  { animation: n-rise var(--n-dur-5) var(--n-ease-emph) both; }
.n-hero__lead  { animation: n-rise var(--n-dur-5) 120ms var(--n-ease-emph) both; }
.n-hero__cta   { animation: n-rise var(--n-dur-5) 180ms var(--n-ease-emph) both; }

/* sans JavaScript, rien ne doit rester invisible */
.no-js .n-reveal { opacity: 1; animation: none; }

/* == 22 · PREFERS-REDUCED-MOTION ==========================================
   Tout s'eteint, rien ne disparait. Les bandeaux s'arretent, les videos ne
   partent pas seules, les etats de depart deviennent l'etat final.
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    animation-delay: 0s !important; transition-duration: .001ms !important;
    transition-delay: 0s !important; scroll-behavior: auto !important;
  }
  .n-reveal, .n-reveal.is-in,
  .n-hero__pill, .n-hero__lead, .n-hero__cta { opacity: 1; transform: none; animation: none; }
  .n-band__rail { animation: none; transform: none; }
  .n-mosaic { animation: none; }
  .n-band { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
  .n-blob { animation: none; }
  .n-hero__hint span { animation: none; }
  .n-telemetry__live::before { animation: none; }
  .n-progress[data-state="indeterminate"] .n-progress__bar {
    animation: none; inline-size: 100%; opacity: .5; }
  .n-btn[data-loading="true"]::after { animation: none; border-block-start-color: currentColor; }
  .n-tile:hover > img, .n-format:hover { transform: none; }
  .n-panel__play:hover { transform: translate(-50%,-50%); }
}

/* == 23 · UTILITAIRES ====================================================
   Ils existent pour UNE raison : la CSP du vhost refuse 'unsafe-inline',
   et un attribut style="" y est ignore SANS erreur — la page se decompose
   en silence et le defaut ne se voit qu'en production.
   Les valeurs d'INSTANCE (proportion d'un format, remplissage d'une jauge)
   passent donc aussi par une classe qui pose la variable.
   ========================================================================= */

.n-mt-5{margin-block-start:var(--n-sp-5)} .n-mt-6{margin-block-start:var(--n-sp-6)}
.n-mt-7{margin-block-start:var(--n-sp-7)} .n-mt-8{margin-block-start:var(--n-sp-8)}
.n-mt-9{margin-block-start:var(--n-sp-9)} .n-mt-10{margin-block-start:var(--n-sp-10)}
.n-mt-11{margin-block-start:var(--n-sp-11)} .n-mt-12{margin-block-start:var(--n-sp-12)}
.n-mt-auto{margin-block-start:auto}
.n-mb-6{margin-block-end:var(--n-sp-6)} .n-mb-7{margin-block-end:var(--n-sp-7)}
.n-mb-9{margin-block-end:var(--n-sp-9)} .n-mb-11{margin-block-end:var(--n-sp-11)}
.n-my-6{margin-block:var(--n-sp-6)} .n-my-7-9{margin-block:var(--n-sp-7) var(--n-sp-9)}
.n-my-6-9{margin-block:var(--n-sp-6) var(--n-sp-9)}
.n-my-6-11{margin-block:var(--n-sp-6) var(--n-sp-11)}
.n-m0{margin:0}
.n-measure-15{max-inline-size:15ch} .n-measure-20{max-inline-size:20ch}
.n-measure-24{max-inline-size:24ch} .n-measure-30{max-inline-size:30ch}
.n-measure-34{max-inline-size:34ch} .n-measure-38{max-inline-size:38ch}
.n-measure-48{max-inline-size:48ch} .n-measure-78{max-inline-size:78ch}
.n-center{text-align:center} .n-mx-auto{margin-inline:auto}
.n-hide{display:none!important}
@media (max-width:639.98px){ .n-only\@sm{display:none!important} }
.n-symbols{position:absolute;inline-size:0;block-size:0;overflow:hidden}
.n-honeypot{position:absolute;inset-inline-start:-9999px;inline-size:1px;block-size:1px;
            opacity:0;pointer-events:none}
.n-note{padding:var(--n-sp-9);margin-block-end:var(--n-sp-7)}
.n-note--ok{border-color:var(--n-ok)} .n-note--danger{border-color:var(--n-danger)}
.n-t-ok{color:var(--n-ok)} .n-t-danger{color:var(--n-danger)}
.n-grid-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--n-sp-6)}
.n-span-all{grid-column:1/-1}
.n-plain-list{list-style:none;padding:0;margin:0}

/* proportions vraies des six formats */
.n-ar-21x9{--n-fw:88px;--n-fh:38px} .n-ar-16x9{--n-fw:88px;--n-fh:50px}
.n-ar-4x3 {--n-fw:80px;--n-fh:60px} .n-ar-1x1 {--n-fw:68px;--n-fh:68px}
.n-ar-3x4 {--n-fw:58px;--n-fh:78px} .n-ar-9x16{--n-fw:50px;--n-fh:89px}
/* remplissage des jauges de palier */
.n-quota-25{--n-quota:25%} .n-quota-50{--n-quota:50%} .n-quota-100{--n-quota:100%}

/* == 24 · LA MARQUE, ET LA MISE EN PAGE DES SOUS-PAGES ====================
   Ecrit le 30/08/2026.

   1. LA MARQUE. Le logotype de Numeri est le LOGOTYPE NOIR — le monogramme
      et le mot, d'un seul trace, qui herite de currentColor et suit donc le
      theme sans un octet de plus. La pastille en degrade qui trainait sur
      l'accueil n'etait pas la marque : c'etait une image, avec son fond
      cuit dedans, qui virait au carre blanc des que le theme passait au
      sombre. Elle est retiree partout.

   2. LES SOUS-PAGES. pricing, privacy et terms utilisaient vingt-six classes
      qui n'existaient nulle part dans cette feuille : la grille, le papier,
      les filets, les depliants. Resultat en production : trois pages sans
      aucune mise en page, le logotype a zero pixel de haut, et les quatre
      cartes de palier empilees en liste nue. Tout ce qui suit comble ce
      trou — rien n'est invente, chaque regle repond a un usage du HTML.
   ========================================================================= */

/* -- 24.1 · le logotype ---------------------------------------------------- */
.n-brand {
  display: block;
  block-size: 21px; inline-size: auto;
  aspect-ratio: 1227 / 232;
  color: var(--n-text);
  transition: color var(--n-dur-2) var(--n-ease-out);
}
.n-nav__brand:hover .n-brand { color: var(--n-accent-hi); }
.n-footer__brand .n-brand { block-size: 19px; }
@media (min-width: 640px) { .n-brand { block-size: 23px; } }

/* -- 24.2 · la grille de douze ------------------------------------------- */
.n-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--n-grid-gap);
}
.n-rowgap-9 { row-gap: var(--n-sp-9); }
/* .n-grid-2 vit dans les utilitaires, donc PLUS HAUT dans la feuille : sans
   cette regle, .n-grid le battait a specificite egale et le formulaire
   Business se retrouvait en douze colonnes, chaque champ large d'un
   douzieme. Le defaut ne se voyait qu'en production. */
.n-grid.n-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--n-sp-6); }
.n-col-full { grid-column: 1 / -1; }
@media (min-width: 860px) {
  .n-col-4 { grid-column: span 4; }
  .n-col-5 { grid-column: span 5; }
  .n-col-6 { grid-column: span 6; }
  .n-col-7 { grid-column: span 7; }
  .n-col-8 { grid-column: span 8; }
}

/* -- 24.3 · le papier ----------------------------------------------------
   Une page de texte n'est pas une page de vitrine : la colonne se cale a
   gauche, la mesure reste courte, et rien ne s'etale sur toute la largeur
   sauf ce qui le demande (.n-paper--full). */
/* On ne retrecit PAS le bloc : on retrecit ce qu'il contient. Retrecir le
   bloc, c'est le recentrer dans la fenetre — et l'en-tete de la page se
   decalait alors du bord gauche ou s'alignent les cartes juste en dessous. */
.n-paper > * { max-inline-size: var(--n-container-text); }
.n-paper--full > * { max-inline-size: none; }
.n-paper--full > .n-lead, .n-paper--full > .n-body,
.n-paper--full > .n-small { max-inline-size: 62ch; }

/* -- 24.4 · les filets de section ---------------------------------------- */
.n-ruler {
  block-size: 1px; border: 0; inline-size: 100%;
  background: linear-gradient(90deg, var(--n-line-3) 0%, var(--n-line) 62%, transparent 100%);
}
.n-ruler--b { background: linear-gradient(90deg, transparent 0%, var(--n-line-2) 38%, transparent 100%); }
.n-ruler--c { background: var(--n-line); }

/* -- 24.5 · les quatre faits d'en-tete (pricing) ------------------------- */
/* Quatre faits, donc quatre colonnes ou deux — jamais trois, qui laissent
   une case vide et grise au bout de la rangee. */
.n-facts {
  display: grid; gap: 1px; margin: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  background: var(--n-line); border: 1px solid var(--n-line);
  border-radius: var(--n-r-lg); overflow: hidden;
}
@media (min-width: 720px) { .n-facts { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.n-fact { background: var(--n-bg); padding: var(--n-sp-7) var(--n-sp-8); }
.n-fact dt {
  font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-dim); margin: 0 0 var(--n-sp-3);
}
.n-fact dd {
  margin: 0; font-size: var(--n-fs-xl); font-weight: var(--n-fw-medium);
  letter-spacing: var(--n-ls-h3); color: var(--n-text);
}

/* -- 24.6 · le bandeau et les colonnes de paliers ------------------------ */
.n-plans__band {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--n-sp-4) var(--n-sp-5);
  padding: var(--n-sp-5) var(--n-sp-8);
  margin: 0 0 var(--n-sp-11);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-pill);
  background: var(--n-surface-2);
  font-family: var(--n-font-mono); font-size: var(--n-fs-xs);
  color: var(--n-text-muted); text-align: center;
}
.n-plans__band b { color: var(--n-text); font-weight: var(--n-fw-medium); }
.n-plans__band span:first-child {
  text-transform: uppercase; letter-spacing: var(--n-ls-caps); color: var(--n-text-dim);
}
.n-plans__cols {
  display: grid; gap: var(--n-sp-7);
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  align-items: start;
}
/* Le palier sur devis ne porte pas de prix : sa carte s'ouvre, elle ne se
   compare pas. Un filet en pointille le dit sans un mot de plus. */
.n-card-plan--open { border-style: dashed; background: transparent; }

/* -- 24.7 · les depliants de questions ---------------------------------- */
.n-qa {
  border-block-end: 1px solid var(--n-line);
  padding-block: var(--n-sp-6);
}
.n-qa > summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-6); cursor: pointer; list-style: none;
  font-size: var(--n-fs-lg); font-weight: var(--n-fw-medium);
  letter-spacing: var(--n-ls-h3); color: var(--n-text);
  padding-block: var(--n-sp-3);
}
.n-qa > summary::-webkit-details-marker { display: none; }
.n-qa > summary::after {
  content: ""; flex: none; inline-size: 11px; block-size: 11px;
  border-inline-end: 1.6px solid var(--n-text-dim);
  border-block-end: 1.6px solid var(--n-text-dim);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--n-dur-2) var(--n-ease-out);
}
.n-qa[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.n-qa > summary:focus-visible {
  outline: var(--n-focus-w) solid var(--n-focus); outline-offset: var(--n-focus-offset);
  border-radius: var(--n-r-xs);
}
.n-qa__body { padding-block-start: var(--n-sp-5); max-inline-size: 68ch; }
.n-qa__body > * { margin: 0; color: var(--n-text-muted); }

/* -- 24.8 · les trois mouvements de la page vie privee ------------------- */
.n-flow3 {
  display: grid; gap: var(--n-sp-7);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.n-index {
  font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
  letter-spacing: var(--n-ls-caps); color: var(--n-text-dim);
  margin-inline-end: var(--n-sp-5);
}
.n-flow > li { padding-block: var(--n-sp-5); border-block-end: 1px solid var(--n-line); }
.n-flow > li:last-child { border-block-end: 0; }

/* -- 24.9 · le pied de page des sous-pages ------------------------------ */
.n-brandcol { display: flex; flex-direction: column; gap: var(--n-sp-6); }
.n-footer__legal {
  margin: 0; font-size: var(--n-fs-xs); color: var(--n-text-dim); max-inline-size: 62ch;
}

/* -- 24.10 · le reste des utilitaires reclames par le HTML -------------- */
.n-nav__spacer { flex: 1 1 auto; }
@media (max-width: 899.98px) { .n-only\@md { display: none !important; } }
.n-measure-16{max-inline-size:16ch} .n-measure-22{max-inline-size:22ch}
.n-measure-76{max-inline-size:76ch}
.n-my-6-5{margin-block:var(--n-sp-6) var(--n-sp-5)}
.n-my-6-6{margin-block:var(--n-sp-6) var(--n-sp-6)}

/* ==========================================================================
   == 25 · LE TUNNEL DE CREATION (create.html) ==============================

   Trois ecrans, aucun compte, aucune carte, aucun paiement. Le tunnel
   s'arrete AVANT /app : il choisit un produit et un palier, puis il remet.

   LA PIECE CENTRALE DE LA CONSTRUCTION, et il faut la comprendre avant de
   toucher une ligne : le noeud <video> de la scene ne change JAMAIS de
   parent. C'est `.n-carry` qui change de forme d'un acte a l'autre, en CSS.
   Reparenter un <video> en lecture le recharge sur Safari — on perdrait la
   lecture, le decodeur et la position a chaque changement d'ecran.

   CE QUI A ETE MESURE, PAS SUPPOSE (charte NOIRE, formule WCAG 2.1) :
     encre sur --n-bg #0B0B0F ......... text 17,51 · muted 9,41 · faint 7,03
                                        dim 6,04 · line-strong 6,05
     encre sur --n-surface-1 #141420 .. text 16,26 · muted 8,75 · faint 6,53
                                        dim 5,61 · line-strong 5,62
     encre sur --n-surface-4 #2C2C40 .. dim 4,19 ✗ — LE SEUL ECHEC DU SYSTEME
     lumiere rasante, pire arret ...... text 12,91 · muted 6,94 · faint 5,18
                                        dim 4,45 ✗
     pastille blanche a 0,90 sur un
     cadre NOIR (le pire) ............. encre #33333B a 10,03
     aplats de la rampe sombre ........ encre #0B0B0F a 8,74 / 9,82 / 7,49
                                        (le BLANC y tomberait a 2,00 — voir §03)

   DEUX REGLES DE SYSTEME QUI EN DECOULENT, et qui manquaient au fichier :
     1. --n-text-dim est interdit sur --n-surface-4 (4,19) et sur la lumiere
        rasante (4,45). Le plancher y est --n-text-faint.
     2. La rampe --n-grad ne porte JAMAIS de texte. Elle est un filet de
        1,5 px, un lisere de 2 px, des traits de jauge et six rectangles.
        Quand un aplat de rampe doit porter du texte, c'est --n-grad-ink et
        l'encre est --n-text-on-accent, qui vaut #0B0B0F sur la charte noire.
   ========================================================================== */

/* -- 25.1 · LA COQUE ET LES ACTES --------------------------------------- */

.n-act {
  contain: layout paint;
  padding-block: var(--n-sp-11) var(--n-sp-12);
}
/* ⚠️ OBLIGATOIRE. Sans cette regle, un display:grid pose plus bas ecrase
   l'attribut hidden et les trois actes s'empilent. Le piege est deja paye
   dans ce fichier par .n-tile[hidden]. */
.n-act[hidden] { display: none !important; }

@media (max-width: 719.98px) {
  .n-act { padding-block-end: 108px; }   /* la reglette collante */
  #start.n-act { padding-block-end: 84px; }
}

/* La coupe entre actes : 90 ms de sortie, 180 ms d'entree. Aucune
   translation — c'est une coupe avec trois images de fondu, pas un
   glissement de diapositive. */
.n-act[data-phase="out"] { animation: n-cut-out 90ms var(--n-ease-in) both; }
.n-act[data-phase="in"]  { animation: n-cut-in 180ms var(--n-ease-out) both; }

/* Le pose des quatre groupes. 10 px, et non les 26 px de n-rise : un tunnel
   n'est pas un heros, le mouvement est un pose, pas une entree. */
.n-cut { animation: n-settle 220ms var(--n-ease-emph) both; }
.n-cut[data-delay="1"] { animation-delay: 45ms; }
.n-cut[data-delay="2"] { animation-delay: 90ms; }
.n-cut[data-delay="3"] { animation-delay: 135ms; }
.no-js .n-cut { animation: none; }

.n-room { display: grid; gap: var(--n-sp-8); align-items: start; }
@media (min-width: 1080px) {
  .n-room[data-act="1"] { grid-template-columns: minmax(0,1.02fr) minmax(440px,.98fr);
                          gap: clamp(2.5rem, 4vw, 4.5rem); }
  .n-room[data-act="3"] { grid-template-columns: minmax(0,.82fr) minmax(0,1.18fr);
                          gap: clamp(2.5rem, 4vw, 4.5rem); }
}
.n-room[data-act="2"] { grid-template-columns: 1fr; }
.n-cards { min-inline-size: 0; }

/* -- 25.2 · LE RAIL, LE FIL, LE BANDEAU DE SIMULATION -------------------- */

/* Le cadran d'instrument. Il ne compte pas des etapes, il AFFICHE des
   valeurs : « le vert est un verdict » applique a un tunnel — la couleur
   arrive quand la valeur est posee, jamais pour dire « champ rempli ». */
.n-rail {
  position: sticky; inset-block-start: var(--n-header-h);
  z-index: var(--n-z-sticky);
  /* OPAQUE : il chevauche du contenu qui defile. Un fond translucide y
     donnerait de la bouillie. */
  background: var(--n-bg);
  border-block-end: 1px solid var(--n-line);
}
.n-rail__inner {
  block-size: 56px; display: grid; align-items: stretch;
  grid-template-columns: repeat(3, minmax(0,1fr));
}
@media (min-width: 1024px) {
  .n-rail__inner { grid-template-columns: repeat(3, minmax(0,180px)) 1fr; }
}
.n-rail__cell {
  display: grid; align-content: center; gap: 2px;
  padding-inline: 14px; text-align: start;
  border-inline-start: 1px solid var(--n-line-2);
  position: relative; min-inline-size: 0;
}
.n-rail__cell:first-child { border-inline-start: 0; padding-inline-start: 0; }
button.n-rail__cell { cursor: pointer; background: none; border-block: 0; border-inline-end: 0; }
button.n-rail__cell:hover .n-rail__value { color: var(--n-accent); }
.n-rail__label {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-dim);            /* 6,04:1 sur --n-bg */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.n-rail__value {
  font-size: 13px; font-weight: var(--n-fw-medium); color: var(--n-text);
  font-variant-numeric: tabular-nums; line-height: 1.2;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: opacity 90ms var(--n-ease-in), transform 90ms var(--n-ease-in);
}
.n-rail__value[data-empty="true"] { color: var(--n-text-dim); }
.n-rail__value[data-flip="out"] { opacity: 0; transform: translate3d(0,3px,0); }
.n-rail__value[data-flip="in"]  { animation: n-flipin 90ms var(--n-ease-out) both; }
/* Le filet de 2 px sous la cellule : il s'allume quand la valeur est posee. */
.n-rail__mark {
  position: absolute; inset-block-end: 0; inset-inline: 14px 0;
  block-size: 2px; background: var(--n-line-2);
  transition: background-color var(--n-dur-1) var(--n-ease-out);
}
.n-rail__cell:first-child .n-rail__mark { inset-inline-start: 0; }
.n-rail__cell[data-set="true"] .n-rail__mark { background: var(--n-accent); }
.n-rail__tol { display: none; }
@media (min-width: 1024px) {
  .n-rail__tol { display: grid; align-content: center; justify-items: end;
                 padding-inline-start: 14px; }
}
/* Sous 420 px, trois cellules ne tiennent pas dans la largeur, et un
   debordement de 14 px elargit le viewport et rapetisse TOUTE la page :
   piege deja paye. La cellule PLAN se retire tant qu'elle est vide. */
@media (max-width: 419.98px) {
  .n-rail__cell[data-set="false"][data-cell="plan"] { display: none; }
  .n-rail__inner { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

.n-tol {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-dim); margin: 0;
}

/* Le fil de progression. On anime transform, jamais width : une largeur
   animee ne passe pas par le compositeur. */
.n-run { block-size: 2px; background: var(--n-surface-3); overflow: hidden; }
.n-run__fill {
  block-size: 100%; inline-size: 100%;
  background-image: var(--n-grad-ink);
  transform: scaleX(var(--n-run, .333)); transform-origin: left center;
  transition: transform 420ms var(--n-ease-out) 120ms;
}
.n-run[data-back="true"] .n-run__fill { transition: transform 260ms var(--n-ease-in); }

/* Le bandeau de simulation. Naît hidden, ne s'allume que si l'API dit
   simulated:true. Non refermable — on ne cache pas a un client qu'il
   regarde une chaine qui ne fabrique rien. */
.n-sim {
  display: grid; place-items: center; min-block-size: 36px;
  margin-block-start: var(--n-sp-6);
  padding: 6px var(--n-sp-6); text-align: center;
  border: 1px dashed var(--n-warn); border-radius: var(--n-r-sm);
  background: var(--n-warn-soft); color: var(--n-warn);   /* 8,69:1 mesure */
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
}

/* -- 25.3 · LA SCENE ET SON REPORT --------------------------------------- */

.n-carry { min-inline-size: 0; }
@media (min-width: 1080px) {
  .n-carry[data-act="1"] {
    position: sticky;
    inset-block-start: calc(var(--n-header-h) + 58px + 24px);
  }
}
/* Acte 2 : la scene se REDUIT, elle ne se voile pas. Un voile sur un rendu
   en studio clair vire au gris laiteux et se lit comme une opacite cassee ;
   une vignette nette et petite garde la preuve presente au moment exact ou
   l'on demande le chiffre. */
.n-carry[data-act="2"] {
  display: flex; align-items: center; gap: var(--n-sp-6);
  min-block-size: 72px; padding: 8px 12px 8px 8px;
  background: var(--n-surface-1); border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-xl); position: static;
}
.n-carry[data-act="3"] { display: block; }

.n-stage {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 9;
  background: var(--n-well);
  border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-2xl);
  box-shadow: var(--n-shadow-4);
}
@media (min-width: 700px) { .n-stage { border-radius: var(--n-r-3xl); } }
.n-stage > img,
.n-stage > video {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%; object-fit: cover;
}
.n-stage > video {
  opacity: 0; transition: opacity var(--n-dur-3) var(--n-ease-out);
}
.n-stage[data-playing="true"] > video { opacity: 1; }

/* Acte 2 : 96 px de large. Ses legendes, ses equerres et son bouton
   disparaissent — un cartouche de 96x54 n'a pas de place pour une legende. */
.n-stage[data-act="2"] {
  inline-size: 96px; max-inline-size: 96px; flex: none;
  border-radius: var(--n-r-sm); box-shadow: none;
}
.n-stage[data-act="2"] .n-panel__cap,
.n-stage[data-act="2"] .n-panel__marks,
.n-stage[data-act="2"] .n-panel__play { display: none; }
.n-stage[data-act="3"] { max-inline-size: 420px; border-radius: var(--n-r-2xl);
                         box-shadow: var(--n-shadow-3); }
.n-stage[data-act="3"] .n-panel__play { display: none; }

.n-carry__name { font-size: var(--n-fs-md); font-weight: var(--n-fw-medium);
                 color: var(--n-text); }
.n-carry__state {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-carry__act { margin-inline-start: auto; }

/* -- 25.4 · LA CARTE PRODUIT --------------------------------------------- */

.n-picks { border: 0; margin: 0; padding: 0; }
.n-pick { position: relative; display: block; }
.n-pick input {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  margin: 0; opacity: 0; cursor: pointer;
  /* jamais display:none : l'element sortirait de la tabulation et du
     lecteur d'ecran */
}
.n-pick__face {
  position: relative; z-index: 1;
  padding: var(--n-sp-7);
  background: var(--n-surface-1);
  border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-2xl);
  box-shadow: var(--n-shadow-1);
  transition: border-color var(--n-dur-1) var(--n-ease-out),
              box-shadow var(--n-dur-2) var(--n-ease-out),
              background-color var(--n-dur-1) var(--n-ease-out),
              transform var(--n-dur-2) var(--n-ease-out);
}
/* L'ECLAIRAGE RASANT — la piece signature. Le degrade de marque n'est
   jamais un aplat : il eclaire par en dessous. Mesure sur la charte noire :
   le pire arret compose #3A222F, ou --n-text tient 12,91 et --n-text-muted
   6,94. --n-text-dim y tombe a 4,45 : INTERDIT sur cette surface. */
.n-pick__face::before {
  content: ""; position: absolute; inset: -1px; z-index: -1;
  border-radius: inherit; opacity: 0;
  background: linear-gradient(115deg, rgba(255,110,127,.16) 0%,
                                      rgba(197,139,242,.10) 52%,
                                      rgba(122,108,240,.16) 100%);
  transition: opacity var(--n-dur-3) var(--n-ease-out);
}
.n-pick input:checked + .n-pick__face {
  border-color: var(--n-accent);
  box-shadow: inset 0 0 0 1px var(--n-accent), var(--n-shadow-3);
  background: var(--n-accent-veil);
}
.n-pick input:checked + .n-pick__face::before { opacity: 1; }
.n-pick input:focus-visible + .n-pick__face {
  outline: var(--n-focus-w) solid var(--n-focus);
  outline-offset: var(--n-focus-offset);
}
@media (hover: hover) and (pointer: fine) {
  .n-pick:hover .n-pick__face { border-color: var(--n-line-accent);
                                box-shadow: var(--n-shadow-4);
                                transform: translateY(-3px); }
}
.n-pick input:active + .n-pick__face { transform: translateY(0);
                                       box-shadow: var(--n-shadow-2); }

.n-pick__band {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 9; border-radius: var(--n-r-lg);
  background: var(--n-well);
}
.n-pick__band img { inline-size: 100%; block-size: 100%; object-fit: cover; }
.n-pick__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-6); margin-block-start: var(--n-sp-7);
}
.n-pick__name {
  display: inline-flex; align-items: center; gap: var(--n-sp-5);
  font-size: var(--n-fs-2xl); font-weight: var(--n-fw-medium);
  letter-spacing: var(--n-ls-h3); color: var(--n-text);
}
.n-pick__tick {
  inline-size: 18px; block-size: 18px; flex: none;
  border-radius: 50%; background-image: var(--n-grad-ink);
  display: grid; place-items: center;
  transform: scale(.7); opacity: 0;
  transition: transform var(--n-dur-2) var(--n-ease-emph),
              opacity var(--n-dur-2) var(--n-ease-emph);
}
.n-pick input:checked + .n-pick__face .n-pick__tick { transform: scale(1); opacity: 1; }
.n-pick__tick svg { inline-size: 10px; block-size: 10px;
                    color: var(--n-text-on-accent); }
.n-pick__help {
  margin-block-start: var(--n-sp-5); max-inline-size: 44ch;
  font-size: var(--n-fs-sm); line-height: 1.6; color: var(--n-text-muted);
}

/* La puce d'etat. Le MOT porte l'etat, jamais la couleur seule, et le point
   est FIXE : six pixels qui clignotent en boucle sans qu'on ait rien touche
   sont exactement ce que la maison refuse. */
.n-chip {
  display: inline-flex; align-items: center; gap: var(--n-sp-4); flex: none;
  padding: 4px 9px; border-radius: var(--n-r-pill);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
}
.n-chip::before { content: ""; inline-size: 6px; block-size: 6px;
                  border-radius: 50%; background: currentColor; }
.n-chip--live { color: var(--n-ok); background: var(--n-ok-soft);
                border: 1px solid rgba(78,211,150,.28); }   /* 8,25:1 mesure */
.n-chip--soon { color: var(--n-text-faint); background: var(--n-surface-2);
                border: 1px solid var(--n-line-2); }

/* -- 25.5 · LES TROIS PRODUITS EN DEVELOPPEMENT -------------------------- */

/* Ce ne sont PAS des radios desactivees : une radio disabled sort de l'ordre
   de tabulation et disparait du lecteur d'ecran — on afficherait trois
   dechets muets. Ce sont des elements de liste, hors du radiogroup. */
.n-soonhead {
  display: flex; align-items: center; gap: var(--n-sp-6);
  margin-block-start: var(--n-sp-9);
}
.n-soonhead::before, .n-soonhead::after {
  content: ""; flex: 1; block-size: 1px; background: var(--n-line);
}
.n-soonhead span {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint); text-align: center;
}
.n-soon {
  list-style: none; margin-block-start: var(--n-sp-7);
  display: grid; gap: var(--n-sp-6); grid-template-columns: 1fr;
}
@media (min-width: 560px) { .n-soon { grid-template-columns: repeat(3, minmax(0,1fr)); } }
.n-soon > li { min-inline-size: 0; }
.n-soon__screen {
  position: relative; overflow: hidden;
  block-size: 72px; border-radius: var(--n-r-lg);
  background: var(--n-surface-2);
  border: 1px solid var(--n-line-2);
  display: grid; place-items: center; gap: 10px; align-content: center;
  transition: border-color var(--n-dur-1) var(--n-ease-out);
  cursor: default;
}
@media (min-width: 560px) { .n-soon__screen { block-size: 96px; } }
.n-soon > li:hover .n-soon__screen { border-color: var(--n-line-3); }
/* La trame technique, plus UNE passe de lumiere rasante. Rien d'anime. */
.n-soon__screen::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right,  var(--n-line-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--n-line-grid) 1px, transparent 1px);
  background-size: 32px 32px;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 50%, #000 20%, transparent 100%);
          mask-image: radial-gradient(120% 90% at 50% 50%, #000 20%, transparent 100%);
}
.n-soon__screen::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 0%,
                                      rgba(197,139,242,.14) 46%,
                                      transparent 78%);
}
/* ⚠️ --n-line-strong A PLEINE OPACITE, jamais --n-accent-lo a opacity .55 :
   ce trait est le SEUL element qui distingue une sandale d'un t-shirt, c'est
   donc un graphique porteur d'information (WCAG 1.4.11, minimum 3:1).
   Mesure sur la charte noire : --n-line-strong sur --n-surface-2 = 5,29:1. */
.n-soon__glyph {
  position: relative; z-index: 1;
  inline-size: 32px; block-size: 32px;
  fill: none; stroke: var(--n-line-strong); stroke-width: 1.25;
  stroke-linecap: round; stroke-linejoin: round;
}
@media (min-width: 560px) { .n-soon__glyph { inline-size: 40px; block-size: 40px; } }
/* Le trace plat : le canal vivant a une image qui bouge, les canaux dormants
   ont une ligne plate. Personne n'a besoin d'explication. */
.n-soon__trace { position: relative; z-index: 1; inline-size: 44px; block-size: 10px;
                 stroke: var(--n-line-strong); stroke-width: 1; fill: none; }
.n-soon__name {
  margin-block-start: var(--n-sp-5);
  font-size: var(--n-fs-sm); font-weight: var(--n-fw-medium); color: var(--n-text);
}
.n-soon__status {
  margin-block-start: 2px;
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);   /* 7,03:1 — jamais --n-text-disabled : c'est
                                   une etiquette, pas un element desactive */
}

/* La prise pour le visiteur venu pour le mauvais produit. Trois types sur
   quatre sont fermes : sans elle, cette part du trafic repart sans rien. */
.n-waitlist {
  margin-block-start: var(--n-sp-7); padding-block-start: var(--n-sp-7);
  border-block-start: 1px solid var(--n-line);
}
.n-waitlist__row {
  display: flex; flex-wrap: wrap; gap: var(--n-sp-4); align-items: flex-end;
  margin-block-start: var(--n-sp-5);
}
.n-waitlist__row .n-select { flex: 0 1 160px; }
.n-waitlist__row .n-input  { flex: 1 1 220px; }
@media (max-width: 559.98px) {
  .n-waitlist__row { flex-direction: column; align-items: stretch; }
  .n-waitlist__row > * { inline-size: 100%; }
}

/* -- 25.6 · LA CHAINE DE FABRICATION ------------------------------------- */

.n-chain { margin-block-start: var(--n-sp-12); }
.n-chain__row {
  display: grid; gap: var(--n-sp-5); align-items: center;
  grid-template-columns: 1fr; margin-block-start: var(--n-sp-7);
}
@media (min-width: 720px) {
  .n-chain__row { grid-template-columns: 1fr 24px 1fr 24px 1fr; }
}
.n-chain__arrow {
  display: grid; place-items: center;
  font-family: var(--n-font-mono); font-size: var(--n-fs-lg);
  color: var(--n-text-faint);
}
.n-chain__cell { min-inline-size: 0; }
.n-chain__frame {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 9; border-radius: var(--n-r-xl);
  background: var(--n-surface-2); border: 1px solid var(--n-line-2);
}
.n-chain__frame > img, .n-chain__frame > video {
  inline-size: 100%; block-size: 100%; object-fit: cover;
}
.n-chain__frame > video { position: absolute; inset: 0; opacity: 0;
                          transition: opacity var(--n-dur-3) var(--n-ease-out); }
.n-chain__frame[data-playing="true"] > video { opacity: 1; }
/* Le schema de la premiere dalle : pas de photo client, on n'en a pas. */
.n-chain__schema {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right,  var(--n-line-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--n-line-grid) 1px, transparent 1px);
  background-size: 32px 32px;
  display: grid; place-items: center;
}
.n-chain__schema svg { inline-size: 44px; block-size: 44px; fill: none;
                       stroke: var(--n-line-strong); stroke-width: 1.25; }
.n-chain__cap {
  margin-block-start: var(--n-sp-5);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-chain__cap b { display: block; color: var(--n-text);
                  font-weight: var(--n-fw-medium); margin-block-end: 3px; }
/* Les quatre equerres de repere, a l'encre claire sur la charte noire. */
.n-marks { position: absolute; inset: 12px; pointer-events: none; }
.n-marks span {
  position: absolute; inline-size: 12px; block-size: 12px;
  border: 0 solid rgba(242,241,248,.34);
}
.n-marks span:nth-child(1){inset-block-start:0;inset-inline-start:0;border-block-start-width:1.5px;border-inline-start-width:1.5px}
.n-marks span:nth-child(2){inset-block-start:0;inset-inline-end:0;border-block-start-width:1.5px;border-inline-end-width:1.5px}
.n-marks span:nth-child(3){inset-block-end:0;inset-inline-start:0;border-block-end-width:1.5px;border-inline-start-width:1.5px}
.n-marks span:nth-child(4){inset-block-end:0;inset-inline-end:0;border-block-end-width:1.5px;border-inline-end-width:1.5px}

/* -- 25.7 · L'ECRAN DES PALIERS ------------------------------------------ */

/* La barre des constantes. Dite UNE fois, la constance devient une decision ;
   repetee sur quatre cartes, elle devient un aveu — et elle pousse a inventer
   une difference qui n'existe pas. */
.n-constants {
  margin-block-start: var(--n-sp-9);
  border-block: 1px solid var(--n-line-2);
  padding-block: 14px;
  display: grid; gap: var(--n-sp-5);
  grid-template-columns: repeat(2, minmax(0,1fr));
}
@media (min-width: 768px) {
  .n-constants { grid-template-columns: auto repeat(4, minmax(0,1fr)); gap: 0; }
}
.n-constants__label {
  grid-column: 1 / -1;
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint); align-self: center;
}
@media (min-width: 768px) {
  .n-constants__label { grid-column: auto; padding-inline-end: var(--n-sp-8); }
}
.n-constants__read { min-inline-size: 0; }
@media (min-width: 768px) {
  .n-constants__read { border-inline-start: 1px solid var(--n-line-2);
                       padding-inline: var(--n-sp-7); }
}
.n-constants__read dt {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-constants__read dd {
  margin: 2px 0 0; font-family: var(--n-font-mono); font-size: var(--n-fs-sm);
  font-weight: var(--n-fw-medium); color: var(--n-text);
  font-variant-numeric: tabular-nums;
}

/* L'alignement des quatre prix sur une meme ligne de base : c'est ce qui
   fait la classe de l'ecran, et ca se fait en subgrid, pas en enceinte
   soudee (filets partages, rayons coin par coin, z-index : trop fragile). */
@media (min-width: 1080px) {
  .n-act .n-plans { grid-template-rows: repeat(6, auto); }
  .n-act .n-plans > * { grid-row: span 6; display: grid;
                        grid-template-rows: subgrid; }
}
@supports not (grid-template-rows: subgrid) {
  .n-act .n-plans > * { display: flex; flex-direction: column; }
  .n-act .n-card-plan__flagzone { min-block-size: 26px; }
  .n-act .n-card-plan__name     { min-block-size: 28px; }
  .n-act .n-card-plan__price    { min-block-size: 84px; }
  .n-act .n-gauge               { min-block-size: 64px; }
  .n-act .n-card-plan__pitch    { min-block-size: 76px; }
  .n-act .n-card-plan__cta      { min-block-size: 60px; }
}
/* Les 80 px du haut degagent le drapeau absolu : sans eux la colonne vedette
   pousse et les quatre prix cessent d'etre alignes. */
.n-act .n-card-plan { padding: 80px var(--n-sp-9) var(--n-sp-9); }
.n-card-plan__flagzone { min-block-size: 0; }

/* LE PRIX EN TYPOGRAPHIE DE CATALOGUE. Le chiffre porte, le symbole
   accompagne. Surcharge LOCALE au tunnel : la landing garde son echelle. */
.n-act .n-card-plan__amount {
  font-size: var(--n-fs-5xl); letter-spacing: -0.045em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.n-card-plan__cur { font-size: .42em; vertical-align: .34em;
                    color: var(--n-text-faint); }
.n-act .n-card-plan__price { align-items: baseline; }
/* Une regle horizontale, et une seule. La retenue est ce qui fait la classe ;
   toute decoration supplementaire la mange. C'est un <span> et pas un <hr> :
   un <label> n'accepte que du contenu de phrase, et un <hr> y est invalide. */
.n-act .n-card-plan__rule { display: block; block-size: 1px;
                            background: var(--n-line);
                            margin-block-start: var(--n-sp-7); border: 0; }

/* LA JAUGE A TRAITS. Elle remplace la barre de quota : une barre remplie a
   25 % sur Starter dit « vous avez le quart de quelque chose », c'est faux,
   et le jour ou Growth passe de 10 a 12 videos le chiffre bouge et la barre
   ne bouge pas — un mensonge qu'on ne voit jamais avant la production.
   Les variables sont LOCALES au composant : aucune valeur de quota n'entre
   dans :root, et aucune n'est ecrite en dur dans ce fichier. */
.n-gauge {
  --n-videos: 5;
  --n-step: calc(100% / var(--n-videos));
  --n-step5: calc(100% / (var(--n-videos) / 5));
  --n-tick-hi: var(--n-line-strong);
  margin-block: var(--n-sp-7);
}
.n-gauge__count {
  font-family: var(--n-font-mono); font-size: var(--n-fs-sm);
  font-weight: var(--n-fw-medium); color: var(--n-text);
  font-variant-numeric: tabular-nums;
}
.n-gauge__scale {
  margin-block-start: var(--n-sp-4);
  block-size: 14px;
  background-image:
    repeating-linear-gradient(90deg, var(--n-tick-hi) 0 1px, transparent 1px var(--n-step5)),
    repeating-linear-gradient(90deg, var(--n-line-strong) 0 1px, transparent 1px var(--n-step));
  background-size: 100% 14px, 100% 8px;
  background-position: left bottom, left bottom;
  background-repeat: no-repeat;
  transition: background-image var(--n-dur-1) var(--n-ease-out);
}
/* Business : l'echelle sort du cadre. « 50+ » se voit avant de se lire. */
.n-gauge--open .n-gauge__scale {
  -webkit-mask-image: linear-gradient(90deg, #000 62%, transparent 100%);
          mask-image: linear-gradient(90deg, #000 62%, transparent 100%);
}
/* Sans JS, --n-videos n'est jamais corrigee depuis l'API : une echelle dont
   le pas ne correspond a rien est un decor faux. La ligne de compte reste. */
.no-js .n-gauge__scale { display: none; }

/* LE FIL DE METAL de la carte vedette. La rampe de marque devient un filet
   de 1,5 px et ne porte AUCUN texte : aucun probleme de contraste, et ca
   ressemble a un objet manufacture. */
.n-card-plan--thread {
  border: 1.5px solid transparent;
  background-image: linear-gradient(var(--n-surface-1), var(--n-surface-1)),
                    var(--n-grad);
  background-origin: border-box;
  background-clip: padding-box, border-box;
}
/* Vedette n'est PAS selectionne, et ca doit se voir : un client doit pouvoir
   choisir Starter sans croire que Growth reste coche. Sur la carte vedette
   l'anneau interne passe a 2 px pour se lire par-dessus le fil. */
.n-act .n-plans input { position: absolute; inset: 0; inline-size: 100%;
                        block-size: 100%; margin: 0; opacity: 0; cursor: pointer; }
.n-act .n-plans label { position: relative; }
.n-act .n-plans input:checked + .n-card-plan__body,
.n-act .n-plans label:has(input:checked) {
  background: var(--n-accent-veil);
  box-shadow: inset 0 0 0 1px var(--n-accent), var(--n-shadow-3);
}
.n-act .n-plans label:has(input:checked):not(.n-card-plan--thread) {
  border-color: var(--n-accent);
}
.n-act .n-plans label.n-card-plan--thread:has(input:checked) {
  box-shadow: inset 0 0 0 2px var(--n-accent), var(--n-shadow-3);
}
.n-act .n-plans input:focus-visible ~ .n-card-plan__focus,
.n-act .n-plans label:has(input:focus-visible) {
  outline: var(--n-focus-w) solid var(--n-focus);
  outline-offset: var(--n-focus-offset);
}
@media (hover: hover) and (pointer: fine) {
  .n-act .n-plans > *:hover { border-color: var(--n-line-accent);
                              box-shadow: var(--n-shadow-4);
                              transform: translateY(-4px); }
}
.n-act .n-plans > * { transition: transform var(--n-dur-2) var(--n-ease-out),
                                  border-color var(--n-dur-1) var(--n-ease-out),
                                  box-shadow var(--n-dur-2) var(--n-ease-out),
                                  background-color var(--n-dur-1) var(--n-ease-out); }
.n-act .n-plans label:has(input:checked) .n-gauge { --n-tick-hi: var(--n-accent); }

/* Le pied : l'anneau se remplit, le libelle passe de Select a Selected. */
.n-choose { display: inline-flex; align-items: center; gap: var(--n-sp-5);
            min-block-size: 40px; }
.n-choose__ring {
  inline-size: 20px; block-size: 20px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--n-line-strong);
  display: grid; place-items: center;
  transition: border-color var(--n-dur-1) var(--n-ease-out);
}
.n-choose__ring svg { inline-size: 10px; block-size: 10px; opacity: 0;
                      color: var(--n-text-on-accent);
                      transform: scale(.7);
                      transition: opacity var(--n-dur-2) var(--n-ease-emph),
                                  transform var(--n-dur-2) var(--n-ease-emph); }
.n-choose__label { font-size: var(--n-fs-xs); color: var(--n-text-muted); }
.n-choose__label b { display: none; font-weight: var(--n-fw-normal); }
label:has(input:checked) .n-choose__ring { border-color: transparent;
                                           background-image: var(--n-grad-ink); }
label:has(input:checked) .n-choose__ring svg { opacity: 1; transform: scale(1); }
label:has(input:checked) .n-choose__label i { display: none; }
label:has(input:checked) .n-choose__label b { display: inline; }

/* L'anneau de rappel « rien n'est choisi ». Pas de secousse : une secousse
   est une punition, un anneau est une indication. */
.n-plans { position: relative; }
.n-plans[data-ring="true"]::after {
  content: ""; position: absolute; inset: -10px; pointer-events: none;
  border: 2px solid var(--n-accent); border-radius: var(--n-r-3xl);
  animation: n-ring 400ms var(--n-ease-out) 1 both;
}

.n-fineprint { margin-block-start: var(--n-sp-8); max-inline-size: 78ch;
               display: flex; flex-direction: column; gap: var(--n-sp-4); }
.n-fineprint p { font-size: var(--n-fs-xs); color: var(--n-text-dim);
                 line-height: 1.6; margin: 0; }

/* -- 25.8 · LA PLAQUE ET LA REMISE --------------------------------------- */

.n-plate {
  position: relative; margin-block-start: var(--n-sp-8);
  padding: var(--n-sp-8);
  background: var(--n-surface-1); border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-2xl); box-shadow: var(--n-shadow-3);
}
/* Le lisere de 2 px : la plaque herite visuellement du choix, comme le fil
   de metal de la carte vedette. */
.n-plate::before {
  content: ""; position: absolute;
  inset-block-start: -1px; inset-inline: -1px;
  block-size: 2px; background-image: var(--n-grad);
  border-radius: var(--n-r-2xl) var(--n-r-2xl) 0 0;
}
.n-plate__head {
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
  padding-block-end: var(--n-sp-5);
  border-block-end: 1px solid var(--n-line-2);
}
.n-spec__change {
  font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
  color: var(--n-accent); text-decoration: underline;
  text-decoration-thickness: 1px; text-underline-offset: .25em;
  min-block-size: 44px; display: inline-flex; align-items: center;
  margin-inline-start: auto;
}
.n-spec__change:hover { color: var(--n-accent-hi); }
.n-spec__value--row { display: flex; align-items: center; gap: var(--n-sp-6);
                      flex-wrap: wrap; }

/* Les six rectangles, aux VRAIES proportions. --n-ar est posee en CSSOM :
   aucune proportion n'est ecrite en dur, ni ici ni dans le HTML. */
.n-formats--mini { display: flex; align-items: flex-end; gap: var(--n-sp-4);
                   flex-wrap: wrap; }
.n-formats--mini i {
  display: block; block-size: 18px; aspect-ratio: var(--n-ar, 16 / 9);
  border: 1px solid var(--n-line-3); border-radius: 3px;
  background-image: var(--n-grad); opacity: .9;
}

.n-next { list-style: none; margin-block-start: var(--n-sp-9); }
.n-next > li {
  display: grid; grid-template-columns: 34px minmax(0,1fr);
  gap: var(--n-sp-6); padding-block: 18px;
  border-block-start: 1px solid var(--n-line-2);
}
.n-next__num {
  font-family: var(--n-font-mono); font-size: var(--n-fs-xs);
  letter-spacing: var(--n-ls-wide);
  background-image: var(--n-grad-text);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.n-next__title { font-size: var(--n-fs-lg); font-weight: var(--n-fw-medium);
                 color: var(--n-text); }
.n-next__body { margin-block-start: var(--n-sp-4); max-inline-size: 52ch;
                font-size: var(--n-fs-sm); line-height: 1.6;
                color: var(--n-text-muted); }

.n-handoff { margin-block-start: var(--n-sp-9); }
.n-handoff__note { margin-block-start: var(--n-sp-5);
                   font-size: var(--n-fs-xs); color: var(--n-text-dim); }
.n-handoff__login { margin-block-start: var(--n-sp-7);
                    font-size: var(--n-fs-sm); color: var(--n-text-muted); }

/* -- 25.9 · LA REGLETTE DE COMMANDE -------------------------------------- */

.n-strip {
  margin-block-start: var(--n-sp-9); padding-block-start: var(--n-sp-8);
  border-block-start: 1px solid var(--n-line);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--n-sp-6); flex-wrap: wrap;
}
.n-strip__read {
  font-family: var(--n-font-mono); font-size: var(--n-fs-2xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-strip__pair { display: flex; align-items: center; gap: var(--n-sp-5);
                 margin-inline-start: auto; }
@media (max-width: 719.98px) {
  .n-strip {
    position: fixed; inset-inline: 0; inset-block-end: 0;
    z-index: var(--n-z-sticky);
    margin: 0; padding: 12px var(--n-sp-gutter)
                       calc(12px + env(safe-area-inset-bottom, 0px));
    background: var(--n-bg-overlay);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    border-block-start: 1px solid var(--n-line-2); border-block-end: 0;
    flex-direction: column; align-items: stretch; gap: var(--n-sp-5);
  }
  .n-strip__pair { margin-inline-start: 0; }
  .n-strip__pair .n-btn--primary { flex: 1; }
}

/* -- 25.10 · ANIMATIONS -------------------------------------------------- */

@keyframes n-cut-out { from { opacity: 1 } to { opacity: 0 } }
@keyframes n-cut-in  { from { opacity: 0 } to { opacity: 1 } }
@keyframes n-settle {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes n-flipin {
  from { opacity: 0; transform: translate3d(0, -3px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes n-ring {
  0%   { opacity: 0 }
  20%  { opacity: 1 }
  100% { opacity: 0 }
}

/* -- 25.11 · PREFERS-REDUCED-MOTION -------------------------------------
   Le reset global de la §22 ecrase les DUREES a .001ms, mais il ne
   neutralise pas les etats de DEPART : un opacity:0 initial resterait a 0
   et l'element ne s'afficherait jamais. Il faut donc les nommer.
   Ce qui reste : bordure, fond et ombre au survol. Ce sont des ETATS, pas
   du mouvement ; les retirer supprimerait l'affordance. */
@media (prefers-reduced-motion: reduce) {
  .n-act[data-phase="out"], .n-act[data-phase="in"],
  .n-cut { animation: none !important; opacity: 1 !important; transform: none !important; }
  .n-run__fill { transition: none !important; }
  .n-rail__value { transition: none !important; opacity: 1 !important;
                   transform: none !important; animation: none !important; }
  .n-rail__mark, .n-gauge__scale, .n-choose__ring,
  .n-choose__ring svg, .n-pick__face::before, .n-pick__tick,
  .n-stage > video { transition: none !important; }
  .n-pick__tick, .n-choose__ring svg { transform: none !important; }
  .n-plans[data-ring="true"]::after { animation: none !important; opacity: 1; }
  @media (hover: hover) and (pointer: fine) {
    .n-pick:hover .n-pick__face,
    .n-act .n-plans > *:hover { transform: none !important; }
  }
}

/* -- 25.12 · SANS JAVASCRIPT ---------------------------------------------
   La page degrade en une page longue et juste, pas en un ecran mort. On ne
   peut pas choisir, mais on peut TOUT lire. */
.no-js .n-act { display: block !important; }
.no-js .n-act + .n-act { border-block-start: 1px solid var(--n-line); }
.no-js .n-strip { position: static; }
.no-js .n-rail__cell { pointer-events: none; }


/* ==========================================================================
   == 26 · LA FORGE — le composeur pose dans le heros =======================

   Une carte, quatre etats : la prise de vue, le controle, le palier, le
   compte. Elle ne change jamais de place ni de largeur d'un etat a l'autre :
   c'est le CONTENU qui change, pas la boite. Une carte qui saute a chaque
   etape donne l'impression d'avoir change de page — et sur un heros, elle
   ferait sauter tout ce qui est en dessous (CLS).

   POURQUOI ELLE N'UTILISE PAS LA §25. Le tunnel de `create.html` est fait
   pour une PAGE : trois actes pleine largeur, une scene video qui ne se
   reparente jamais, une reglette collante. Ici on est dans 960 px poses sur
   un fond video, au-dessus de la ligne de flottaison. Les deux se
   ressemblent de loin et n'ont ni la meme contrainte de hauteur, ni la meme
   hierarchie. Les melanger aurait couple deux ecrans qui evoluent
   separement — et la §25 est ecrite par un autre lot.

   CONTRASTES MESURES (charte NOIRE, la carte est --n-surface-1 #141420) :
     text 16,26 · muted 8,75 · faint 6,53 · dim 5,61 · accent 8,04
   En clair la carte est #FFFFFF : text 19,64 · muted 7,37 · dim 4,82.
   Les deux tiennent AA partout ou du texte se pose. La zone de depot passe
   en --n-surface-2 : dim y tient encore 5,29 (sombre) et 4,58 (clair).
   ========================================================================== */

.n-forge {
  inline-size: 100%;
  max-inline-size: 980px;
  margin-block-start: var(--n-sp-10);
  padding: var(--n-sp-6);
  text-align: start;
  background: var(--n-surface-1);
  border: 1px solid var(--n-line-3);
  border-radius: var(--n-r-3xl);
  box-shadow: var(--n-shadow-4), var(--n-bevel);
}
/* Le filet de rampe sur l'arete haute. C'est le seul emploi de --n-grad
   autorise par la §25 : un trait de decor, jamais un fond qui porte du
   texte. Il donne a la carte la presence qu'une surface a peine plus claire
   que le fond video ne lui donnait pas — et il coute un pseudo-element,
   pas un backdrop-filter que le telephone paierait a chaque image. */
.n-forge::before {
  content: ""; position: absolute; inset-block-start: -1px;
  inset-inline: var(--n-sp-9); block-size: 2px;
  background-image: var(--n-grad); border-radius: var(--n-r-pill);
  opacity: .9;
}
.n-forge { position: relative; }
@media (min-width: 720px) { .n-forge { padding: var(--n-sp-7); } }

/* -- 26.1 · LE FIL DES QUATRE ETAPES ------------------------------------
   Il ne se clique pas : sauter au palier sans avoir de photo n'aurait pas
   de sens, et un repere cliquable qui refuse le clic est pire qu'un repere
   qui n'en promet aucun. */
.n-forge__rail {
  display: flex; align-items: center; gap: var(--n-sp-4);
  margin: 0 0 var(--n-sp-6); padding: 0; list-style: none;
}
.n-forge__step {
  display: flex; align-items: center; gap: var(--n-sp-4);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-caps); text-transform: uppercase;
  color: var(--n-text-faint);
}
.n-forge__step::before {
  content: ""; inline-size: 7px; block-size: 7px; border-radius: 50%;
  background: var(--n-line-3);
  transition: background-color var(--n-dur-2) var(--n-ease-out);
}
.n-forge__step + .n-forge__step { margin-inline-start: var(--n-sp-4); }
.n-forge__step + .n-forge__step::after { content: none; }
/* le trait de liaison, pose AVANT la pastille de la suivante */
.n-forge__step + .n-forge__step { position: relative; padding-inline-start: var(--n-sp-6); }
.n-forge__step + .n-forge__step > span { position: relative; }
.n-forge__step[data-state="done"] { color: var(--n-text-muted); }
.n-forge__step[data-state="done"]::before { background: var(--n-accent); }
.n-forge__step[data-state="now"] { color: var(--n-text); }
.n-forge__step[data-state="now"]::before {
  background: var(--n-accent); box-shadow: 0 0 0 3px var(--n-accent-soft);
}
/* Sous 560 px le fil ne garde que l'etape courante : quatre libelles en
   mono sur 320 px, c'est deux lignes de bruit avant le premier champ. */
@media (max-width: 559.98px) {
  .n-forge__step > span { display: none; }
  .n-forge__step[data-state="now"] > span { display: inline; }
  .n-forge__step + .n-forge__step { padding-inline-start: 0; }
}

/* -- 26.2 · L'ETAT « PRISE DE VUE » -------------------------------------- */
.n-forge__panel[hidden] { display: none !important; }
.n-forge__panel--pad { padding-block: var(--n-sp-3) var(--n-sp-2); }

.n-forge__grid { display: grid; gap: var(--n-sp-6); align-items: end; }
@media (min-width: 900px) {
  .n-forge__grid {
    grid-template-columns: minmax(0, 1.45fr) minmax(0, .95fr) minmax(0, .95fr) auto;
    gap: var(--n-sp-5);
  }
}
.n-forge__field { gap: var(--n-sp-3); min-inline-size: 0; }

/* La zone de depot. L'input couvre toute la surface : le clic marche
   partout, le clavier l'atteint par tabulation, et `:focus-within` porte
   l'anneau — c'est le meme montage que .n-drop de l'application. */
.n-forge__drop {
  position: relative; display: flex; align-items: center;
  min-block-size: 76px; padding: var(--n-sp-5) var(--n-sp-6);
  background: var(--n-surface-2);
  border: 1px dashed var(--n-line-3); border-radius: var(--n-r-xl);
  transition: border-color var(--n-dur-2) var(--n-ease-out),
              background-color var(--n-dur-2) var(--n-ease-out);
}
.n-forge__file {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  opacity: 0; cursor: pointer;
}
.n-forge__drop:hover { border-color: var(--n-accent-lo); }
.n-forge__drop:focus-within {
  border-color: var(--n-accent); box-shadow: 0 0 0 3px var(--n-accent-soft);
}
.n-forge__drop[data-state="over"] {
  border-color: var(--n-accent); background: var(--n-accent-soft);
  border-style: solid;
}
.n-forge__drop[data-state="filled"] { border-style: solid; border-color: var(--n-line-2); }
.n-forge__drop[data-state="error"]  { border-color: var(--n-danger); }

/* ⚠️ OBLIGATOIRE, et le piege est deja paye deux fois dans ce fichier :
   un display: flex pose plus bas ECRASE l'attribut hidden, et les deux
   faces de la zone de depot s'affichent en meme temps — la vignette vide
   par-dessus l'invitation a deposer. */
.n-forge__dropface[hidden], .n-forge__shot[hidden] { display: none !important; }
.n-forge__dropface { display: flex; align-items: center; gap: var(--n-sp-6);
                     min-inline-size: 0; flex: 1 1 auto; }
.n-forge__dropicon { inline-size: 26px; block-size: 26px; flex: none; color: var(--n-text-faint); }
.n-forge__drop:hover .n-forge__dropicon,
.n-forge__drop[data-state="over"] .n-forge__dropicon { color: var(--n-accent); }
.n-forge__dropmain { display: block; font-size: var(--n-fs-sm); font-weight: var(--n-fw-medium);
                     color: var(--n-text); }
.n-forge__dropmain label { cursor: pointer; }
.n-forge__drophint { display: block; margin-block-start: 2px;
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); color: var(--n-text-dim); }

/* La photo posee. Le cadre prend LE FORMAT CHOISI : c'est la seule facon
   de montrer, avant de lancer, que le 9:16 va recadrer un paysage. Les
   proportions arrivent en variables CSS, jamais en attribut style — la CSP
   du vhost refuse le style en ligne. */
.n-forge__shot { display: flex; align-items: center; gap: var(--n-sp-6); min-inline-size: 0;
                 inline-size: 100%; }
.n-forge__frame {
  --n-ar-w: 9; --n-ar-h: 16;
  flex: none; display: block; overflow: hidden;
  block-size: 52px; aspect-ratio: var(--n-ar-w) / var(--n-ar-h);
  border-radius: var(--n-r-sm); background: var(--n-well);
  border: 1px solid var(--n-line-2);
  transition: aspect-ratio var(--n-dur-3) var(--n-ease-out);
}
.n-forge__thumb { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.n-forge__shotmeta { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; flex: 1 1 auto; }
.n-forge__shotname {
  font-size: var(--n-fs-sm); font-weight: var(--n-fw-medium); color: var(--n-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.n-forge__shotsize { font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
                     letter-spacing: var(--n-ls-wide); color: var(--n-text-dim); }
/* Le bouton passe AU-DESSUS de l'input, sinon le clic « Replace » rouvre
   le selecteur de fichier au lieu de vider le champ. */
.n-forge__clear {
  position: relative; z-index: 1; flex: none;
  display: inline-flex; align-items: center; gap: var(--n-sp-3);
  min-block-size: 32px; padding: var(--n-sp-3) var(--n-sp-5);
  background: var(--n-surface-1); color: var(--n-text-muted);
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-pill);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase; cursor: pointer;
  transition: color var(--n-dur-1) var(--n-ease-out), border-color var(--n-dur-1) var(--n-ease-out);
}
.n-forge__clear:hover { color: var(--n-text); border-color: var(--n-line-strong); }

/* Les deux deroules. La fleche est un SVG frere, pas une image de fond :
   `img-src 'self' blob:` ne couvre pas `data:`, et une fleche en data-URI
   dans le CSS ne s'affiche donc PAS en production. Le piege est deja dans
   ce fichier sur .n-select — celui-la ne le refait pas. */
.n-forge__pick { position: relative; display: block; }
/* `appearance: none` est ICI et pas sur .n-input : sans elle le deroule
   garde la fleche du systeme ET recoit la notre — deux chevrons cote a
   cote. .n-select porte deja la sienne, ce controle-la ne l'utilise pas. */
.n-forge__select { appearance: none; -webkit-appearance: none;
                   padding-inline-end: var(--n-sp-11); cursor: pointer; }
.n-forge__chev {
  position: absolute; inset-inline-end: var(--n-sp-6); inset-block-start: 50%;
  inline-size: 12px; block-size: 8px; margin-block-start: -4px;
  color: var(--n-text-faint); pointer-events: none;
}
/* Deux lignes, hauteur reservee. L'aide vient de la base (`help` de
   /config) et depasse une ligne : coupee a l'ellipse, elle s'arretait au
   milieu d'un mot. Hauteur fixe pour que le passage du repli HTML au texte
   de l'API ne fasse pas sauter la carte. */
.n-forge__hint {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; min-block-size: 2.6em; line-height: 1.3;
}

.n-forge__go { inline-size: 100%; }
@media (min-width: 900px) { .n-forge__go { inline-size: auto; min-inline-size: 148px; } }

.n-forge__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--n-sp-4) var(--n-sp-6);
  margin: var(--n-sp-6) 0 0;
  font-size: var(--n-fs-2xs); color: var(--n-text-dim);
}
.n-forge__badge {
  display: inline-flex; align-items: center;
  padding: 3px var(--n-sp-5); border-radius: var(--n-r-pill);
  background: var(--n-accent-soft); color: var(--n-accent);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase;
}

/* -- 26.3 · L'ETAT « CONTROLE » ------------------------------------------ */
.n-forge__eyebrow {
  margin: 0 0 var(--n-sp-4); font-family: var(--n-font-mono);
  font-size: var(--n-fs-3xs); letter-spacing: var(--n-ls-caps);
  text-transform: uppercase; color: var(--n-accent);
}
.n-forge__title {
  margin: 0; font-size: var(--n-fs-xl); font-weight: var(--n-fw-medium);
  letter-spacing: var(--n-ls-h3); color: var(--n-text);
}
.n-forge__sub { margin: var(--n-sp-4) 0 0; font-size: var(--n-fs-sm); color: var(--n-text-muted); }

.n-forge__track {
  block-size: 3px; margin-block: var(--n-sp-7) var(--n-sp-6);
  background: var(--n-line-2); border-radius: var(--n-r-pill); overflow: hidden;
}
.n-forge__bar {
  display: block; block-size: 100%; inline-size: var(--n-forge-progress, 0%);
  background-image: var(--n-grad);
  transition: inline-size var(--n-dur-3) var(--n-ease-out);
}

.n-forge__checks { margin: 0; padding: 0; list-style: none; }
.n-forge__check {
  display: flex; align-items: baseline; gap: var(--n-sp-5);
  padding-block: var(--n-sp-4);
  border-block-end: 1px solid var(--n-line);
  font-size: var(--n-fs-sm);
  opacity: .38;
  transition: opacity var(--n-dur-3) var(--n-ease-out);
}
.n-forge__check:last-child { border-block-end: 0; }
.n-forge__check b { flex: none; inline-size: 88px; font-weight: var(--n-fw-medium);
                    color: var(--n-text-muted); }
.n-forge__check span { color: var(--n-text); min-inline-size: 0; }
.n-forge__check::before {
  content: ""; flex: none; inline-size: 7px; block-size: 7px; border-radius: 50%;
  background: var(--n-line-3); align-self: center;
}
.n-forge__check[data-state="ok"]  { opacity: 1; }
.n-forge__check[data-state="ok"]::before  { background: var(--n-ok); }
.n-forge__check[data-state="bad"] { opacity: 1; }
.n-forge__check[data-state="bad"]::before { background: var(--n-danger); }
.n-forge__check[data-state="bad"] span    { color: var(--n-danger); }

.n-forge__note {
  margin: var(--n-sp-6) 0 0; min-block-size: 1.4em;
  font-size: var(--n-fs-sm); color: var(--n-text-muted);
}
.n-forge__note[data-tone="bad"] { color: var(--n-danger); }

.n-forge__actions {
  display: flex; flex-wrap: wrap; gap: var(--n-sp-5);
  margin-block-start: var(--n-sp-7);
}
.n-forge__actions .n-btn { flex: 1 1 auto; }
@media (min-width: 560px) { .n-forge__actions .n-btn { flex: 0 0 auto; } }
.n-forge__actions .n-btn[data-toaccount], .n-forge__actions .n-btn[type="submit"] { margin-inline-start: auto; }

/* -- 26.4 · L'ETAT « PALIER » -------------------------------------------- */
.n-forge__plans {
  display: grid; gap: var(--n-sp-5); margin-block-start: var(--n-sp-7);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 720px) { .n-forge__plans { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.n-forge__plan { position: relative; display: block; cursor: pointer; }
.n-forge__plan input {
  position: absolute; inset: 0; inline-size: 100%; block-size: 100%;
  opacity: 0; margin: 0; cursor: pointer;
}
.n-forge__planface {
  display: flex; flex-direction: column; gap: var(--n-sp-2);
  min-block-size: 96px; padding: var(--n-sp-6);
  background: var(--n-surface-2); border: 1px solid var(--n-line-2);
  border-radius: var(--n-r-lg);
  transition: border-color var(--n-dur-2) var(--n-ease-out),
              background-color var(--n-dur-2) var(--n-ease-out);
}
.n-forge__planname { font-size: var(--n-fs-xs); font-weight: var(--n-fw-medium);
                     color: var(--n-text-muted); }
.n-forge__planprice { font-size: var(--n-fs-2xl); font-weight: var(--n-fw-semi);
                      letter-spacing: var(--n-ls-title); color: var(--n-text); }
.n-forge__planquota { font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
                      letter-spacing: var(--n-ls-wide); color: var(--n-text-dim); }
.n-forge__planflag {
  margin-block-start: var(--n-sp-3); align-self: flex-start;
  padding: 2px var(--n-sp-4); border-radius: var(--n-r-pill);
  background: var(--n-accent-soft); color: var(--n-accent);
  font-family: var(--n-font-mono); font-size: var(--n-fs-3xs);
  letter-spacing: var(--n-ls-wide); text-transform: uppercase;
}
.n-forge__plan input:hover + .n-forge__planface { border-color: var(--n-line-strong); }
.n-forge__plan input:focus-visible + .n-forge__planface {
  outline: var(--n-focus-w) solid var(--n-focus); outline-offset: var(--n-focus-offset);
}
/* La selection n'est jamais portee par la seule couleur : cadre double
   ET coche dans le coin. */
.n-forge__plan input:checked + .n-forge__planface {
  border-color: var(--n-accent); background: var(--n-accent-veil);
  box-shadow: inset 0 0 0 1px var(--n-accent);
}
.n-forge__plan input:checked + .n-forge__planface::after {
  content: ""; position: absolute;
  inset-block-start: var(--n-sp-6); inset-inline-end: var(--n-sp-6);
  inline-size: 10px; block-size: 6px;
  border-inline-start: 1.5px solid var(--n-accent);
  border-block-end: 1.5px solid var(--n-accent);
  transform: rotate(-45deg);
}

/* -- 26.5 · L'ETAT « COMPTE » -------------------------------------------- */
.n-forge__form { display: flex; flex-direction: column; gap: var(--n-sp-6);
                 margin-block-start: var(--n-sp-7); }
@media (min-width: 720px) {
  .n-forge__form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                   gap: var(--n-sp-6) var(--n-sp-7); align-items: start; }
  .n-forge__tos, .n-forge__actions, .n-forge__switch,
  .n-forge__form > .n-field__error { grid-column: 1 / -1; }
}
.n-forge__tos {
  display: flex; align-items: flex-start; gap: var(--n-sp-5);
  font-size: var(--n-fs-sm); color: var(--n-text-muted); cursor: pointer;
}
.n-forge__tos input {
  flex: none; inline-size: 18px; block-size: 18px; margin: 2px 0 0;
  accent-color: var(--n-accent); cursor: pointer;
}
.n-forge__tos a { color: var(--n-accent); }
.n-forge__switch { margin: 0; }
.n-forge__link {
  padding: 0; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--n-fs-sm); color: var(--n-accent);
  text-decoration: underline; text-underline-offset: 3px;
}
.n-forge__link:hover { color: var(--n-accent-hi); }
.n-forge__nojs { margin: 0; font-size: var(--n-fs-sm); color: var(--n-text-muted); }

/* -- 26.6 · LE HEROS QUI PORTE LA CARTE ---------------------------------
   Le heros faisait 100svh avec la seule colonne de texte. La carte ajoute
   ~220 px sur mobile : sans ces deux reglages elle pousserait l'invite de
   defilement hors de l'ecran, et le premier ecran deviendrait un mur. */
@media (max-width: 899.98px) {
  .n-hero { padding-block-start: calc(var(--n-header-h) + var(--n-sp-10)); }
  .n-hero__lead { display: none; }         /* le titre + la carte suffisent */
  .n-hero__hint { display: none; }
}
@media (max-width: 1199.98px) and (min-width: 900px) {
  .n-hero { padding-block-start: calc(var(--n-header-h) + var(--n-sp-11)); }
}

/* -- 26.7 · MOUVEMENT REDUIT ---------------------------------------------
   La carte reste utilisable a l'identique : ce qui saute, c'est le fondu
   d'un etat a l'autre et le glissement de la jauge. */
@media (prefers-reduced-motion: reduce) {
  .n-forge__bar, .n-forge__frame, .n-forge__check { transition: none !important; }
  .n-forge__panel { animation: none !important; }
}
.n-forge__panel[data-phase="in"] { animation: n-cut-in 180ms var(--n-ease-out) both; }
.no-js .n-forge { display: none; }

/* -- 25.13 · CE QUE LA COQUE MONTRE, ACTE PAR ACTE -----------------------
   Un seul jeu d'elements vit dans .n-carry ; l'attribut data-act decide de
   ce qui se voit. C'est ce qui permet a la scene de ne jamais changer de
   parent : rien n'est cree ni detruit, tout est montre ou cache. */
.n-carry[data-act="1"] [data-only="2"], .n-carry[data-act="1"] [data-only="3"],
.n-carry[data-act="2"] [data-only="1"], .n-carry[data-act="2"] [data-only="3"],
.n-carry[data-act="3"] [data-only="1"], .n-carry[data-act="3"] [data-only="2"] {
  display: none !important;
}
/* La chaine explique le produit : elle n'a de sens qu'au premier ecran. */
.n-room[data-act="2"] .n-chain, .n-room[data-act="3"] .n-chain { display: none; }
.no-js .n-room[data-act] .n-chain { display: block; }
.no-js .n-carry [data-only] { display: revert !important; }

/* La note de service. Elle se pose seule, sans carte autour, contrairement
   a .n-note de la section 23 qui vit dans un .n-card. */
.n-act .n-note {
  padding: var(--n-sp-6) var(--n-sp-7); margin-block-end: 0;
  border: 1px solid var(--n-line-2); border-radius: var(--n-r-lg);
  background: var(--n-surface-1); font-size: var(--n-fs-sm);
  color: var(--n-text-muted); line-height: 1.6;
}
.n-act .n-note--warn   { border-color: var(--n-warn);   background: var(--n-warn-soft); }
.n-act .n-note--ok     { border-color: var(--n-ok);     background: var(--n-ok-soft); }
.n-act .n-note--danger { border-color: var(--n-danger); background: var(--n-danger-soft); }
