/* ============================================================================
   orbis.css — LA FEUILLE UNIQUE DU SITE · « GRAPHITE » (2026-09-17)
   ============================================================================
   ⚠️⚠️ « OULA ÇA FAIT TRÈS IA » (17/09) — le premier regard d'une personne
   extérieure sur la « Nuit violette » du 15/09. Puis l'éditeur : « pousse
   encore plus loin le diagnostic, le site ne doit plus du tout faire IA ».
   Le détecteur d'anti-patterns du skill impeccable, branché sur les six pages
   publiques (bureau + téléphone), lui a donné raison : 297 constats, dont
   129 lueurs colorées (`dark-glow`), 73 filets fins sous ombre large, 20
   palettes violettes (`ai-color-palette`), 12 halos radiaux « projecteur ».
   La référence choisie le 15/09 — une page SaaS de Dribbble — EST le gabarit
   que les générateurs de sites reproduisent : sol violet, faisceau, grille
   dans la lumière, grain, pilule de navigation à point, pastille à point
   au-dessus de chaque titre, bouton lumineux. Aucun de ces gestes n'y est
   un défaut isolé ; c'est leur somme qui signe « généré ».

   LA DA « GRAPHITE » EST CELLE DES APPLICATIONS : les gris d'Everything et
   d'AssetBrowser sont relevés sur Final Cut Pro (mémoire du projet : sol
   #0E0E10 · panneau #1C1C1E · levé #2C2C2E), UNE couleur pour ce qui se
   clique — un orange, en aplat —, aucune lumière colorée, aucun stade (un
   rayon s'arrête avant la demi-hauteur du contrôle). Le site a désormais la
   tête des outils qu'il vend : la couleur vient des captures, des icônes et
   de ce qui se clique.

   ⚠️⚠️ LE VIOLET EST DEVENU GRAPHITE À LUMINANCE CONSTANTE — le geste inverse
   de celui du 15/09. Chaque couleur de la famille violette (teinte 240-290)
   garde sa luminance relative WCAG et devient un gris neutre de même alpha :
   les contrastes mesurés par les bancs restent les mêmes. Seule l'ACTION a
   changé de rôle : bleu des applications d'abord, orange une heure plus tard
   (« c'est un peu fade avec les boutons bleus »), avec une encre SOMBRE
   dessus (7,3:1) — voir les jetons.
   Les NOMS des jetons (`--bleu`, `--bleu-clair`…) n'ont pas bougé : une
   trentaine de pages et de scripts les citent.

   CE QUI EST PARTI, et ne doit pas revenir sans une demande qui le nomme :
     · le halo, le faisceau, la grille dans la lumière, le grain et le lavis
       violet du sol (`#fond`, `[data-lueur]`). La nappe ShaderGradient, elle,
       RESTE (« j'aimais bien shaderGradient », 17/09) — en gris ;
     · toute ombre COLORÉE, toute lueur à décalage nul, et le couple « filet
       d'un pixel + ombre large » sur une même surface ;
     · la pastille à point au-dessus des titres et le point de l'onglet actif ;
     · les pilules : `--r-pill` vaut 12 px, la valeur des applications ;
     · le chevron dessiné des grands boutons.

   ⚠️⚠️ ET RIEN N'EST PLUS CENTRÉ PAR DÉFAUT (§ « l'asymétrie », en fin de
   feuille) : ça, c'était une demande de l'éditeur (« trop symétrique, c'est
   chiant ») et ça reste.

   ⚠️⚠️ CE QUI A ÉTÉ REFUSÉ AVANT, ET QUE CETTE DA NE REFAIT PAS :
     · une BANDE pleine largeur qui coupe la page (« là il y a une barre de
       dessous ») ;
     · un fond animé qui devient le sujet (« horrible le fond animé ») ;
     · le texte en dégradé : `.degrade` reste neutralisé (§ typographie).

   RÈGLES DE LECTURE DES BANCS, tenues dans toute la feuille :
     · la lumière vit dans des PSEUDO-ÉLÉMENTS : `t-contraste` remonte les
       ancêtres d'un texte et prend le pire arrêt d'un `background-image`. Un
       halo posé sur la section elle-même lui masquerait tout le texte ;
     · un seul thème, sombre, sur `:root` ET `[data-theme="dark"]` (`t-theme`,
       `t-essai`) ;
     · toute boucle `infinite` a son `animation: none` sous mouvement réduit,
       sur le MÊME sélecteur (`t-mouvement-reduit`) ;
     · pas de verre dans du verre, huit couches au plus par page, flou plus
       épais pour une plus grande surface (`t-verre`).
   ========================================================================== */

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

/* ----------------------------------------------------------------- jetons */
/* ⚠️ `:root` ET `:root[data-theme="dark"]` portent les MÊMES valeurs : la page
   doit être sombre sans `theme.js` (script bloquant du <head> qui pose
   l'attribut), et forcer `data-theme="light"` ne doit réveiller aucun blanc.
   `t-essai` exige que `--avert` suive `:root[data-theme="dark"]` de près. */
:root,
:root[data-theme="dark"] {
  color-scheme: dark;
  --avert: #E0A65B;
  --avert-fond: #221A0E;
  --avert-trait: rgba(224, 166, 91, .28);

  /* le sol, du plus profond au plus levé — des gris NEUTRES, à la luminance
     des violets qu'ils remplacent (le sol a gagné un cheveu : #09050E valait
     presque le noir pur, et un noir pur est lui aussi un réflexe de gabarit) */
  --papier-2: #0A0A0B;          /* le sol de la page */
  --papier: #0C0C0C;            /* une surface posée */
  --papier-3: #181818;          /* une surface levée, un champ au survol */
  --cadre: #111111;             /* le fond d'un cadre de produit */

  --trait: rgba(177, 177, 177, .11);
  --trait-fort: rgba(177, 177, 177, .21);

  /* les encres — mêmes luminances que les encres violettes : 18 / 9,3 / 5,7:1 */
  --encre: #F5F5F7;
  --encre-2: #C7C7CB;
  --encre-3: #A6A6AD;

  /* L'ORANGE : ce qui se clique, les liens, le repère clavier, la page
     courante. Une seule couleur, en APLAT — jamais en lueur ni en lavis.
     ⚠️⚠️ ELLE A ÉTÉ BLEUE UNE HEURE (17/09). Le bleu des applications était
     juste et sage ; l'éditeur, en le voyant : « c'est un peu fade avec les
     boutons bleus, et sans le violet ». L'orange est la couleur des outils du
     métier (Houdini, Blender), répond au bleu du logo, et n'appartient à
     aucune palette de page générée.
     ⚠️ LE TEXTE SUR L'ORANGE EST SOMBRE (`--sur-action`) : du blanc n'y tient
     que 2,6:1. Toute règle qui pose `--action` en fond pose `--sur-action` en
     encre — jamais `#fff`. Les noms `--bleu*` restent (voir l'en-tête). */
  --bleu: #FF8533;
  --bleu-vif: #FF9D5C;
  --bleu-clair: #FFAF78;        /* liens, repère clavier, curseurs — 11:1 sur le sol */

  --action: #FF8533;            /* 7,3:1 sous `--sur-action` */
  --action-vive: #FF9D5C;
  --sur-action: #1A0D04;
  --sur-clair: #0C0C0C;
  --sur-clair-fond: rgba(255, 255, 255, .06);

  /* voiles : du blanc à très faible dose, pour lever une surface */
  --voile-1: rgba(255, 255, 255, .03);
  --voile-2: rgba(255, 255, 255, .055);
  --voile-3: rgba(255, 255, 255, .085);
  --voile-4: rgba(255, 255, 255, .12);
  --voile-entete: rgba(10, 10, 11, 0);
  --voile-entete-collee: rgba(10, 10, 11, .78);
  --bord-defile: rgba(10, 10, 11, .9);

  /* vestiges nommés par d'anciens gabarits : ils suivent la palette */
  --lavis-1: #1B1B1B;
  --lavis-2: #1F1F1F;
  --lavis-3: #161616;

  --vert: #28C840;
  --rouge: #FF7A6E;

  --r-s: 12px;
  --r-l: 20px;
  --r-xl: 28px;
  /* ⚠️ PLUS DE STADE : 12 px, le `--r-pill` des applications. Le jeton garde
     son nom (une quarantaine de règles le lisent) ; un cercle s'écrit `50%`. */
  --r-pill: 12px;

  --entete-h: 76px;
  --pas: clamp(64px, 7vw, 112px);
  --pas-bas: clamp(64px, 7.5vw, 120px);
  --large: 1180px;
  --etroit: 680px;

  --ombre-1: 0 1px 2px rgba(0, 0, 0, .5);
  --ombre-2: 0 10px 30px -14px rgba(0, 0, 0, .8);
  --ombre-3: 0 40px 90px -50px rgba(0, 0, 0, .95), 0 2px 10px -4px rgba(0, 0, 0, .6);

  /* le liseré d'un cadre de produit : un anneau d'ombre, jamais une bordure,
     pour ne pas bouger d'un pixel la mise en page de ce qu'il entoure.
     ⚠️ UN SEUL PIXEL, et plus de lunette de 9 px ni de lueur dessous : un
     produit posé dans un cadre épais qui rayonne, c'est la « maquette
     d'appareil » des gabarits. Une capture d'application a un bord, pas un
     écrin. Et jamais ce filet AVEC une ombre large sur la même surface
     (`gpt-thin-border-wide-shadow` du détecteur) : l'un ou l'autre. */
  --anneau: 0 0 0 1px rgba(255, 255, 255, .11);

  /* le verre, du plus fin au plus épais — la taille de la surface décide */
  --verre-fin: blur(10px) saturate(150%);
  --verre-moyen: blur(16px) saturate(160%);
  --verre-epais: blur(26px) saturate(170%);
}

/* ------------------------------------------------------------------- base */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* ⚠️ iPhone (17/09) : sans cette ligne, Safari GROSSIT le texte quand on tourne
   le téléphone en paysage, et les rangées calibrées au pixel (la barre de
   navigation tient à un pixel près à 375 px) passent à la ligne. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* ⚠️⚠️ `svh`, JAMAIS `dvh` (26/09, « quand on descend il y a plein de bugs
   d'UI » — l'éditeur, sur iPhone). Sur Safari iOS, la barre d'adresse se
   replie dès qu'on descend et revient dès qu'on remonte : `dvh` suit cette
   hauteur, donc TOUT ce qui s'y mesure (marges du héros, de l'ouverture des
   applications, du bandeau, de la page Compte…) changeait à chaque geste, et
   le contenu sautait de 5 à 11 px sous le doigt — Safari n'a pas l'ancrage
   de défilement qui le masque dans Chrome. `svh` est la petite hauteur, celle
   du chargement : elle ne bouge plus. Sur ordinateur, les deux sont égales.
   Mesuré par une sonde qui imite la barre (repli + retour, défilement
   immobile, ancrage coupé) : 30 sauts sur 9 pages avant, voir § TÉLÉPHONE
   ET TABLETTE en fin de feuille. */
body {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: var(--papier-2);
  color: var(--encre);
  font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: -0.006em;
  font-feature-settings: 'cv11', 'ss03';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, canvas { display: block; max-width: 100%; }
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
::selection { background: rgba(255,133,51, .38); color: #fff; }
:focus-visible { outline: 2px solid var(--bleu-clair); outline-offset: 3px; border-radius: 6px; }

/* ⚠️⚠️ LE FILET SANS JAVASCRIPT : les entrées partent à `opacity: 0` ; sans
   script (extension, erreur, CSP), rien ne les ferait revenir. `i18n.js` pose
   `js` sur <html> dès sa première ligne. */
html:not(.js) [data-anim],
html:not(.js) [data-stagger] > * { opacity: 1 !important; transform: none !important; }

/* ------------------------------------------------------------------ décor */
/* Le sol de TOUTES les pages : un aplat, fixe, immobile.
   ⚠️⚠️ GRAPHITE (17/09) : plus de lavis violet en haut de l'écran, plus de
   GRAIN. Le grain cassait les paliers d'un dégradé sombre ; il n'y a plus de
   dégradé à casser, et un grain posé sur un sol sombre est lui-même une
   signature des pages générées. */
#fond {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--papier-2);
}

/* ⚠️ `body > …` porte le contenu AU-DESSUS du sol fixe. `.langmenu` n'est
   PAS dans la liste : il est reparenté sur <body> et vit en `fixed`. */
body > header, body > section, body > footer, body > main {
  position: relative;
  z-index: 1;
}

/* LA LUMIÈRE — RETIRÉE (17/09).
   `[data-lueur]` portait un halo en haut à droite, un faisceau diagonal et une
   grille qui n'apparaissait que dans la lumière : le « projecteur » des pages
   générées (`radial-spotlight-glow` et `codex-grid-background` du détecteur,
   sur les douze pages). L'attribut reste posé ; il ne porte plus que ceci.
   ⚠️ `overflow-x: clip` RESTE : le cadre du héros de l'accueil déborde à
   droite. `hidden` forcerait `overflow-y: auto` et créerait un conteneur de
   défilement, qui casserait le `sticky` de l'en-tête. */
[data-lueur] {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
}
/* ⚠️ Safari avant la version 16 (iOS 15, iPadOS 15) ne connaît pas `clip` :
   sans repli, les images et les panneaux qui partent jusqu'au bord de l'écran
   ÉLARGISSENT la page — et Safari sur iPad dézoome alors la page ENTIÈRE pour la
   faire tenir. `hidden` y fige un titre collant de la FAQ : c'est le moindre
   des deux défauts, et il ne touche que ces anciennes versions. */
@supports not (overflow: clip) {
  [data-lueur] { overflow-x: hidden; }
}
/* LA NAPPE — le vrai ShaderGradient (`nappe.js`), dans le premier écran.
   ⚠️⚠️ GARDÉE, MAIS PLUS VIOLETTE (17/09). L'éditeur, au milieu de la passe
   « ça fait IA » : « après j'aimais bien shaderGradient ». Ce qui signait
   « généré », ce n'était pas le composant : c'était son violet, le faisceau
   CSS qui le doublait, la grille dans la lumière et le grain. Elle garde son
   mouvement et prend les gris des applications (`REGLAGE` de `nappe.js`,
   affiches refaites par `tools/nappe-affiches.js`).
   ⚠️ Son MASQUE est sa limite : ancré en haut à gauche, il s'éteint avant le
   bas du héros — jamais une bande, jamais un bord. */
.nappe {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(-1 * var(--entete-h));
  height: 1040px;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  -webkit-mask-image: radial-gradient(1460px 1020px at 17% -6%, #000 24%, rgba(0, 0, 0, .66) 48%, rgba(0, 0, 0, .26) 68%, transparent 86%);
  mask-image: radial-gradient(1460px 1020px at 17% -6%, #000 24%, rgba(0, 0, 0, .66) 48%, rgba(0, 0, 0, .26) 68%, transparent 86%);
  /* ⚠️⚠️ L'ÉCLAIR ORANGE DES TARIFS (24/09, vidéo d'un ami de l'éditeur,
     Chrome, 2 560 × 1 440) : ~2 s après l'arrivée, DEUX images où la nappe
     sort SANS son masque — toute la boîte, saturée par le filtre, coupée net
     à 1 040 px. À la bascule, trois changements de structure tombaient dans
     la même image sur ce calque masqué et filtré : la toile qui passe de 0 à
     1 (un calque neuf à composer), l'affiche retirée (`nappe-live-frame`), et
     le masque à poser sur la surface qui naît. Sur certains pilotes, le masque
     arrive une ou deux images après. Non reproduit ici (RTX, 1 230 images
     enregistrées) : le correctif retire la CAUSE — la nappe est composée avec
     son masque dès la première image, la toile existe dès sa naissance
     (opacité ,001), et l'affiche ne part que deux images après la toile. */
  will-change: transform;
}
/* ⚠️⚠️ LA TOILE MONTE SUR SON AFFICHE (15/09, nuit : « quand j'arrive sur la
   page rien ne doit buger »). L'AFFICHE est la première image de la nappe de
   la page (`uTime` 0), posée dès la première peinture ; la toile démarre sur
   cette image même, et son fondu de 0,5 s ne montre que la texture qui se pose.
   ⚠️ 2 560 × 1 040 px, ancrée au MILIEU du haut : la caméra garde son champ
   vertical, donc à hauteur égale le centre de l'image est le même quelle que
   soit la largeur de l'écran. `tools/nappe-affiches.js` les refait — À
   RELANCER après toute retouche de `REGLAGE`, sinon l'affiche garde les
   anciennes couleurs et la page change d'image au montage de la toile.
   ⚠️ L'affiche suit la nappe : cachée avec elle au téléphone, sous « moins de
   mouvement » et « moins de transparence ». Là, le sol reste un aplat : plus
   de faisceau CSS de repli. */
.nappe-toile {
  position: absolute;
  inset: 0;
  /* ,001 et pas 0 : un calque à opacité nulle n'est pas composé, et c'est sa
     NAISSANCE au moment de la bascule qui laissait passer l'éclair (voir
     `.nappe`). À ,001 la toile est composée dès qu'elle existe, et invisible
     (255 × ,001 s'arrondit à 0). */
  opacity: .001;
  will-change: opacity;
  /* L'affiche nette et la toile à t=0 se remplacent sans fondu flou. */
  transition: none;
}
.nappe-toile.prete { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .nappe-toile { transition: none; } }
.nappe[data-affiche] { background-repeat: no-repeat; background-position: 50% 0; background-size: 2560px 1040px; }
.nappe[data-affiche="accueil"] { background-image: url(/assets/nappe/accueil.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="applications"] { background-image: url(/assets/nappe/applications.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="assetbrowser"] { background-image: url(/assets/nappe/assetbrowser.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="everything"] { background-image: url(/assets/nappe/everything.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="telecharger"] { background-image: url(/assets/nappe/telecharger.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="tarifs"] { background-image: url(/assets/nappe/tarifs.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="cgv"] { background-image: url(/assets/nappe/cgv.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="conditions"] { background-image: url(/assets/nappe/conditions.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="confidentialite"] { background-image: url(/assets/nappe/confidentialite.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="mentions-legales"] { background-image: url(/assets/nappe/mentions-legales.webp?v=20260920-sans-grain-2); }
.nappe[data-affiche="compte"] { background-image: url(/assets/nappe/compte.webp?v=20260920-sans-grain-2); }

/* --------------------------------------------------------------- gabarit */
.wrap { width: min(100% - 48px, var(--large)); margin-inline: auto; }
.wrap.tres-large { width: min(100% - 48px, 1560px); }
.etroit { max-width: var(--etroit); margin-inline: auto; }
section { padding-top: var(--pas); padding-bottom: var(--pas-bas); }
main { flex: 1 0 auto; }
.centre { text-align: center; }
/* L'acte de clôture : le seul changement de sol de la page, et il se fait
   par la LUMIÈRE, pas par un aplat (un aplat redevient une bande). */
.acte { background: transparent; }

/* ------------------------------------------------------------ typographie */
/* La référence titre FIN : poids 500, interlettrage serré, grand corps. C'est
   ce qui la rend calme — un 600 à cette taille crie. */
h1, h2, h3, h4 { margin: 0; font-weight: 500; }

.display {
  font-size: clamp(2.6rem, 5.6vw, 4.5rem);
  line-height: 1.03;
  letter-spacing: -0.038em;
  font-weight: 500;
  text-wrap: balance;
}
.titre {
  font-size: clamp(1.9rem, 3.4vw, 2.85rem);
  line-height: 1.08;
  letter-spacing: -0.032em;
  font-weight: 500;
  text-wrap: balance;
}
.titre-s {
  font-size: 1.1rem;
  line-height: 1.3;
  letter-spacing: -0.014em;
  font-weight: 500;
}
.sous-titre {
  font-size: clamp(1rem, 1.15vw, 1.075rem);
  line-height: 1.62;
  letter-spacing: -0.004em;
  color: var(--encre-2);
  font-weight: 400;
  text-wrap: pretty;
}
/* le chapeau qui suit un grand titre : un cran au-dessus du corps, jamais gras */
.display + .sous-titre,
.titre + .sous-titre {
  margin-top: 18px;
  font-size: clamp(1.04rem, 1.35vw, 1.2rem);
  line-height: 1.55;
  letter-spacing: -0.006em;
  font-weight: 400;
}

/* LE NOM DE LA SECTION. `.legende` est une petite note grise ; au-dessus d'un
   titre elle nomme l'application que la section montre (« Everything »,
   « AssetBrowser »), en toutes lettres, comme un intertitre de documentation.
   ⚠️⚠️ PLUS DE PILULE À POINT (17/09). « • Secure. Scalable. » au-dessus de
   chaque titre était la signature la plus reconnaissable de la référence — et
   des pages générées (`hero-eyebrow-chip` du détecteur). Pas de capitales
   espacées non plus : c'est la même étiquette, habillée autrement
   (`kicker-above-heading`). Une ligne de texte, à la taille du corps.
   ⚠️ `assetbrowser.html` s'en sert aussi pour deux mentions sous des boutons :
   la règle de base reste une note. */
.legende {
  font-size: 12.5px;
  line-height: 1.5;
  letter-spacing: 0;
  font-weight: 450;
  color: var(--encre-3);
}
.legende:has(+ .titre),
.legende:has(+ h2) {
  display: block;
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--encre-2);
}
.legende:has(+ .titre) + .titre,
.legende:has(+ h2) + h2 { margin-top: 10px !important; }

/* un chapeau centré ne s'étale pas sur toute la colonne */
.centre > .titre + .sous-titre { max-width: 60ch; margin-inline: auto; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
strong { font-weight: 600; color: var(--encre); }
small { font-size: 13px; }

/* ⚠️⚠️ LE DÉGRADÉ DE TITRE RESTE NEUTRALISÉ. Décision de l'éditeur (08/09 :
   « il disparaît »), et quatre pages portent encore la classe sur leur seconde
   ligne de titre. Cette règle est le filet : sans elle, les arrêts de couleur
   reviendraient. ⚠️ `d4` y reste nommée pour la même raison. */
.degrade, .degrade.d1, .degrade.d2, .degrade.d3, .degrade.d4, .degrade.d5 {
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
  -webkit-text-fill-color: currentColor;
  color: inherit;
}
/* le mot-à-mot de `mouvement.js` */
.mot { display: inline-block; white-space: pre; }

/* --------------------------------------------------------------- boutons */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 22px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font: inherit;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.01em;
  cursor: pointer;
  text-align: center;
  white-space: nowrap;
  transition: transform .12s ease-out, background-color .2s, border-color .2s,
              box-shadow .25s, color .2s, opacity .2s;
}
.btn:active { transform: scale(.975); }
.btn[disabled], .btn[aria-disabled="true"] { cursor: default; opacity: .55; }
.btn[disabled]:active { transform: none; }

/* LE BOUTON PLEIN — le bleu des applications, en aplat.
   ⚠️⚠️ GRAPHITE (17/09) : plus de lueur colorée dessous, plus de reflet
   intérieur, plus de chevron dessiné. Un bouton qui rayonne sur un sol sombre
   est le premier réflexe des pages générées (`dark-glow`) ; celui des
   applications est un aplat, et c'est lui qu'on voit dans les démonstrations
   juste en dessous (« Convertir tout »).
   ⚠️ Aplat, jamais dégradé : un `background-image` ferait mesurer par
   `t-contraste` son arrêt le plus clair. */
.btn-1 {
  background-color: var(--action);
  color: var(--sur-action);
  border-color: transparent;
}
.btn-1:hover { background-color: var(--action-vive); }
.btn-1[disabled]:hover { background-color: var(--action); }

/* LE BOUTON SECONDAIRE — un contour, sans verre.
   ⚠️ Le reflet qui suivait le pointeur (`--mx`, `--my` de `verre-liquide.js`)
   est parti avec le verre : un halo qui suit la souris sur un bouton est un
   effet de démonstration, pas un état. `verre-liquide.js` peut rester chargé,
   ses variables ne sont plus lues. */
.btn-2 {
  background-color: transparent;
  border-color: rgba(255, 255, 255, .22);
  color: var(--encre);
}
.btn-2:hover { background-color: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .34); }
.chip, .langbtn { position: relative; }

.btn-3 { padding-inline: 6px; color: var(--encre-2); background: transparent; }
.btn-3:hover { color: var(--encre); }
.btn-bloc { width: 100%; }
.btn-l { padding: 14px 26px; font-size: 15px; }
.btn-s { padding: 11px 20px; font-size: 14.5px; }

.lien-fleche {
  font-size: 15px;
  font-weight: 500;
  color: var(--bleu-clair);
  border-bottom: 1px solid transparent;
  transition: border-color .18s, color .18s;
}
.lien-fleche::after { content: ' ›'; }
.lien-fleche:hover { color: #FFBD8A; border-color: currentColor; }

.lienbtn {
  border: 0;
  background: transparent;
  color: var(--encre-2);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--trait-fort);
}
.lienbtn:hover { color: var(--encre); text-decoration-color: currentColor; }

/* ------------------------------------------------------------- pastilles */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 11px;
  border-radius: 8px;
  border: 1px solid var(--trait-fort);
  background: rgba(255, 255, 255, .03);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.004em;
  color: var(--encre-2);
}
.chip.sombre { border-color: var(--trait-fort); background: rgba(255, 255, 255, .03); color: var(--encre-2); }
/* le point d'ÉTAT (« Disponible ») : vert, et seulement là où il dit quelque
   chose */
.chip .pt {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 50%;
  background: var(--vert);
}
/* ⚠️⚠️ DANS UN HÉROS, LA PASTILLE N'EN EST PLUS UNE (17/09). Le point bleu
   lumineux et la pilule au-dessus du grand titre, c'était le héros SaaS par
   défaut des générateurs (`hero-eyebrow-chip`). La ligne reste — elle dit
   pour quel système on télécharge — mais en simple texte gris. */
.hero .chip,
.bandeau .chip {
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-size: 14px;
  color: var(--encre-3);
}
.hero .chip .pt,
.bandeau .chip .pt { display: none; }
.chip.plan { background: rgba(119, 119, 119, .12); border-color: rgba(155, 155, 155, .32); color: var(--encre); }
.chip.ok { background: rgba(40, 200, 64, .10); border-color: rgba(40, 200, 64, .28); color: var(--vert); }
.chip.warn { background: rgba(251, 191, 36, .10); border-color: rgba(251, 191, 36, .28); color: #FBBF24; }

/* les noms de logiciels, en rangée */
.dcc { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.dcc span {
  padding: 8px 16px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .025);
  font-size: 14px;
  font-weight: 450;
  color: var(--encre-2);
  transition: border-color .2s, color .2s;
}
.dcc span:hover { color: var(--encre); border-color: var(--trait-fort); }

/* ------------------------------------------------------------- en-tête */
/* La marque à gauche, la navigation au centre, les outils à droite.
   ⚠️ En haut de page la barre est TRANSPARENTE. Elle devient une surface
   opaque à 78 % dès qu'on défile (`.collee`, posée par `mouvement.js` ou
   `site.js`), avec un filet — et plus d'ombre large sous ce filet.
   ⚠️ Dans la barre, AUCUN contrôle ne porte de flou : du verre dans du verre
   ouvre une seconde région d'échantillonnage (`t-verre`, règle 1). */
.entete {
  position: sticky;
  top: 0;
  z-index: 60;
  height: var(--entete-h);
  display: flex;
  align-items: center;
  padding-block: 0;
  background: var(--voile-entete);
  border-bottom: 1px solid transparent;
  transition: background-color .35s ease, border-color .35s ease, box-shadow .35s ease;
}
.entete.collee {
  background: var(--voile-entete-collee);
  -webkit-backdrop-filter: var(--verre-epais);
  backdrop-filter: var(--verre-epais);
  border-bottom-color: var(--trait);
}
/* ⚠️⚠️ L'EN-TÊTE NE DOIT PAS DÉPENDRE D'UN SCRIPT POUR ÊTRE LISIBLE (17/09,
   capture de l'éditeur sur `/tarifs.html` : la ligne « AssetBrowser » du
   tableau passait par-dessus la marque, et ses quatre « Oui » entre les liens
   de la barre). La barre est `sticky` et son fond vaut `rgba(10, 10, 11, 0)`
   tant que personne ne lui pose `.collee` : TOUT ce qui défile dessous la
   traverse, en clair, sans le moindre message d'erreur.
   La classe était posée par deux mécanismes, et chacun peut manquer son
   moment : `mouvement.js` (GSAP) ne la pose qu'une fois la page POSÉE, et le
   filet de `site.js` écoute `scroll` — or la restauration du défilement
   n'émet pas toujours cet événement (piège déjà payé le 14/08, § LA BANDE DU
   BAS). Entre les deux, une page ouverte déjà défilée montre du texte à
   travers sa barre.
   Le voile est donc lié au DÉFILEMENT LUI-MÊME, sans script : dès le premier
   pixel quitté, l'en-tête a son fond et son filet. La classe reste pour les
   navigateurs sans `animation-timeline` (Safari d'avant 26), où les deux
   scripts continuent de la poser.
   ⚠️ Ce n'est pas du mouvement : rien ne bouge, c'est un fond qui apparaît.
   `prefers-reduced-motion` n'a donc rien à couper, et `t-mouvement-reduit` ne
   voit ici aucune boucle. */
@supports (animation-timeline: scroll()) {
  .entete {
    animation: entete-voile linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 14px;
  }
  @keyframes entete-voile {
    from {
      background-color: var(--voile-entete);
      border-bottom-color: transparent;
    }
    to {
      background-color: var(--voile-entete-collee);
      border-bottom-color: var(--trait);
      -webkit-backdrop-filter: var(--verre-epais);
      backdrop-filter: var(--verre-epais);
    }
  }
}
.entete .wrap {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 20px;
  width: min(100% - 48px, 1280px);
}
.entete .menu a, .entete .outils .btn, .entete .langbtn, .entete .marque { white-space: nowrap; }
.entete .marque { justify-self: start; }
.entete .menu { justify-self: center; margin-inline: 0; }
.entete .outils { justify-self: end; }

.marque {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 500;
  font-size: 18px;
  letter-spacing: -0.03em;
  color: var(--encre);
}
.marque img { width: 30px; height: 30px; }

/* la navigation : des liens, pas une pilule.
   ⚠️⚠️ GRAPHITE (17/09) : la pilule centrée et son onglet actif marqué d'un
   point lumineux étaient la barre de la référence, donc celle des gabarits.
   ⚠️ Le rembourrage du CONTENEUR (5 px) et sa bordure restent comptés dans la
   largeur : au téléphone la bande tient à un pixel près (`t-menu-tel`), on ne
   l'élargit pas d'un seul. Seules la surface et la bordure deviennent
   invisibles. */
.menu {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-inline: auto;
  padding: 5px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  background: transparent;
}
.menu a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 17px;
  border-radius: 8px;
  font-size: 14.5px;
  font-weight: 450;
  color: var(--encre-2);
  transition: color .18s, background-color .18s;
}
.menu a:hover { color: var(--encre); background: rgba(255, 255, 255, .05); }
/* la page courante : la couleur pleine du texte et un souligné, rien d'autre */
.menu a.on {
  color: var(--encre);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 7px;
  text-decoration-color: var(--action);
}

.outils { display: flex; align-items: center; gap: 10px; }
.langbtn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 13px;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  background: transparent;
  color: var(--encre-2);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  transition: color .18s, border-color .18s, background-color .18s;
}
.langbtn:hover { color: var(--encre); border-color: var(--trait); background: rgba(255, 255, 255, .03); }
.langbtn svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.7; }

/* le bouton du coin (« Se connecter ») : le bouton plein, en plus petit.
   ⚠️ Il garde sa classe `btn-2` (site.js et plusieurs bancs la nomment) ;
   c'est son rang dans la barre qui le remplit. Aplat, sans lueur. */
.entete .btn-2,
.entete .langbtn {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
}
.entete #ctaAuth {
  padding: 10px 20px;
  background-color: var(--action);
  border-color: transparent;
  color: var(--sur-action);
}
.entete #ctaAuth:hover { background-color: var(--action-vive); }
.entete #ctaAuth::before { display: none; }

/* le lien vers le tableau de bord, que `site.js` ajoute pour l'éditeur */
.navbord { font-size: 13px; color: var(--encre-3); }

/* LE MENU DE LANGUE.
   ⚠️⚠️ `position: fixed` ET REPARENTÉ sur <body> : un ancêtre filtré (la barre
   de verre) deviendrait le bloc conteneur d'un enfant `fixed`, et le menu
   partirait hors écran. Ne jamais le styler par un sélecteur de l'en-tête. */
.langmenu {
  position: fixed;
  z-index: 200;
  display: none;
  min-width: 184px;
  padding: 6px;
  border-radius: 16px;
  border: 1px solid var(--trait-fort);
  background: rgba(13, 13, 13, .88);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  backdrop-filter: blur(22px) saturate(160%);
  box-shadow: 0 12px 24px -12px rgba(0, 0, 0, .8), 0 0 0 1px rgba(0, 0, 0, .4);
}
.langmenu.open { display: block; }
.langopt {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--encre-2);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.langopt:hover { background: rgba(255, 255, 255, .05); color: var(--encre); }
.langopt.on, .langopt[aria-current="true"] {
  color: var(--encre);
  font-weight: 500;
  background: rgba(119, 119, 119, .14);
}
.langopt.on::after { content: '✓'; float: right; color: var(--bleu-clair); }

/* LE MENU DU COMPTE (17/09) : « il faut aussi que je puisse facilement me
   déconnecter de mon compte » — l'éditeur. Connecté, « Mon compte » ouvre ce
   menu (`site.js`) : qui est connecté, les Paramètres, Se déconnecter. Le
   dessin et le clavier du menu de langue, auquel il emprunte `.langmenu` et
   `.langopt` (même `fixed`, même reparentage sur <body>).
   ⚠️ SANS VERRE : il porte du texte fin (l'adresse), et du gris plat sur un
   fond flouté est ce que `t-verre` refuse. Un aplat et un bord. */
.comptemenu {
  min-width: 220px;
  max-width: calc(100vw - 16px);
  background: #141414;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.comptemenu-qui { display: grid; gap: 2px; padding: 8px 12px 10px; }
.comptemenu-qui b,
.comptemenu-qui span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.comptemenu-qui b { font-size: 14px; font-weight: 500; color: var(--encre); }
.comptemenu-qui span { font-size: 13px; color: var(--encre-3); }
.comptemenu-trait { height: 1px; margin: 6px 8px; background: var(--trait); }
.comptemenu .langopt { display: flex; align-items: center; }
.comptemenu a.langopt { color: var(--encre-2); text-decoration: none; }
.comptemenu a.langopt:hover { color: var(--encre); }
@media (max-width: 760px), (hover: none) and (pointer: coarse) {
  .comptemenu .langopt { min-height: 44px; }
}

/* ------------------------------------------------------------ méga-menu */
/* Le panneau qui se déplie sous « Applications » (`menu-deroulant.js` pose
   son `top` sur le bas de la barre). */
.megamenu {
  position: fixed;
  left: 0;
  right: 0;
  z-index: 150;
  background: rgba(9, 9, 9, .9);
  -webkit-backdrop-filter: blur(28px) saturate(170%);
  backdrop-filter: blur(28px) saturate(170%);
  border-bottom: 1px solid var(--trait);
  clip-path: inset(0 0 100% 0);
  transform: translateY(-6px);
  opacity: 0;
  transition: clip-path .32s cubic-bezier(.32, .72, .35, 1),
              transform .32s cubic-bezier(.32, .72, .35, 1),
              opacity .22s ease;
}
.megamenu.ouvert { clip-path: inset(0 0 0 0); transform: none; opacity: 1; }
.mega-dedans { width: min(100% - 48px, var(--large)); margin-inline: auto; padding: 30px 0 26px; }
.mega-titre {
  margin: 0 0 18px;
  font-size: 12px;
  font-weight: 500;
  color: var(--encre-3);
}
.mega-fam {
  margin: 22px 0 10px;
  font-size: 12px;
  font-weight: 500;
  color: var(--encre-3);
}
.mega-dedans > .mega-fam:first-child { margin-top: 4px; }
.mega-grille {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(4, auto);
  gap: 0 clamp(18px, 3vw, 44px);
}
.mega-col {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  gap: 6px;
  align-content: start;
  padding: 18px;
  border-radius: var(--r-l);
  border: 1px solid transparent;
  transition: border-color .2s, background-color .2s;
}
.mega-col:hover { border-color: var(--trait); background: rgba(255, 255, 255, .02); }
@supports not (grid-template-rows: subgrid) {
  .mega-grille { grid-template-rows: none; }
  .mega-col { grid-row: auto; display: flex; flex-direction: column; gap: 6px; }
}
.mega-app { display: flex; align-items: center; gap: 12px; }
.mega-app b { font-size: clamp(17px, 1.5vw, 20px); font-weight: 500; letter-spacing: -0.02em; }
.mega-ic {
  width: 42px;
  height: 42px;
  border-radius: var(--r-s);
  display: grid;
  place-items: center;
  background: var(--papier-3);
  box-shadow: inset 0 0 0 1px var(--trait);
}
.mega-dit { font-size: 13.5px; color: var(--encre-2); line-height: 1.5; margin-bottom: 6px; max-width: 34ch; }
.mega-lien {
  justify-self: start;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--encre-2);
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  transition: color .16s;
}
.mega-lien::after { content: ' ›'; }
.mega-lien:hover { color: var(--encre); }
.mega-tester { color: var(--bleu-clair); }
.mega-tester:hover { color: #FFBD8A; }
.mega-tout {
  display: inline-block;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--trait);
  width: 100%;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--encre-2);
}
.mega-tout:hover { color: var(--encre); }
@media (max-width: 760px) {
  .mega-grille { grid-template-columns: 1fr; grid-template-rows: none; gap: 10px; }
  .mega-col { grid-row: auto !important; padding: 12px 0; }
  .mega-fam { margin: 18px 0 8px; }
}
body.mega-ouvert main,
body.mega-ouvert .pied { filter: blur(7px); opacity: .5; }
main, .pied { transition: filter .28s ease, opacity .28s ease; }
@media (prefers-reduced-motion: reduce) {
  .megamenu { transition: opacity .15s ease; }
  main, .pied { transition: none; }
  body.mega-ouvert main, body.mega-ouvert .pied { filter: none; opacity: .5; }
}

/* ----------------------------------------------------------------- héros */
.hero {
  text-align: center;
  padding-block: clamp(56px, 9svh, 112px) clamp(40px, 6svh, 72px);
}
/* ⚠️ Pas de largeur en `ch` sur un titre à deux phrases : le `<br>` fait la
   coupe, une borne en caractères la refaisait au milieu de la première. */
.hero .display { margin: 22px auto 0; max-width: min(100%, 1000px); font-size: clamp(2.6rem, 5vw, 4.25rem); }
/* ⚠️ `--etroit` et pas une largeur en `ch` : la page Télécharger pose une
   colonne étroite plus bas, et 54ch mettait les deux bords à 12 px l'un de
   l'autre (`t-alignement`). */
.hero .sous-titre {
  margin: clamp(18px, 2vw, 26px) auto 0;
  max-width: var(--etroit);
  text-wrap: balance;
}
.hero .actions { margin-top: 32px; }
.actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.hero-note {
  margin: 16px 0 0;
  font-size: 13px;
  color: var(--encre-3);
}

/* L'ACCUEIL : le texte à gauche, le produit à droite, qui déborde du bord —
   la composition de la référence. Sous 1100 px, tout se centre et le produit
   passe dessous, dans la colonne.
   ⚠️ Les lignes du texte et le visuel sont les enfants DIRECTS de la grille :
   la chorégraphie d'ouverture de `mouvement.js` anime `[data-anim="heros"] > *`
   un par un. Un bloc de texte enveloppé entrerait d'un seul tenant. Les
   rangées 1 et 6 (en `1fr`) centrent le texte à la hauteur du visuel.
   ⚠️ DEUX LIGNES DEPUIS LE 18/09 : titre, chapeau. Les boutons et la note
   ont quitté le premier écran (« je veux un gros hook ») ; le surtitre et la
   rangée de preuves étaient partis le 17/09 avec le deuxième diagnostic « ça
   fait IA » : le héros de gabarit est parti pièce par pièce. */
.hero.hero-duo { text-align: left; padding-block: clamp(32px, 5svh, 56px) 56px; overflow: clip; }
/* Accueil large : texte et marque partagent une marge de 48 px, jusqu'à
   1 920 px de contenu. Le produit déborde à droite du viewport. */
.hero-duo .wrap { width: min(100% - 96px, 1920px); }
.hero-duo .hero-grille {
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  grid-template-rows: 1fr repeat(2, auto) 1fr;
  column-gap: clamp(32px, 3vw, 64px);
  align-items: start;
}
.hero-duo .hero-grille > * { grid-column: 1; }
.hero-duo .hero-grille > :nth-child(1) { grid-row: 2; }
.hero-duo .hero-grille > :nth-child(2) { grid-row: 3; }
.hero-duo .hero-grille > .hero-visuel { grid-column: 2; grid-row: 1 / -1; align-self: center; }
/* ⚠️ Chaque phrase du titre tient sur SA ligne (le `<br>` les sépare) : le
   corps se règle sur la plus longue en français, « Une bibliothèque 3D »
   (19 signes, 18/09) — et la colonne de texte a pris la place des boutons —, pas
   sur une largeur de caractères qui les casserait en quatre. Une langue plus
   longue passe à la ligne — jamais `nowrap`, qui la ferait déborder sur le
   visuel. */
.hero-duo .display {
  margin: 0;
  max-width: none;
  font-size: clamp(2.8rem, 4.3vw, 5.8rem);
  line-height: 1.04;
  letter-spacing: -.04em;
  text-wrap: balance;
}
.hero-duo .sous-titre {
  margin: 24px 0 0;
  max-width: 40ch;
  font-size: clamp(1rem, 1.2vw, 1.2rem);
  color: #E1D9D2;
  line-height: 1.65;
  text-wrap: pretty;
}

/* le cadre du produit : épais et liseré clair, qui déborde du bord droit.
   ⚠️ Plus de lumière floutée dessous ni d'ombre de 120 px (17/09) : un filet
   ET une ombre large sur la même surface, c'est la carte des gabarits. */
.hero-visuel {
  position: relative;
  height: clamp(600px, calc(100svh - 180px), 840px);
  width: clamp(1200px, 86vw, 1840px);
  /* Le mur d'assets continue hors écran : son échelle ne dépend pas de la
     petite colonne visible. Le maître 2560 px conserve les détails. */
  overflow: hidden;
  border-radius: 22px 0 0 0;
  mask-image: linear-gradient(#000 90%, transparent);
}
.hero-cadre {
  margin: 0;
  padding: 0;
  border-radius: 22px 0 0 0;
  background: var(--cadre);
  line-height: 0;
}
.hero-cadre img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 22px 0 0 0;
}
@media (min-width: 1101px) {
  /* Descendre le produit sans déplacer le texte ni allonger le premier écran. */
  .hero-duo .hero-visuel {
    --hero-decalage: clamp(72px, 10svh, 120px);
    margin-top: var(--hero-decalage);
    height: calc(clamp(600px, calc(100svh - 180px), 840px) - var(--hero-decalage));
  }
}
@media (max-width: 1100px) {
  /* ⚠️ UNE COLONNE, MAIS À GAUCHE : recentrer le héros sous 1 100 px
     redonnait sur tablette et téléphone la symétrie qu'on retire partout. */
  .hero.hero-duo { text-align: left; }
  .hero-duo .wrap { width: min(100% - 48px, 820px); }
  .hero-duo .hero-grille { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .hero-duo .hero-grille > * { grid-column: 1; grid-row: auto !important; }
  .hero-duo .hero-grille > .hero-visuel { grid-column: 1; margin-top: clamp(48px, 8vw, 72px); }
  .hero-duo .display { margin-inline: 0; max-width: 18ch; text-wrap: balance; font-size: clamp(2.25rem, 7.4vw, 3.7rem); }
  .hero-duo .sous-titre { margin-inline: 0; text-wrap: pretty; }
  .hero-visuel { width: max(1000px, 120vw); height: clamp(440px, 62vw, 640px); }
  .hero-cadre, .hero-cadre img { border-radius: 18px 0 0 0; }
}
@media (max-width: 600px) {
  .hero.hero-duo { padding-block: 40px 28px; }
  .hero-duo .hero-grille > .hero-visuel { margin-top: 36px; }
  .hero-duo .display { font-size: clamp(2.25rem, 8.7vw, 3.3rem); }
  .hero-visuel { width: 760px; height: 420px; }
}

/* LE BANDEAU — la tête des pages Tarifs et légales */
.bandeau { text-align: center; padding-block: clamp(52px, 8svh, 100px) clamp(40px, 6svh, 72px); }
.fil { font-size: 13px; color: var(--encre-3); margin-bottom: 20px; }
.fil a:hover { color: var(--encre); }
.bandeau .display { margin-bottom: 20px; }
.bandeau .sous-titre { max-width: 620px; margin-inline: auto; }

/* -------------------------------------------------------------- surfaces */
/* UNE CARTE : un aplat à peine levé et un filet — jamais un dégradé (voir
   `.btn-1`).
   ⚠️ GRAPHITE (17/09) : ni reflet intérieur en haut, ni ombre large sous le
   filet. Le couple « filet d'un pixel + ombre diffuse » est une signature des
   interfaces générées (`gpt-thin-border-wide-shadow`) : une surface a un bord
   OU une élévation, pas les deux. */
.carte {
  background-color: var(--papier);
  border: 1px solid var(--trait);
  border-radius: var(--r-l);
  padding: 28px;
}
/* une carte qui ne porte QU'une image devient un cadre de produit */
.carte:has(> img:only-child) {
  padding: 0 !important;
  overflow: hidden;
  border-color: rgba(185, 185, 185, .18);
}

/* LA SCÈNE — le cadre du launcher et d'AssetBrowser, vivants dans la page.
   ⚠️ Le liseré est un ANNEAU D'OMBRE (`--anneau`) : une bordure ou un padding
   changeraient la taille de l'iframe, dont la forme est calculée (16:10,
   « une forme normale mais que ce soit grand »). Plus de lueur dessous. */
.scene {
  position: relative;
  background: var(--papier);
  border-radius: 18px;
  overflow: hidden;
  width: max-content;
  max-width: calc(100% - 20px);
  margin-inline: auto;
  box-shadow: var(--anneau);
}
/* ⚠️ Au-dessus de 1 400 px, le launcher de l'accueil prend d'autres tailles,
   par paliers de hauteur d'écran : § « LE LAUNCHER AU MILIEU ». */
.cadre-app {
  display: block;
  border: 0;
  height: clamp(700px, 86svh, 800px);
  width: calc(clamp(700px, 86svh, 800px) * 1.6);
  max-width: 100%;
}
/* ⚠️⚠️ EVERYTHING ET ANIMATED NE S’ESSAIENT PAS SOUS 1 025 px (19/09) : ils
   travaillent sur les FICHIERS du visiteur, et un iPad n’y donne pas accès.
   Le bouton disparaît, le message prend sa place. Même dessin que
   `.sans-lanceur`, dont on reprend les règles de texte. */
.sans-app { display: none; padding: clamp(24px, 6vw, 36px) clamp(18px, 4vw, 28px);
  text-align: center; border: 1px solid var(--trait); border-radius: 16px; margin-top: 22px; }
.sans-app h3 { font-size: 18px; font-weight: 500; letter-spacing: -0.02em; margin: 0 0 10px; }
.sans-app p { margin: 0 auto 10px; max-width: 44ch; font-size: 14.5px; color: var(--encre-2); }
.sans-app .btn { margin-top: 8px; }
@media (max-width: 1024px) {
  .sans-app { display: block; }
  [data-essai="everything"], [data-essai="usd2skel"] { display: none; }
}

.sans-lanceur {
  display: none;
  padding: clamp(28px, 7vw, 44px) clamp(20px, 5vw, 32px);
  text-align: center;
}
.sans-lanceur h3 { font-size: 19px; font-weight: 500; letter-spacing: -0.02em; margin: 0 0 10px; }
.sans-lanceur p { margin: 0 auto 10px; max-width: 44ch; font-size: 14.5px; color: var(--encre-2); }
.sans-lanceur-cta { color: var(--encre) !important; font-weight: 500; }
.sans-lanceur .btn { margin-top: 8px; }

/* la section qui porte une scène.
   ⚠️ La lueur floutée DERRIÈRE le cadre est partie (17/09) : un halo sous une
   capture est le même réflexe qu'une ombre colorée. */
.scene-fond { position: relative; padding-bottom: clamp(56px, 7svh, 88px); }
.scene-fond > .wrap { position: relative; z-index: 1; }
.hero + .scene-fond { padding-top: clamp(24px, 4svh, 48px); }

/* les affiches et les captures posées dans une section */
.acte-affiche {
  margin: 0 auto clamp(36px, 4vw, 56px);
  max-width: 880px;
  border-radius: var(--r-l);
  overflow: hidden;
  line-height: 0;
  box-shadow: 0 0 0 1px rgba(185, 185, 185, .14);
}
.acte-affiche img { width: 100%; height: auto; display: block; }

.ab-affiche {
  margin: clamp(36px, 4vw, 56px) auto 0;
  max-width: 1000px;
  line-height: 0;
}
.ab-affiche img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 16px;
  box-shadow: var(--anneau);
}
.ab-affiche figcaption {
  margin: 26px auto 0;
  max-width: 72ch;
  font-size: 13px;
  line-height: 1.7;
  color: var(--encre-3);
  text-align: center;
}

.produit { margin: clamp(56px, 7svh, 88px) auto 0; max-width: 100%; padding: 0; }
.produit img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r-l);
  box-shadow: var(--anneau), var(--ombre-3);
}

/* LE CADRE DE LA VRAIE APPLICATION (la démonstration d'Everything).
   ⚠️ L'application s'ouvre à 1300 × 820 et n'a aucun point de rupture : le
   script la MET À L'ÉCHELLE et pose la hauteur du cadre. Donc, ici non plus,
   ni padding ni bordure — l'épaisseur est un anneau d'ombres. */
.ea {
  position: relative;
  margin: 10px auto;
  max-width: 1300px;
  border-radius: 16px;
  overflow: hidden;
  background: var(--papier);
  height: clamp(360px, 46vw, 640px);
  box-shadow: var(--anneau);
}
/* ⚠️ UNE PRÉSENTATION, PAS UN ESSAI (15/09) : le cadre est `inert` (posé par
   `demo-eapp.js`) ; `pointer-events: none` est le filet d'un navigateur qui
   ignorerait l'attribut. La molette passe à la page, pas à l'application. */
.ea-cadre {
  position: absolute;
  top: 0;
  left: 0;
  width: 1300px;
  height: 820px;
  border: 0;
  transform-origin: 0 0;
  display: block;
  pointer-events: none;
}
/* LA FENÊTRE DES PRÉSENTATIONS SUR PETIT ÉCRAN (17/09, « illisible sur iPhone
   et sur iPad ») — posée autour de `.ea` par `camera-presentations.js`, qui dit
   tout le pourquoi. Sur ordinateur elle n'a aucun style : le cadre est dessiné
   comme avant. En caméra, c'est ELLE qui porte l'arrondi, le liseré et le fond ;
   le cadre, plus large qu'elle, glisse dedans par une translation.
   ⚠️ `isolation: isolate` : Safari coupe alors l'iframe mise à l'échelle au
   rayon de la fenêtre, au lieu de laisser déborder ses coins. */
.ea-fenetre { position: relative; }
.ea-fenetre.en-camera {
  overflow: hidden;
  border-radius: 16px;
  background: var(--papier);
  box-shadow: var(--anneau);
  isolation: isolate;
}
/* ⚠️ Pas de `will-change` : trois cadres de 1 170 px à la densité d'un iPhone
   garderaient chacun un calque permanent en mémoire graphique. La transition
   de la caméra promeut le cadre le temps du mouvement, et le relâche. */
.ea-fenetre.en-camera > .ea {
  margin: 0;
  max-width: none;
  border-radius: 0;
  box-shadow: none;
}

/* l'affiche de repos : du HTML, lisible sans script */
/* ⚠️⚠️ AU TÉLÉPHONE, LA PRÉSENTATION EST UNE AFFICHE (18/09). « le sur
   téléphone doit être utilisable la c'est pas le cas du tout, les
   présentations on voit rien » : le cadre fait 342 px et l'application est
   posée à sa largeur de bureau (1 300 à 1 440), plafonnée à 0,55 pour rester
   lisible — on n'en voyait que 26 % au repos de la caméra, et pour
   AssetBrowser 67 % des textes étaient coupés par le bord (t-tablette le
   mesurait sans l'exiger). Les scripts des trois présentations n'ouvrent donc
   plus l'application sous 761 px : ils montrent une VRAIE capture du produit,
   et la note sous le cadre le dit (`demo.tel`).
   ⚠️ L'image n'a pas de `src` dans le balisage, seulement `data-src` : cachée
   par la feuille, elle se téléchargerait quand même. Sur ordinateur ces
   240 Ko ne partent pas.
   ⚠️ CE N'EST PAS LA CORRECTION DE FOND, et il faut le savoir : l'application
   est fluide (mesuré le 18/09 — à 820 px elle passe d'elle-même en deux
   colonnes, à 622 px le rail et la grille tiennent encore). La lui charger à
   la largeur du cadre ferait voir 61 % au lieu de 26 %, en gardant la vraie
   app. C'est le chantier qui touche les trois chorégraphies et `t-tablette` ;
   l'éditeur a choisi l'affiche d'abord. */
.ea-affiche { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top left; }

.ea-repos {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 24px;
  overflow: hidden;
}
.ea-lueur {
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(closest-side, rgba(106, 106, 106, .30), transparent 70%);
  pointer-events: none;
}
.ea-repos::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(182, 182, 182, .07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(182, 182, 182, .07) 1px, transparent 1px);
  background-size: 48px 48px;
  background-position: center;
  -webkit-mask-image: radial-gradient(50% 60% at 50% 50%, #000, transparent 80%);
  mask-image: radial-gradient(50% 60% at 50% 50%, #000, transparent 80%);
}
.ea-repos > p, .ea-repos > button { position: relative; z-index: 1; }
.ea-titre { margin: 0; font-size: clamp(18px, 2vw, 24px); font-weight: 500; letter-spacing: -0.02em; color: var(--encre); }
.ea-sous { margin: 0; font-size: 14px; color: var(--encre-2); }
.ea-go { margin-top: 14px; }
/* ⚠️⚠️ L'AFFICHE DIT QU'ELLE CHARGE (17/09, « je veux que toutes les
   présentations démarrent automatiquement »). Elles démarrent bien seules —
   mesuré au téléphone, les quatre s'allument sans un clic, y compris sous
   « moins de mouvement ». Mais sur un lien mobile (120 ms d'aller-retour,
   4 Mb/s, cache vide) il s'écoule près de SEPT SECONDES entre « la section
   entre à l'écran » et « ça joue » : le temps que la coque de l'application
   et son lot arrivent. Pendant ces secondes, l'affiche montrait un bouton
   grisé — et un bouton grisé se lit « mort », pas « ça arrive ».
   Un filet qui avance sous le bouton le dit, sans un mot à traduire. */
.ea-repos[data-charge] .ea-go {
  opacity: .5;
  pointer-events: none;
  position: relative;
  overflow: hidden;
}
.ea-repos[data-charge] .ea-go::after {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: 6px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: .45;
  transform-origin: left center;
  animation: ea-charge 1.4s ease-in-out infinite;
}
@keyframes ea-charge {
  0% { transform: scaleX(.06); }
  50% { transform: scaleX(1); }
  100% { transform: scaleX(.06); }
}
@media (prefers-reduced-motion: reduce) {
  .ea-repos[data-charge] .ea-go::after { animation: none; transform: scaleX(.55); }
}

/* le pointeur et le halo qui disent OÙ l'on clique dans les présentations
   (Everything et AssetBrowser : les deux scripts fabriquent ces deux éléments).
   ⚠️⚠️ « LE CURSEUR IL EST SUPER GROS ET CACHE DE FOU L'ÉCRAN » (15/09, nuit).
   Le pointeur était une bille blanche de 18 px nimbée d'une lueur de 18 px, et
   le halo une pilule de VERRE (flou, saturation, éclaircissement) posée SUR le
   contrôle visé. Photographié à 1 920 px CSS au facteur 2 : la pilule couvrait
   entièrement la pastille « .abc » qu'on cliquait, et montait à 247 × 55 px
   sur la barre des vignettes. L'instrument cachait ce qu'il devait montrer.
   · le pointeur est une FLÈCHE de curseur, 14 × 20 px, pointe sur le point
     visé ; elle s'enfonce d'un cran au clic ;
   · ⚠️ le halo n'est PLUS DESSINÉ (17/09) : « le curseur pour les
     présentations est bien mais le contour carré quand je clic non j'aime
     pas » (l'éditeur). C'était un anneau aux coins de `--r-pill`, à la taille
     du contrôle visé, allumé le temps d'un battement au clic. Le clic se lit
     désormais à la flèche qui s'enfonce, et aux états de l'application.
     L'élément reste : les quatre scripts (Everything, AssetBrowser, Animated,
     logiciels) le créent, le placent et lui posent `clic` ; il ne s'affiche
     plus, et rien ne mesure sa géométrie (vérifié dans tools/).
   ⚠️ La position vient de `transform: translate()`, posée en ligne par les
   deux scripts : le clic n'anime donc JAMAIS `scale` sur l'élément lui-même
   (il composerait avec le déplacement et ferait sauter la flèche vers le coin
   du cadre) — seulement sur son pseudo-élément, ou sur l'ombre de l'anneau. */
.ea-pointeur,
.ea-halo {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  opacity: 0;
  z-index: 3;
  will-change: transform, opacity;
}
.ea-pointeur {
  width: 14px;
  height: 20px;
  /* la pointe du dessin est à (1,4 ; 1,4) px du coin de sa boîte */
  margin: -1.4px 0 0 -1.4px;
  transition: transform .52s cubic-bezier(.22, .8, .28, 1), opacity .3s ease;
}
.ea-pointeur::before {
  content: '';
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 15 21'%3E%3Cpath d='M1.5 1.5V17.1L5.3 13.5L8.1 19.6L10.9 18.4L8.2 12.4H13.7Z' fill='%23fff' stroke='%23120a1c' stroke-width='1.25' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat 0 0 / 100% 100%;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .55));
  transform-origin: 1.4px 1.4px;
  transition: scale .12s ease;
}
.ea-pointeur.on { opacity: 1; }
.ea-pointeur.clic::before { scale: .86; }
.ea-halo { display: none; }
/* ⚠️ AU TÉLÉPHONE, LA CAMÉRA ZOOME LE CADRE (le plan large de
   `camera-presentations.js`) : la flèche y rétrécirait avec l'application.
   Son dessin reçoit l'inverse du zoom, autour de sa pointe (`transform-origin`
   ci-dessus), et garde sa taille à l'écran. `--z-camera` est DÉCLARÉE pour
   s'animer avec la caméra ; sans `@property` (Safari avant 16.4), la flèche
   change de taille en 0,12 s au départ du mouvement. */
@property --z-camera {
  syntax: '<number>';
  inherits: true;
  initial-value: 1;
}
.ea-fenetre.en-camera .ea-pointeur::before { scale: calc(1 / var(--z-camera, 1)); }
.ea-fenetre.en-camera .ea-pointeur.clic::before { scale: calc(.86 / var(--z-camera, 1)); }
/* LE DOSSIER QUE LE POINTEUR GLISSE DANS L'APPLICATION (15/09, nuit : « je
   veux que ca soit un icon de dossier ») — l'icône au-dessus, son nom
   dessous, comme un dossier qu'on tire de l'explorateur.
   ⚠️ La légende est un APLAT, pas du verre : elle passe au-dessus de
   l'interface, et `t-verre` refuse un verre plus petit qui floute plus qu'un
   plus grand.
   ⚠️ L'ombre suit la SILHOUETTE du dossier (`drop-shadow`), pas une boîte :
   une ombre rectangulaire sous une icône à onglet se lit comme un cadre. */
.ea-glisse {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  opacity: 0;
  pointer-events: none;
  white-space: nowrap;
  transition: transform 1.2s cubic-bezier(.3, .7, .2, 1), opacity .35s ease, scale .28s ease;
  will-change: transform;
}
.ea-glisse.on { opacity: 1; }
.ea-glisse.tenu { scale: .94; }
.ea-glisse.lache { opacity: 0; scale: .5; transition: opacity .24s ease, scale .24s ease; }
.eg-dossier {
  display: block;
  width: 92px;
  height: 74px;
  filter: drop-shadow(0 12px 14px rgba(0, 0, 0, .55));
}
.eg-t {
  display: grid;
  justify-items: center;
  gap: 1px;
  line-height: 1.2;
  padding: 5px 11px 6px;
  border-radius: 10px;
  background: #151515;
  border: 1px solid rgba(192, 192, 192, .30);
  box-shadow: 0 6px 12px -6px rgba(0, 0, 0, .8);
}
.eg-t b { font-size: 13.5px; font-weight: 500; color: var(--encre); }
.eg-t small { font-size: 12px; color: var(--encre-2); }
/* ⚠️ Le dossier vit sur la PAGE, pas dans l'application : il n'est pas réduit
   avec elle. Sur téléphone l'application est à 0,55 et le dossier à pleine
   taille couvrait la moitié du panneau (capture à 390 px) — on le réduit. */
@media (max-width: 760px) {
  .eg-dossier { width: 64px; height: 51px; }
  .eg-t { padding: 4px 9px 5px; }
  .eg-t b { font-size: 12.5px; }
  .eg-t small { font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) { .ea-glisse { display: none; } }

/* ⚠️ LA LÉGENDE D'ÉTAPE NE SE VOIT PLUS, ELLE SE LIT : c'est la liste
   `.ev-etapes` à côté du cadre qui montre l'étape en cours. Masquée à la façon
   d'un texte pour lecteur d'écran — jamais `display: none`, qui la ferait
   taire aussi. */
.ea-etape {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ⚠️⚠️ L'interrupteur : sans lui, `t-mouvement-reduit` rougit — et le script,
   lui, ne fabrique même pas le pointeur dans ce cas. */
@media (prefers-reduced-motion: reduce) {
  .ea-pointeur,
  .ea-halo { display: none; }
}
/* les bibliothèques lues, en pastilles qui s'allument */
.ea-sources {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 7px;
  margin: 0 0 clamp(22px, 2.4vw, 32px);
  padding: 0;
  list-style: none;
  min-height: 28px;
}
.ea-src {
  padding: 5px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .02);
  color: var(--encre-3);
  font-size: 12.5px;
  opacity: .5;
  transition: opacity .35s ease, color .35s ease, border-color .35s ease, background-color .35s ease;
}
.ea-src.on {
  opacity: 1;
  color: var(--encre);
  border-color: rgba(179, 179, 179, .45);
  background: rgba(119, 119, 119, .10);
}
@media (prefers-reduced-motion: reduce) {
  .ea-src { transition: none; }
}
.ea-vrai {
  margin: clamp(12px, 1.6vw, 18px) auto 0;
  max-width: 640px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--encre-2);
}
@media (max-width: 760px) {
  .ea { height: clamp(300px, 92vw, 460px); }
  .ea-vrai { font-size: 13px; }
}

/* ------------------------------------------------------ les chiffres */
/* La rangée de la référence (« 99.9% Uptime | 400k+ Active Users ») : de
   grands nombres fins, séparés par un filet vertical.
   ⚠️ Aucun nombre n'est inventé : les quatre viennent du dictionnaire, avec
   leur source écrite dessous (`ch.source`). */
.chiffres {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: clamp(40px, 5vw, 64px) 0 0;
  border-top: 1px solid var(--trait);
  border-bottom: 1px solid var(--trait);
}
.ch-case {
  text-align: left;
  padding: clamp(26px, 3vw, 40px) clamp(18px, 2.4vw, 34px);
}
.ch-case + .ch-case { border-left: 1px solid var(--trait); }
.ch-n {
  display: block;
  font-size: clamp(2.5rem, 4.6vw, 3.9rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.045em;
  color: var(--encre);
  font-variant-numeric: tabular-nums;
}
.ch-t {
  display: block;
  margin: 14px 0 0;
  max-width: 24ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--encre-2);
}
/* ⚠️ 640 px, comme `.ea-vrai` juste au-dessus : deux notes centrées de
   largeurs voisines (74ch et 68ch, corps différents) posaient leurs bords à
   2 px l'un de l'autre — le « presque aligné » que `t-alignement` refuse. */
.ch-source {
  margin: clamp(26px, 3vw, 38px) auto 0;
  max-width: 640px;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--encre-3);
}
@media (max-width: 860px) {
  .chiffres { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ch-case:nth-child(3) { border-left: 0; }
  .ch-case:nth-child(n + 3) { border-top: 1px solid var(--trait); }
}

/* ------------------------------------------------------ les trois gestes */
.gestes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 1.6vw, 20px);
  margin-top: clamp(32px, 4vw, 52px);
  text-align: left;
}
@media (max-width: 780px) { .gestes { grid-template-columns: 1fr; gap: 12px; } }
.geste {
  position: relative;
  padding: 26px 26px 28px;
  border-radius: var(--r-l);
  border: 1px solid var(--trait);
  background-color: var(--papier);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.geste .n {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-bottom: 20px;
  border-radius: 50%;
  border: 1px solid rgba(179, 179, 179, .38);
  background: rgba(119, 119, 119, .12);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  color: var(--bleu-clair);
  font-variant-numeric: tabular-nums;
}
.geste > b { display: block; font-size: 16.5px; font-weight: 500; margin-bottom: 8px; letter-spacing: -0.016em; color: var(--encre); }
.geste span:not(.n) { display: block; font-size: 14px; color: var(--encre-2); line-height: 1.6; }
.geste span b { color: var(--encre); font-weight: 500; }

/* ------------------------------------------------ les cartes de temps */
.mosaique { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
@media (max-width: 900px) { .mosaique { grid-template-columns: 1fr; } }
.mosaique.duo { grid-template-columns: repeat(2, 1fr); max-width: 900px; margin-inline: auto; }
@media (max-width: 900px) { .mosaique.duo { grid-template-columns: 1fr; } }
/* les lignes des cartes s'alignent d'une carte à l'autre */
@media (min-width: 901px) {
  .mosaique { grid-template-rows: auto auto auto auto 1fr auto auto; }
  .mosaique > .carte-gain {
    grid-row: span 7;
    display: grid;
    grid-template-rows: subgrid;
    align-content: start;
  }
  .mosaique > .carte-gain > * { margin-top: 0; margin-bottom: 0; }
}
.carte-gain {
  position: relative;
  padding: clamp(24px, 2.2vw, 30px);
  border-radius: var(--r-l);
  border: 1px solid var(--trait);
  background-color: var(--papier);
  text-align: left;
}
.carte-gain > * { position: relative; }
.carte-gain-tete { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
.carte-gain-tete img { width: 32px; height: 32px; }
.carte-gain-tete b { font-size: 14.5px; font-weight: 500; letter-spacing: -0.02em; }
.carte-gain .gain {
  display: block;
  font-size: clamp(2rem, 3.2vw, 2.6rem);
  font-weight: 400;
  letter-spacing: -0.045em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.carte-gain .gain-lg { display: block; font-size: 13px; color: var(--encre-2); margin-top: 8px; }
.carte-gain .reglage { margin-top: 20px; }
.carte-gain .reglage-tete {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 13px;
  color: var(--encre-2);
  margin-bottom: 6px;
}
.carte-gain .reglage-tete b { font-variant-numeric: tabular-nums; color: var(--encre); font-weight: 500; }
.bilan { display: grid; gap: 4px; margin-top: 14px; font-size: 13px; }
.bilan div { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.bilan span { color: var(--encre-2); }
.bilan b { color: var(--encre); font-weight: 500; font-variant-numeric: tabular-nums; }
.postes {
  list-style: none;
  margin: 16px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--trait);
  display: grid;
  gap: 6px;
  min-height: calc(var(--lignes, 3) * 22px);
}
.postes li {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 46px 30px;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  line-height: 1.35;
}
.postes b { font-weight: 500; color: var(--encre); font-variant-numeric: tabular-nums; }
.postes span { color: var(--encre-2); }
.postes .part {
  display: block;
  height: 3px;
  border-radius: 999px;
  background: rgba(177, 177, 177, .12);
  position: relative;
  overflow: hidden;
}
.postes .part::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--part, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--bleu), var(--bleu-clair));
}
.postes em {
  font-style: normal;
  font-size: 11.5px;
  text-align: right;
  color: var(--encre-2);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 420px) {
  .postes li { grid-template-columns: 54px minmax(0, 1fr); }
  .postes .part, .postes em { display: none; }
}

/* la glissière */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 22px;
  background: transparent;
  cursor: pointer;
  margin: 0;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--bleu-vif) var(--p, 50%), rgba(177, 177, 177, .14) var(--p, 50%));
}
input[type="range"]::-moz-range-track { height: 4px; border-radius: 999px; background: rgba(177, 177, 177, .14); }
input[type="range"]::-moz-range-progress { height: 4px; border-radius: 999px; background: var(--bleu-vif); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  margin-top: -7px;
  border-radius: 50%;
  background: #fff;
  border: 0;
  box-shadow: 0 0 0 4px rgba(119, 119, 119, .35), 0 4px 12px rgba(0, 0, 0, .5);
  transition: transform .12s ease-out, box-shadow .12s ease-out;
}
input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  border: 0;
  box-shadow: 0 0 0 4px rgba(119, 119, 119, .35), 0 4px 12px rgba(0, 0, 0, .5);
  transition: transform .12s ease-out, box-shadow .12s ease-out;
}
input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.2); box-shadow: 0 0 0 7px rgba(119, 119, 119, .35), 0 4px 12px rgba(0, 0, 0, .5); }
input[type="range"]:active::-moz-range-thumb { transform: scale(1.2); box-shadow: 0 0 0 7px rgba(119, 119, 119, .35), 0 4px 12px rgba(0, 0, 0, .5); }

/* les bibliothèques à choisir sous la glissière */
.choix { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 16px; }
.choix button {
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .025);
  color: var(--encre-2);
  padding: 5px 12px;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color .16s, color .16s, border-color .16s, transform .1s ease-out;
}
.choix button:hover { color: var(--encre); border-color: var(--trait-fort); }
.choix button:active { transform: scale(.96); }
.choix button[aria-pressed="true"] { background: var(--action); border-color: transparent; color: var(--sur-action); }

/* ---------------------------------------------------------------- la FAQ */
/* ⚠️ Tout fermé au chargement, un seul rang (deux colonnes font sauter la
   voisine à chaque ouverture), et un filet EN HAUT de chaque entrée. */
.faq { max-width: 860px; margin: 0 auto; }
.faq-item {
  border: 1px solid var(--trait);
  border-radius: 16px;
  background-color: var(--papier);
  transition: border-color .2s, background-color .2s;
}
.faq-item + .faq-item { margin-top: 10px; }
.faq-item[open] { border-color: var(--trait-fort); background-color: #0F0F0F; }
.faq-item > summary {
  display: flex;
  align-items: center;
  gap: 16px;
  list-style: none;
  cursor: pointer;
  padding: 20px 22px;
  font-size: clamp(1rem, 1.15vw, 1.0625rem);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.012em;
  color: var(--encre);
  border-radius: 16px;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary:hover { color: #fff; }
.faq-item > summary:focus-visible { outline: 2px solid var(--bleu-clair); outline-offset: -2px; }
.faq-item > summary .signe {
  flex: none;
  margin-left: auto;
  position: relative;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--trait-fort);
  background: rgba(255, 255, 255, .02);
  transition: background-color .2s, border-color .2s;
}
.faq-item[open] > summary .signe { background: rgba(119, 119, 119, .16); border-color: rgba(179, 179, 179, .45); }
.faq-item > summary .signe::before,
.faq-item > summary .signe::after {
  content: '';
  position: absolute;
  left: 8px;
  right: 8px;
  top: 50%;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transform: translateY(-50%);
  transition: transform .26s cubic-bezier(.16, 1, .3, 1), opacity .2s ease;
}
.faq-item > summary .signe::after { transform: translateY(-50%) rotate(90deg); }
.faq-item[open] > summary .signe::after { transform: translateY(-50%) rotate(0deg); opacity: 0; }
.faq-item > .faq-r {
  margin: 0;
  padding: 0 60px 22px 22px;
  max-width: 72ch;
  color: var(--encre-2);
  font-size: 15px;
  line-height: 1.7;
}
@keyframes faq-ouvre {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
.faq-item[open] > .faq-r { animation: faq-ouvre .3s cubic-bezier(.16, 1, .3, 1); }
.faq-sortie {
  margin: clamp(30px, 3.4vw, 44px) 0 0;
  font-size: 14px;
  color: var(--encre-3);
}
.faq-sortie a { color: var(--bleu-clair); text-decoration: underline; text-underline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .faq-item > summary .signe::before,
  .faq-item > summary .signe::after { transition: none; }
  .faq-item[open] > .faq-r { animation: none; }
}

/* ------------------------------------------ la barre d'appel qui suit */
/* ⚠️ Discrète par construction, et ABSENTE au repos (`visibility: hidden`
   la retire du parcours clavier). `bottom` tient compte de l'encoche.
   ⚠️ DANS LE COIN, PLUS AU MILIEU (15/09) : centrée, elle se posait sur
   l'axe de chaque section et en couvrait le contenu — et c'était un objet
   symétrique de plus sur une page qui ne doit plus l'être. */
.barre-appel {
  position: fixed;
  right: calc(22px + env(safe-area-inset-right, 0px));
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 8px 8px 8px 22px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait-fort);
  background: rgba(10, 10, 10, .78);
  -webkit-backdrop-filter: var(--verre-moyen);
  backdrop-filter: var(--verre-moyen);
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, .9);
  visibility: hidden;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .34s ease, transform .34s cubic-bezier(.16, 1, .3, 1), visibility 0s linear .34s;
}
.barre-appel.ba-on {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition-delay: 0s;
}
/* ⚠️ 500, pas 400 : du texte gris PLAT sur du verre est ce que `t-verre`
   refuse (la vibrance) */
.ba-t { font-size: 13.5px; font-weight: 500; color: var(--encre-2); white-space: nowrap; }
/* ⚠️ 44 px : le plancher du pouce, mesuré par `t-iphone` */
.ba-b { min-height: 44px; white-space: nowrap; }
@media (max-width: 720px) {
  .barre-appel {
    left: 12px;
    right: 12px;
    transform: translateY(14px);
    padding: 8px;
    justify-content: center;
  }
  .barre-appel.ba-on { transform: translateY(0); }
  .ba-t { display: none; }
  .ba-b { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .barre-appel { transition: opacity .01s linear, visibility 0s linear .01s; }
  .barre-appel.ba-on { transition-delay: 0s; }
}

/* ------------------------------------------------- listes et mentions */
.bandeau-sources {
  margin: 0;
  font-size: 14px;
  line-height: 2;
  color: var(--encre-2);
}
.liste-points {
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
  display: grid;
  gap: 12px;
  font-size: 14.5px;
  color: var(--encre-2);
  line-height: 1.6;
}
.liste-points li { padding-left: 20px; position: relative; }
.liste-points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .62em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--encre-3);
}
.liste-points b { color: var(--encre); font-weight: 500; }

/* ----------------------------------------------------------------- grilles */
.grille { display: grid; gap: 16px; }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 880px) { .g3, .g2 { grid-template-columns: 1fr; } }

/* ------------------------------------------------ la page Applications */
/* le dock des trois applications, sous le titre */
.dock {
  display: inline-flex;
  gap: 4px;
  padding: 5px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .025);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.dock a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 7px 18px 7px 8px;
  border-radius: var(--r-pill);
  font-size: 14.5px;
  font-weight: 450;
  color: var(--encre-2);
  transition: background-color .18s, color .18s, transform .12s ease-out;
}
.dock a img { width: 30px; height: 30px; }
.dock a:hover { color: var(--encre); background: rgba(255, 255, 255, .06); }
.dock a:active { transform: scale(.97); }

/* ⚠️ LES PANNEAUX `.appsec` DE L'ANCIENNE PAGE APPLICATIONS NE SONT PLUS
   (15/09, nuit) : la page est faite de chapitres (`.pa-*`, fin de feuille).
   Le médaillon, lui, sert encore à assetbrowser.html. */
.medaillon {
  width: 64px;
  height: 64px;
  border-radius: 18px;
  display: grid;
  place-items: center;
  background: var(--papier-3);
  box-shadow: inset 0 0 0 1px var(--trait-fort);
  margin-bottom: 22px;
}
.medaillon img { width: 46px; height: 46px; }

/* TROIS PROMESSES. Pleine largeur (page AssetBrowser), trois cartes côte à
   côte dont les rangées s'alignent ; dans la colonne d'une application, UNE
   carte et trois lignes séparées d'un filet — trois cartes dans 480 px en
   donnaient deux et une orpheline. */
.claims {
  margin-top: 26px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto auto auto;
  gap: 12px;
}
.claim {
  padding: 22px 20px 24px;
  display: grid;
  gap: 6px;
  align-content: start;
  grid-row: span 3;
  grid-template-rows: subgrid;
  border-radius: 16px;
  border: 1px solid var(--trait);
  background-color: var(--papier);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.claim::before {
  content: '';
  width: 8px;
  height: 8px;
  margin-bottom: 8px;
  border-radius: 50%;
  background: var(--encre-3);
}
.claim b { font-size: 14.5px; font-weight: 500; color: var(--encre); line-height: 1.35; }
.claim span { font-size: 13.5px; color: var(--encre-2); line-height: 1.55; }
.grille .claims {
  grid-template-columns: 1fr;
  grid-template-rows: none;
  gap: 0;
  border-radius: 16px;
  border: 1px solid var(--trait);
  background-color: var(--papier);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
  overflow: hidden;
}
.grille .claim {
  grid-row: auto;
  grid-template-rows: none;
  grid-template-columns: 14px minmax(0, 1fr);
  column-gap: 12px;
  row-gap: 4px;
  padding: 16px 18px;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.grille .claim + .claim { border-top: 1px solid var(--trait); }
.grille .claim::before { grid-row: 1 / span 2; margin: 6px 0 0; }
.grille .claim b, .grille .claim span { grid-column: 2; }
@media (max-width: 900px) {
  .claims { grid-template-columns: 1fr; }
  .claim { grid-row: auto; grid-template-rows: none; }
}

/* -------------------------------- l'essai d'une application, par-dessus */
.essai-fond {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(7, 3, 11, .74);
  -webkit-backdrop-filter: blur(40px) saturate(160%);
  backdrop-filter: blur(40px) saturate(160%);
  display: grid;
  place-items: center;
  padding: 14px;
  animation: essai-voile .42s cubic-bezier(.32, .72, .35, 1);
}
@keyframes essai-voile {
  from { opacity: 0; }
  to { opacity: 1; }
}
.essai-panneau:focus,
.essai-panneau:focus-visible { outline: none; }
.essai-panneau {
  position: relative;
  width: auto;
  height: auto;
  border-radius: var(--r-l);
  animation: essai-entre .52s cubic-bezier(.22, 1.18, .36, 1);
}
/* ⚠️ Plus de flou à l'entrée (17/09) : une fenêtre qui arrive floue puis se
   précise est l'entrée par défaut des pages générées. Un fondu et un léger
   agrandissement suffisent. */
@keyframes essai-entre {
  from { opacity: 0; transform: scale(.97); }
  to { opacity: 1; transform: scale(1); }
}
/* ⚠️ Pas de liseré blanc autour de l'application (« je veux pas un carré
   blanc autour de l'app ») : un filet gris à peine visible, sans lueur. */
.essai-echelle {
  overflow: hidden;
  border-radius: var(--r-l);
  border: 0;
  box-shadow: 0 0 0 1px rgba(185, 185, 185, .16);
}
.essai-app { display: block; border: 0; background: #101014; transform-origin: 0 0; }
.essai-attente {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: grid;
  place-items: center;
  background: #101014;
  border-radius: inherit;
  pointer-events: none;
}
.essai-rond {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2px solid rgba(179, 179, 179, .18);
  border-top-color: rgba(179, 179, 179, .85);
  animation: essai-tourne .8s linear infinite;
}
@keyframes essai-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .essai-fond, .essai-panneau { animation: none; }
  .essai-rond { animation: none; border-top-color: rgba(179, 179, 179, .5); }
}
/* le mur du compte (`.mur-compte`) est parti le 15/09 : « Tester » mène droit
   à la page Compte, qui dit elle-même quelle application s'ouvre après. */

/* ------------------------------------------------------------- tarifs */
/* LE SEGMENT MENSUEL / ANNUEL — la pilule de la navigation, avec une lentille
   qui glisse sous le choix. */
.segment {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  padding: 5px;
  gap: 0;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .025);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
.segment::before {
  content: '';
  position: absolute;
  z-index: -1;
  top: 5px;
  bottom: 5px;
  left: 5px;
  width: calc(50% - 5px);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .075);
  box-shadow: inset 0 0 0 1px rgba(192, 192, 192, .12), inset 0 1px 0 rgba(255, 255, 255, .08);
  transition: transform .44s cubic-bezier(.32, .72, .35, 1);
}
.segment:has(button:nth-child(2).on)::before,
.segment:has(button:nth-child(2)[aria-pressed="true"])::before { transform: translateX(100%); }
@media (prefers-reduced-motion: reduce) { .segment::before { transition: none; } }
.segment button {
  border: 0;
  background: transparent;
  flex: 1 1 0;
  min-width: 0;
  padding: 8px 22px;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: 14px;
  font-weight: 450;
  color: var(--encre-2);
  cursor: pointer;
  transition: color .2s;
}
.segment button[aria-pressed="true"], .segment button.on { color: var(--encre); font-weight: 500; }
.economie { color: var(--vert); font-size: 14px; font-weight: 500; }

/* LES CARTES DE TARIF — leurs sept rangées s'alignent d'une carte à l'autre */
.tarifs { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; align-items: start; }
@supports (grid-template-rows: subgrid) {
  @media (min-width: 1081px) {
    .tarifs { grid-template-rows: repeat(7, auto); align-items: stretch; }
    .tarifs > .plan {
      display: grid;
      grid-row: span 7;
      grid-template-rows: subgrid;
      align-content: start;
    }
    .tarifs > .plan > .plan-tete { grid-row: 1; }
    .tarifs > .plan > .sieges { grid-row: 2; }
    .tarifs > .plan > .prix { grid-row: 3; align-self: start; }
    .tarifs > .plan > .plan-lead { grid-row: 4; align-self: start; }
    .tarifs > .plan > .btn { grid-row: 5; align-self: start; }
    .tarifs > .plan > hr { grid-row: 6; }
    .tarifs > .plan > .liste { grid-row: 7; align-self: start; }
  }
}
@media (max-width: 1080px) { .tarifs { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .tarifs { grid-template-columns: 1fr; } }

/* ⚠️ `.plan` EST INTERDIT comme sélecteur de carte : la classe désigne aussi
   la pastille de plan du compte (`.chip.plan`). Les cartes, c'est `.pcard`. */
.pcard {
  position: relative;
  overflow: hidden;
  padding: 28px 24px 30px;
  border-radius: var(--r-l);
  border: 1px solid var(--trait);
  background-color: var(--papier);
}
.pcard > * { position: relative; z-index: 1; }
/* la carte recommandée : un fond un cran plus levé et un filet orange.
   ⚠️ GRAPHITE (17/09) : plus de lumière qui tombe du haut ni d'ombre large,
   la « carte vedette qui rayonne » des pages de tarifs générées. */
.pcard.vedette {
  border-color: rgba(255,133,51, .55);
  background-color: #111111;
}
.plan-tete { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.plan-nom { font-size: 15px; font-weight: 500; letter-spacing: -0.01em; }
.puce {
  font-size: 11.5px;
  font-weight: 500;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: var(--action);
  color: var(--sur-action);
}
.prix { display: flex; align-items: baseline; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.prix b {
  font-size: clamp(2.1rem, 2.9vw, 2.6rem);
  font-weight: 400;
  letter-spacing: -0.045em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.prix b small { font-size: 13px; font-weight: 400; letter-spacing: normal; color: var(--encre-2); }
.prix span { font-size: 13.5px; color: var(--encre-2); }
.plan-lead { font-size: 14px; color: var(--encre-2); line-height: 1.55; margin-bottom: 22px; min-height: 42px; }
.pcard .btn { margin-bottom: 24px; }
.pcard hr { border: 0; border-top: 1px solid var(--trait); margin: 0 0 20px; }
.liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.liste li { display: flex; gap: 10px; font-size: 14px; line-height: 1.45; color: var(--encre-2); }
.liste svg { width: 15px; height: 15px; flex: none; margin-top: 2px; stroke: var(--bleu-clair); fill: none; stroke-width: 2.4; }
.liste b { color: var(--encre); font-weight: 500; }

/* le sélecteur de postes de la carte Studio */
.pcard .sieges {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 16px;
  font-size: 13.5px;
  color: var(--encre-2);
}
.pcard .sieges button {
  width: 32px;
  height: 32px;
  display: inline-grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--trait-fort);
  background: rgba(255, 255, 255, .03);
  color: var(--encre);
  font: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.pcard .sieges button:hover { border-color: rgba(179, 179, 179, .5); background: rgba(119, 119, 119, .12); }
.pcard .sieges b { min-width: 2ch; text-align: center; font-weight: 500; color: var(--encre); font-variant-numeric: tabular-nums; }

/* L'ESTIMATION DU TEMPS RÉCUPÉRÉ */
.estim {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0;
  align-items: center;
  padding: clamp(26px, 3vw, 38px) clamp(24px, 3vw, 40px);
  border-radius: var(--r-l);
  border: 1px solid var(--trait);
  background-color: var(--papier);
}
.estim-reglage { padding-right: clamp(24px, 4vw, 56px); }
.estim-lecture {
  text-align: right;
  padding-left: clamp(24px, 4vw, 56px);
  border-left: 1px solid var(--trait);
}
.estim-tete { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 20px; gap: 14px; }
.estim-tete b { font-size: 15.5px; font-weight: 500; letter-spacing: -0.012em; }
.estim-tete span { font-size: 14px; color: var(--encre-2); font-variant-numeric: tabular-nums; font-weight: 500; }
.graduations { display: flex; justify-content: space-between; margin-top: 12px; }
.graduations span { font-size: 12px; color: var(--encre-3); font-variant-numeric: tabular-nums; }
.estim-chip { display: block; font-size: 12.5px; font-weight: 500; color: var(--encre-3); margin-bottom: 12px; }
.estim-lecture b {
  display: block;
  line-height: 1;
  font-size: clamp(2.5rem, 3.8vw, 3.3rem);
  font-weight: 400;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}
.estim-lecture small { display: block; margin-top: 12px; color: var(--encre-2); font-size: 13px; }
@media (max-width: 760px) {
  .estim { grid-template-columns: 1fr; }
  .estim-reglage { padding-right: 0; }
  .estim-lecture { text-align: left; padding-left: 0; border-left: 0; border-top: 1px solid var(--trait); padding-top: 22px; margin-top: 26px; }
}

/* LE TABLEAU COMPARATIF */
.cadre-table { overflow-x: auto; }
.compare { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 640px; table-layout: fixed; }
.compare th:first-child { width: 28%; }
.compare thead th {
  font-size: 13px;
  font-weight: 500;
  color: var(--encre-2);
  padding: 0 14px 16px;
  text-align: center;
}
.compare thead th:first-child { text-align: left; }
.compare .groupe td {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--bleu-clair);
  padding: 26px 14px 10px;
}
.compare tbody td {
  padding: 14px;
  border-top: 1px solid var(--trait);
  text-align: center;
  color: var(--encre-2);
}
.compare tbody td:first-child { text-align: left; color: var(--encre); }
.compare tbody .groupe td:first-child { color: var(--bleu-clair); }
/* la colonne Pro, éclairée comme sa carte */
.compare th:nth-child(3), .compare td:nth-child(3) { background: rgba(119, 119, 119, .07); color: var(--encre); }
@media (min-width: 761px) {
  .cadre-table { overflow-x: visible; }
  .compare thead th {
    position: sticky;
    top: var(--entete-h);
    z-index: 3;
    padding-top: 14px;
    background: var(--papier-2);
  }
  .compare thead th:nth-child(3) { background: #0F0F0F; }
}

/* LA BANNIÈRE DU MODE D'ESSAI DE STRIPE — ambre, jamais bleue : c'est un
   avertissement, pas une décoration. ⚠️ `[hidden]` doit battre `display:flex`
   (`t-essai`) : sinon elle s'afficherait en mode réel. */
.ban-essai {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 26px;
  margin-inline: auto;
  padding: 13px 16px;
  max-width: 62ch;
  text-align: left;
  border: 1px solid var(--avert-trait);
  border-radius: var(--r-s);
  background: var(--avert-fond);
  color: var(--avert);
  font-size: .92rem;
  line-height: 1.5;
}
.ban-essai svg {
  width: 18px; height: 18px; flex: none; margin-top: 1px;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}
.ban-essai[hidden] { display: none; }

/* LA BOÎTE DE CONSENTEMENT AVANT PAIEMENT (tarifs.js) */
.accords-boite {
  width: min(100% - 28px, 470px);
  padding: clamp(24px, 3vw, 32px);
  border: 1px solid var(--trait-fort);
  border-radius: var(--r-l);
  background: var(--papier);
  color: var(--encre);
}
.accords-boite::backdrop {
  background: rgba(7, 3, 11, .6);
  -webkit-backdrop-filter: blur(40px) saturate(160%);
  backdrop-filter: blur(40px) saturate(160%);
}
.accords-boite h2 { font-size: 1.2rem; letter-spacing: -0.02em; margin: 0 0 6px; }
.accords-plan { margin: 0 0 18px; font-size: 13px; color: var(--encre-2); font-weight: 500; }
.accords-boite .accords { margin: 0 0 20px; }
.accords-pied { display: flex; gap: 10px; justify-content: flex-end; }
@media (max-width: 420px) {
  .accords-pied { flex-direction: column-reverse; }
  .accords-pied .btn { width: 100%; }
}

/* ---------------------------------------------------------- télécharger */
.dl-meta { margin: 18px 0 0; font-size: 13.5px; color: var(--encre-2); font-variant-numeric: tabular-nums; }
.dl-note { margin: 10px 0 0; font-size: 13px; color: var(--encre-3); }
.dl-tete { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.dl-tete img { width: 40px; height: 40px; flex: none; }
.dl-tete h2 { margin: 0; }
/* ⚠️ LA PASTILLE « DISPONIBLE » SE POSE AU PIED DE SA CARTE. Les trois cartes
   ont la même hauteur (la rangée s'étire), mais pas la même phrase : celle
   d'AssetBrowser tient sur trois lignes, sa pastille tombait 22 px plus bas
   que ses voisines. Depuis l'ordre du 15/09, elle est AU MILIEU — un creux
   entre deux pastilles alignées. */
.carte[data-app] { display: flex; flex-direction: column; }
.carte[data-app] > .chip { margin-top: auto; align-self: flex-start; }
.empreinte { margin: 12px 0 0; }
.empreinte > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  list-style: none;
  cursor: pointer;
  font-size: 13px;
  color: var(--encre-3);
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid transparent;
  transition: color .18s ease, background-color .18s ease, border-color .18s ease;
}
.empreinte > summary::-webkit-details-marker { display: none; }
.empreinte > summary::before {
  content: '';
  width: 6px; height: 6px; flex: none;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg) translate(-1px, -1px);
  transition: transform .22s cubic-bezier(.16, 1, .3, 1);
}
.empreinte[open] > summary::before { transform: rotate(45deg) translate(-2px, -2px); }
.empreinte > summary:hover { color: var(--encre); background: rgba(255, 255, 255, .03); border-color: var(--trait); }
.empreinte > summary:focus-visible { outline: 2px solid var(--bleu-clair); outline-offset: 2px; }
.empreinte > p {
  margin: 8px auto 0;
  max-width: 62ch;
  font-size: 12px;
  line-height: 1.7;
  color: var(--encre-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  word-break: break-all;
  background: var(--papier);
  border: 1px solid var(--trait);
  border-radius: var(--r-s);
  padding: 10px 13px;
}
.empreinte:not([open]) > p { display: none; }
@media (prefers-reduced-motion: reduce) {
  .empreinte > summary, .empreinte > summary::before { transition: none; }
}

/* ------------------------------------------------------- formulaires */
.champ { display: block; margin-bottom: 16px; }
.champ > span, .champ > label {
  display: block;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--encre-3);
  margin-bottom: 8px;
}
input[type="text"], input[type="email"], input[type="password"], input[type="number"], select, textarea {
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--r-s);
  border: 1px solid var(--trait-fort);
  background: #0A0A0A;
  color: var(--encre);
  font: inherit;
  font-size: 15px;
  transition: border-color .16s, box-shadow .16s;
}
input::placeholder, textarea::placeholder { color: var(--encre-3); }
/* ⚠️ Le repère de focus est une bordure BLEUE et un anneau — jamais un
   `outline: 0` nu sur tous les champs, qui retirerait le repère clavier des
   cases et des glissières. */
input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus,
input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus,
input[type="url"]:focus, input:not([type]):focus, select:focus, textarea:focus {
  outline: 0;
  border-color: rgba(164, 164, 164, .8);
  box-shadow: 0 0 0 4px rgba(119, 119, 119, .22);
}

.onglets {
  display: flex;
  padding: 5px;
  gap: 2px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .025);
  border: 1px solid var(--trait);
  margin-bottom: 24px;
}
.onglets button {
  flex: 1;
  border: 0;
  background: transparent;
  padding: 9px 14px;
  border-radius: var(--r-pill);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--encre-2);
  cursor: pointer;
  transition: background-color .2s, color .2s, box-shadow .2s;
}
.onglets button[aria-selected="true"], .onglets button.on {
  background: rgba(255, 255, 255, .075);
  color: var(--encre);
  box-shadow: inset 0 0 0 1px rgba(192, 192, 192, .12);
}

/* S'IDENTIFIER — une colonne, une carte éclairée par le haut */
/* ⚠️ LE BOUTON DANS LE PREMIER ÉCRAN : arrivé par « Tester », le visiteur lit
   quatre lignes de plus (l'application qui s'ouvre, pourquoi un compte) ; à
   1 440 × 900, « Créer mon compte » tombait sous le pli. */
.cpt { padding-block: clamp(26px, 4.4svh, 72px) clamp(60px, 10svh, 120px); }
.cpt-colonne { width: min(100%, 470px); margin-inline: auto; }
/* ⚠️⚠️ LA PAGE COMPTE RETROUVE LA NAPPE (15/09, nuit : « fais une super page
   pour se connecter ou en créer un avec shaderGradient ») — le pourquoi, et ce
   qui protège le mot de passe, sont dans le cartouche de `compte.html`.
   Ici, la nappe ENTOURE la carte au lieu de tenir le haut gauche : son masque
   est centré sur la colonne et s'éteint avant les bords de l'écran.
   ⚠️ LA CARTE RESTE DU PAPIER, et c'est la leçon du 19/08 : le verre est pour la
   navigation, jamais pour le contenu (`t-verre`). Ce qui la détache de la
   lumière, c'est son liseré éclairé par le haut, un anneau d'appareil comme les
   cadres des produits (`--anneau`), et une ombre violette — pas un flou.
   ⚠️ Son fond est à 92 % : la nappe teinte à peine la carte, et le texte se
   mesure toujours sur un sol sombre. */
/* ⚠️ Le bas du masque s'éteint AVANT le bord de la houle : à 1 000 px de
   rayon, sa silhouette sombre se dessinait en bas à droite de l'écran. */
.nappe.nappe-compte {
  -webkit-mask-image: radial-gradient(1560px 760px at 50% 30%, #000 34%, rgba(0, 0, 0, .5) 60%, transparent 86%);
  mask-image: radial-gradient(1560px 760px at 50% 30%, #000 34%, rgba(0, 0, 0, .5) 60%, transparent 86%);
}
.identite {
  position: relative;
  width: 100%;
  margin-inline: auto;
  padding: clamp(32px, 4vw, 44px) clamp(24px, 3.2vw, 38px) clamp(28px, 3.4vw, 38px);
  text-wrap: pretty;
  border-radius: var(--r-xl);
  border: 1px solid rgba(185, 185, 185, .18);
  background-color: rgba(12, 12, 12, .92);
  /* ⚠️ GRAPHITE (17/09) : ni double anneau, ni lueur sous la carte. */
  box-shadow: none;
}
/* le liseré éclairé par le haut : un dégradé de bordure, découpé en anneau */
.identite::before {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(180deg, rgba(205, 205, 205, .6), rgba(205, 205, 205, .1) 30%, transparent 58%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}
.identite > .volet > * { width: 100%; }
.identite .titre {
  font-size: clamp(1.6rem, 2.5vw, 2rem);
  line-height: 1.14;
  letter-spacing: -0.032em;
  text-align: center;
  text-wrap: balance;
  margin-bottom: 10px;
}
.identite .sous-titre { font-size: 14.5px; text-align: center; text-wrap: balance; max-width: 52ch; margin: 0 auto 24px; }
.identite .champ {
  display: block;
  margin-bottom: 10px;
  padding: 9px 14px 10px;
  border: 1px solid var(--trait-fort);
  border-radius: var(--r-s);
  background: #0A0A0A;
  cursor: text;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.identite .champ:focus-within { border-color: rgba(164, 164, 164, .8); box-shadow: 0 0 0 4px rgba(119, 119, 119, .22); }
.identite .champ > span { display: block; font-size: 12px; font-weight: 500; color: var(--encre-3); margin-bottom: 0; }
.identite .champ input[type="text"],
.identite .champ input[type="email"],
.identite .champ input[type="password"] {
  width: 100%;
  border: 0;
  background: transparent;
  padding: 0;
  border-radius: 0;
  font-size: 16px;
  line-height: 1.4;
  color: var(--encre);
}
.identite .champ input:focus { outline: 0; box-shadow: none; background: transparent; }
.identite .champ.err input,
.identite .champ.err select { border-color: var(--rouge); }
.identite .champ .ferr { display: block; margin: 6px 0 0; font-size: 12.5px; color: var(--rouge); min-height: 0; }
.identite .btn-bloc { margin-top: 14px; }
.identite .onglets {
  display: flex;
  justify-content: center;
  margin: 18px 0 0;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}
.identite .onglets button {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  font-size: 14px;
  font-weight: 500;
  color: var(--bleu-clair);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(179, 179, 179, .35);
  transition: text-decoration-color .16s ease;
}
.identite .onglets button.on { display: none; }
.identite .onglets button:hover { text-decoration-color: currentColor; }
.identite .cpt-mark { display: block; width: 56px; margin: 0 auto 18px; }
.identite .cpt-mark img { display: block; width: 100%; height: auto; filter: drop-shadow(0 12px 28px rgba(106, 106, 106, .55)); }
/* arrivé par « Tester » : l'application qui s'ouvre juste après */
.identite .cpt-essai {
  display: flex;
  align-items: center;
  gap: 10px;
  width: max-content;
  max-width: 100%;
  margin: -6px auto 20px;
  padding: 5px 15px 5px 5px;
  border-radius: var(--r-pill);
  background: #151515;
  border: 1px solid rgba(179, 179, 179, .3);
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.3;
  color: var(--encre);
}
.identite .cpt-essai img { display: block; flex: none; width: 26px; height: 26px; border-radius: 7px; }

.accords { display: grid; gap: 10px; margin: 22px 0 16px; }
.accord {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  font-size: 13px;
  line-height: 1.5;
  color: var(--encre-2);
  cursor: pointer;
}
.accord input { width: 17px; height: 17px; margin: 1px 0 0; accent-color: var(--bleu-vif); cursor: pointer; }
.accord a { color: var(--encre); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: rgba(179, 179, 179, .45); }
.accord a:hover { color: var(--bleu-clair); }

.bascule {
  width: 44px;
  height: 26px;
  padding: 3px;
  border-radius: 999px;
  border: 1px solid var(--trait-fort);
  background: var(--papier-3);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  transition: background-color .2s, border-color .2s;
}
.bascule > span {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: var(--ombre-1);
  transition: transform .2s cubic-bezier(.2, .7, .3, 1);
}
.bascule[aria-checked="true"] { background: var(--action); border-color: rgba(164, 164, 164, .6); }
.bascule[aria-checked="true"] > span { transform: translateX(18px); }
.bascule:disabled { opacity: .55; cursor: default; }

/* les trois assurances sous la carte */
.rassure { list-style: none; margin: clamp(40px, 6svh, 60px) 0 0; padding: 0; display: grid; grid-template-columns: 1fr; }
.rassure li {
  display: grid;
  grid-template-columns: calc(1px + clamp(24px, 3.2vw, 36px)) 1fr;
  grid-template-areas: 'ico titre' '. texte';
  column-gap: 0;
  row-gap: 5px;
  align-items: center;
  padding: clamp(17px, 2vw, 23px) 0;
  border-top: 1px solid var(--trait);
}
.rassure li:first-child { border-top: 0; padding-top: 0; }
.rassure li:last-child { padding-bottom: 0; }
.rassure svg {
  grid-area: ico;
  justify-self: start;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--bleu-clair);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.rassure b { grid-area: titre; font-size: 15px; font-weight: 500; letter-spacing: -0.012em; }
.rassure span { grid-area: texte; font-size: 13.5px; color: var(--encre-3); line-height: 1.55; max-width: 46ch; }

.ferr { color: var(--rouge); font-size: 13.5px; min-height: 18px; margin-bottom: 6px; }
.ferr:empty { min-height: 0; }
.tiers { margin-top: 22px; }
.tiers-ou { position: relative; text-align: center; margin-bottom: 14px; font-size: 12.5px; color: var(--encre-3); }
.tiers-ou::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; border-top: 1px solid var(--trait); }
.tiers-ou span { position: relative; background: var(--papier); padding: 0 12px; font-weight: 500; }
.tiers .btn + .btn { margin-top: 8px; }
.forgot { margin-top: 16px; text-align: center; }
.sousform { margin-top: 20px; }
.oactions { display: flex; gap: 10px; flex-wrap: wrap; }
.oactions .btn { flex: 1; min-width: 0; }

/* le panneau connecté (`compte.js` le montre en style en ligne) */
.me { display: none; }
.avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--action);
  color: var(--sur-action);
  font-weight: 500;
  font-size: 18px;
}
.avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* les postes enregistrés du compte */
.me .sieges { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--trait); }
.sieges-t {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--encre-3);
  margin-bottom: 10px;
}
.sieges-q { font-size: 12px; }
.sieges-l { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.sieges-l li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 10px 12px;
  border-radius: var(--r-s);
  background: #0A0A0A;
  border: 1px solid var(--trait);
}
.sieges-l .sid {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--encre);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sieges-l .sdate { display: block; font-size: 11.5px; color: var(--encre-3); font-family: inherit; }
.sieges-l button {
  flex: none;
  padding: 6px 12px;
  font-size: 12.5px;
  font-weight: 500;
  border-radius: var(--r-pill);
  cursor: pointer;
  color: var(--encre-2);
  background: transparent;
  border: 1px solid var(--trait-fort);
  transition: color .18s ease, border-color .18s ease, background .18s ease;
}
.sieges-l button:hover:not(:disabled) { color: var(--encre); border-color: rgba(179, 179, 179, .5); background: rgba(119, 119, 119, .1); }
.sieges-l button:disabled { opacity: .5; cursor: default; }
.sieges-n { margin: 10px 0 0; font-size: 12px; line-height: 1.55; color: var(--encre-3); }

/* ------------------------------------------------ les paramètres du compte */
/* ⚠️⚠️ « À LA MODE CHATGPT » (16/09) : une colonne de sections à gauche, UNE
   section à droite, chaque réglage sur une ligne — ce qu'il fait à gauche, son
   contrôle à droite. Connecté, la colonne étroite de la connexion (470 px)
   s'élargit : un tableau de réglages à deux colonnes ne tient pas dans la
   largeur d'un formulaire de mot de passe.
   ⚠️ La carte reste la MÊME (`.identite`, papier, liseré éclairé) : se
   connecter ne change pas d'univers. Seul son rembourrage part, les deux
   colonnes portent le leur.
   ⚠️ Aucun verre ici non plus (`t-verre` : le verre est pour la navigation,
   jamais pour le contenu) — ni sur les boîtes de dialogue, ni sur leur voile. */
.cpt.connecte { padding-block: clamp(20px, 3.4svh, 52px) clamp(60px, 10svh, 120px); }
.cpt.connecte .cpt-colonne { width: min(100%, 1040px); }
.cpt.connecte .identite { padding: 0; }
.cpt.connecte .cpt-mark,
.cpt.connecte .rassure { display: none; }
/* un jeton en poche : la colonne attend `/v1/me` au lieu de montrer le
   formulaire de connexion à quelqu'un qui est déjà connecté (`compte.js`) */
.cpt.attente .cpt-colonne { visibility: hidden; }

.pr { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 640px; text-align: left; }
.pr-cote { display: flex; flex-direction: column; padding: 28px 14px; border-right: 1px solid var(--trait); }
.pr-h1 { margin: 0 12px 14px; font-size: 13px; font-weight: 500; letter-spacing: .01em; color: var(--encre-3); }
.pr-nav { position: relative; display: flex; flex-direction: column; gap: 2px; }
.pr-onglet {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: 42px;
  padding: 9px 12px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--encre-2);
  font: inherit;
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}
.pr-onglet svg { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.pr-onglet:hover { background: rgba(255, 255, 255, .045); color: var(--encre); }
.pr-onglet[aria-selected="true"] { background: rgba(255, 255, 255, .085); color: var(--encre); box-shadow: inset 0 0 0 1px rgba(192, 192, 192, .1); }
/* SE DÉCONNECTER, en bas de la colonne (17/09, « il faut aussi que je puisse
   facilement me déconnecter de mon compte ») : le dessin d'un onglet, posé au
   pied de la colonne derrière un filet — le geste de sortie, pas une section. */
.pr-quitter {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: 42px;
  margin-top: auto;
  padding: 9px 12px;
  border: 0;
  border-top: 1px solid var(--trait);
  border-radius: 0 0 12px 12px;
  background: transparent;
  color: var(--encre-2);
  font: inherit;
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .16s ease, color .16s ease;
}
.pr-quitter svg { width: 18px; height: 18px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.pr-quitter:hover { background: rgba(255, 255, 255, .045); color: var(--encre); }

.pr-contenu { min-width: 0; padding: 28px clamp(22px, 3.2vw, 44px) 34px; }
/* ⚠️ `section { padding-top: var(--pas) }` vaut pour les sections de PAGE :
   sans ceci, chaque section de réglages descendait de 64 px sous sa colonne. */
.pr-section { padding: 0; }
.pr-h2 { margin: 0; padding-bottom: 18px; border-bottom: 1px solid var(--trait); font-size: 21px; font-weight: 500; line-height: 1.2; letter-spacing: -0.024em; }

/* l'identité en tête du Profil : la photo EST le bouton qui la change */
.pr-carte-id { display: flex; align-items: center; gap: 18px; padding: 24px 0; border-bottom: 1px solid var(--trait); }
.pr-photo { position: relative; flex: none; width: 76px; height: 76px; padding: 0; border: 0; border-radius: 50%; background: none; cursor: pointer; }
.pr-photo .avatar { width: 76px; height: 76px; font-size: 29px; }
.pr-photo-cam {
  position: absolute;
  right: -3px;
  bottom: -3px;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--trait-fort);
  background: var(--papier-3);
  color: var(--encre);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .55);
  transition: background-color .16s ease, border-color .16s ease;
}
.pr-photo-cam svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linejoin: round; }
.pr-photo:hover .pr-photo-cam { background: var(--action); border-color: transparent; color: var(--sur-action); }
.pr-photo.depot .avatar { box-shadow: 0 0 0 3px var(--bleu-clair); }
.pr-carte-t { min-width: 0; }
.pr-nom { font-size: 19px; font-weight: 500; letter-spacing: -0.02em; overflow-wrap: anywhere; }
.pr-mail { margin-top: 2px; font-size: 14px; color: var(--encre-2); overflow-wrap: anywhere; }
.pr-carte-t .chip { margin-top: 10px; padding: 3px 12px; font-size: 12.5px; }

/* une ligne de réglage */
.pr-ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  column-gap: 20px;
  row-gap: 12px;
  padding: 18px 0;
  border-bottom: 1px solid var(--trait);
}
.pr-ligne:last-child { border-bottom: 0; }
.pr-lib { flex: 1 1 260px; min-width: 0; }
.pr-lib b { display: block; font-size: 14.5px; font-weight: 500; letter-spacing: -0.01em; color: var(--encre); }
.pr-lib span { display: block; max-width: 54ch; margin-top: 3px; font-size: 13.5px; line-height: 1.5; color: var(--encre-3); overflow-wrap: anywhere; }
.pr-val { flex: none; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px; font-size: 14px; color: var(--encre-2); }
.pr-note { font-size: 13px; color: var(--encre-3); }
.pr-vide { margin: 18px 0 0; padding: 16px 18px; border: 1px dashed var(--trait-fort); border-radius: var(--r-s); font-size: 13.5px; line-height: 1.55; color: var(--encre-3); }
.me .pr .sieges { margin-top: 0; padding-top: 18px; border-top: 0; }

/* les petits boutons des réglages : cerclés, sans verre */
.pr-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 36px;
  padding: 7px 16px;
  border: 1px solid var(--trait-fort);
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .03);
  color: var(--encre);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}
.pr-btn:hover { background: rgba(255, 255, 255, .075); border-color: rgba(192, 192, 192, .36); }
.pr-btn:disabled { opacity: .5; cursor: default; }
.pr-btn:disabled:hover { background: rgba(255, 255, 255, .03); border-color: var(--trait-fort); }
.pr-btn.plein { background: var(--action); border-color: transparent; color: var(--sur-action); }
.pr-btn.plein:hover { background: var(--action-vive); }
.pr-btn.plein:disabled:hover { background: var(--action); border-color: transparent; }
/* ⚠️ Le rouge PLEIN est plus sombre que `--rouge` : du blanc sur `#FF7A6E` ne
   tient pas 4,5:1 (2,5:1), sur `#C9372C` il en tient 5,2. */
.pr-btn.danger { color: var(--rouge); border-color: rgba(255, 122, 110, .38); }
.pr-btn.danger:hover { background: rgba(255, 122, 110, .1); border-color: rgba(255, 122, 110, .62); }
.pr-btn.danger.plein { background: #C9372C; border-color: rgba(255, 122, 110, .6); color: #fff; }
.pr-btn.danger.plein:hover { background: #B5302A; }
.pr-btn.danger.plein:disabled:hover { background: #C9372C; }

/* les formulaires qui s'ouvrent SOUS leur ligne */
.pr-form { flex: 1 0 100%; max-width: 460px; margin-top: 4px; }
.pr-form-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 8px; }

/* ⚠️ Les boîtes de dialogue sont `<dialog>` : le voile, le piège du focus et
   Échap sont natifs. Elles vivent DANS le panneau, pour que les règles des
   champs (`.identite .champ`) les atteignent. */
.pr-dialog {
  width: min(92vw, 440px);
  max-height: min(92svh, 760px);
  padding: 0;
  border: 1px solid rgba(185, 185, 185, .2);
  border-radius: var(--r-l);
  background: #0F0F0F;
  color: var(--encre);
  overscroll-behavior: contain;
}
.pr-dialog::backdrop { background: rgba(6, 3, 10, .74); }
.pr-dialog[open] { animation: pr-dialog-entre .18s cubic-bezier(.2, .7, .3, 1); }
@keyframes pr-dialog-entre { from { opacity: 0; transform: translateY(8px) scale(.985); } }
.pr-dialog-corps { padding: 26px 26px 22px; text-align: left; }
.pr-dialog-t { margin: 0 0 8px; font-size: 18px; font-weight: 500; letter-spacing: -0.02em; }
.pr-dialog-p { margin: 0 0 18px; font-size: 14px; line-height: 1.55; color: var(--encre-2); }
.pr-dialog-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.pr-dialog .pr-note { display: block; margin: 10px 0 0; text-align: center; }

/* le recadrage de la photo : un carré qu'on fait glisser, un cercle qui montre
   ce qui sera gardé */
.rognage {
  position: relative;
  width: min(100%, 300px);
  aspect-ratio: 1;
  margin: 6px auto 0;
  overflow: hidden;
  border-radius: var(--r-l);
  background: #0B0B0C;
  touch-action: none;
  cursor: grab;
}
.rognage:active { cursor: grabbing; }
.rognage canvas { display: block; width: 100%; height: 100%; }
.rognage::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .55), 0 0 0 600px rgba(10, 10, 11, .6);
  pointer-events: none;
}
.rognage:focus-visible { outline: 2px solid var(--bleu-clair); outline-offset: 3px; }
.rognage-zoom { display: flex; align-items: center; gap: 12px; width: min(100%, 300px); margin: 16px auto 0; color: var(--encre-3); }
.rognage-zoom svg { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.rognage-zoom input[type="range"] { flex: 1; min-width: 0; accent-color: var(--bleu-vif); }

@media (prefers-reduced-motion: reduce) {
  .pr-dialog[open] { animation: none; }
}

/* ⚠️ AU TÉLÉPHONE, LES SECTIONS PASSENT EN RANGÉE QUI DÉFILE au-dessus du
   contenu — la page, elle, ne défile jamais de côté. Chaque cible tient les
   44 px du pouce. */
@media (max-width: 760px) {
  .pr { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .pr-cote { padding: 18px 0 0; border-right: 0; border-bottom: 1px solid var(--trait); }
  /* au téléphone, « Se déconnecter » monte à droite du titre : sous la rangée
     d'onglets qui défile, il serait un bouton de plus à chercher */
  .pr-cote { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .pr-cote > .pr-nav { grid-column: 1 / -1; }
  .pr-quitter { grid-row: 1; grid-column: 2; width: auto; min-height: 44px; margin: 0 14px 10px 0; padding: 8px 15px;
    border: 1px solid var(--trait); border-radius: var(--r-pill); font-size: 14px; }
  .pr-quitter svg { width: 16px; height: 16px; }
  .pr-h1 { margin: 0 18px 10px; }
  .pr-nav { flex-direction: row; gap: 6px; padding: 0 14px 14px; overflow-x: auto; scrollbar-width: none; }
  .pr-nav::-webkit-scrollbar { display: none; }
  .pr-onglet { flex: none; width: auto; min-height: 44px; padding: 8px 15px; border-radius: var(--r-pill); font-size: 14px; }
  .pr-onglet svg { display: none; }
  .pr-contenu { padding: 22px 18px 26px; }
  .pr-val { justify-content: flex-start; }
  .pr-btn, .sieges-l button { min-height: 44px; }
  .pr-btn { padding-inline: 18px; }
  .pr-carte-id { gap: 14px; }
  .pr-photo, .pr-photo .avatar { width: 64px; height: 64px; }
  .pr-photo .avatar { font-size: 25px; }
  .pr-dialog-corps { padding: 22px 18px 18px; }
  .pr-dialog-actions { flex-direction: column-reverse; }
  .pr-dialog-actions .pr-btn { width: 100%; }
}

/* la pastille de la page de vérification d'adresse */
.verico {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  margin: 0 auto 20px;
  background: var(--papier-3);
  color: var(--encre-2);
  box-shadow: inset 0 0 0 1px var(--trait-fort);
}
.verico svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.verico.ok { background: rgba(40, 200, 64, .1); color: var(--vert); }
.verico.non { background: rgba(255, 122, 110, .1); color: var(--rouge); }

/* les pages de réinitialisation et de vérification : une carte centrée */
.carte.centre h1 { font-size: clamp(1.6rem, 2.6vw, 2rem); letter-spacing: -0.03em; line-height: 1.15; margin-bottom: 10px; }
.carte.centre .sous-titre { margin-bottom: 22px; }

/* ------------------------------------------------------ pages légales */
.prose { max-width: 70ch; margin-inline: auto; font-size: 16px; line-height: 1.75; color: var(--encre-2); overflow-wrap: break-word; }
.prose h1 {
  color: var(--encre);
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.035em;
  margin-bottom: 22px;
}
.prose h2 { font-size: 1.35rem; font-weight: 500; letter-spacing: -0.024em; margin: 48px 0 14px; color: var(--encre); }
.prose h3 { font-size: 1.06rem; font-weight: 500; letter-spacing: -0.016em; margin: 30px 0 10px; color: var(--encre); }
.prose h2:first-child, .prose h3:first-child { margin-top: 0; }
.prose ul, .prose ol { padding-left: 22px; margin: 0 0 1em; }
.prose li { margin-bottom: .45em; }
.prose li::marker { color: var(--bleu-clair); }
.prose b, .prose strong { color: var(--encre); font-weight: 500; }
.prose a {
  color: var(--encre);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: rgba(179, 179, 179, .45);
  overflow-wrap: anywhere;
}
.prose a:hover { color: var(--bleu-clair); text-decoration-color: currentColor; }
.prose table { width: 100%; border-collapse: collapse; font-size: 14.5px; margin: 0 0 1.4em; }
/* ⚠️ Au téléphone, ce tableau devient une suite de BLOCS — voir le bloc
   « la lecture au téléphone », en fin de feuille (il doit passer APRÈS la
   règle de rembourrage ci-dessous, sinon il perd à spécificité égale). */
.prose th, .prose td { text-align: left; padding: 11px 12px; border-top: 1px solid var(--trait); vertical-align: top; }
.prose th { color: var(--encre); font-weight: 500; }
.prose .maj { font-size: 13.5px; color: var(--encre-3); }
.prose .foinote {
  display: inline-block;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait);
  background: rgba(255, 255, 255, .025);
  font-size: 13px;
  color: var(--encre-2);
}
.prose .chapo { color: var(--encre); font-size: 1.05rem; }
/* ⚠️ Les trous du vendeur crèvent les yeux, en AMBRE : publiés tels quels,
   ils doivent se voir (échec bruyant, pas muet). */
.todo { background: rgba(224, 166, 91, .16); color: #F0BF7A; padding: 1px 6px; border-radius: 5px; font-weight: 600; }

/* ----------------------------------------------------------------- le pied */
.pied {
  padding-block: 40px 44px;
  border-top: 1px solid var(--trait);
  color: var(--encre-3);
  font-size: 13.5px;
}
.pied .wrap { display: flex; flex-wrap: wrap; gap: 24px; align-items: center; padding-right: clamp(60px, 11vw, 170px); }
.pied a { color: var(--encre-2); transition: color .16s; }
.pied a:hover { color: var(--encre); }
.pied nav { display: flex; flex-wrap: wrap; gap: 22px; margin-left: auto; }
/* la barre d'appel flotte en bas de l'écran : en fin de page, elle couvrait
   les liens légaux du pied. On lui laisse sa place. */
body:has(.barre-appel) .pied { padding-bottom: 116px; }

/* ---------------------------------------------------------------- toast */
#toast {
  position: fixed;
  left: 50%;
  bottom: 26px;
  transform: translate(-50%, 14px);
  z-index: 300;
  padding: 11px 18px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait-fort);
  background: rgba(11, 11, 11, .92);
  /* ⚠️ le verre le plus FIN de la page : vide, le toast mesure 900 px² et
     `t-verre` exige qu'une plus grande surface (un bouton cerclé) floute
     davantage que la plus petite */
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: #fff;
  font-size: 14px;
  font-weight: 500;
  opacity: 0;
  pointer-events: none;
  transition: opacity .24s, transform .24s;
  max-width: min(90vw, 460px);
  text-align: center;
  box-shadow: 0 20px 50px -20px rgba(0, 0, 0, .9);
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }
#toast.err { background: rgba(120, 28, 20, .94); border-color: rgba(255, 122, 110, .4); }
#toast.ok { border-color: rgba(40, 200, 64, .35); }

/* --------------------------------------------------------- accessibilité */
/* MOINS DE MOUVEMENT : les entrées deviennent des fondus courts, et chaque
   boucle a son interrupteur écrit à côté d'elle (voir `.essai-rond`,
   `.ea-pointeur`). Ce bloc-ci est le filet général. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .12s !important;
  }
  /* ⚠️⚠️ ON CACHE LA TOILE, PAS L’AFFICHE (19/09). Cette ligne disait
     `.nappe` : elle retirait TOUT le dégradé. Or l’affiche est une image
     FIXE — aucune animation, aucune transition sur `.nappe` — et `nappe.js`
     refuse déjà de monter la toile sous ce réglage (l.154). On ne cachait
     donc pas du mouvement, on cachait le dégradé — et « Réduire les
     animations » est allumé sur beaucoup d’iPhone.
     ⚠️ Le voisin `prefers-reduced-transparency` garde son `.nappe`, lui :
     là c’est bien un voile qu’on retire, et c’est ce qui est demandé. */
  .nappe-toile { display: none; }
}

/* MOINS DE TRANSPARENCE : des surfaces PLEINES, jamais un flou atténué.
   ⚠️ Des couleurs du thème sombre, pas du blanc en dur : le texte, lui, reste
   clair (le défaut « Critical » de l'audit, mesuré par `t-reglages`). */
@media (prefers-reduced-transparency: reduce) {
  .entete, .entete.collee, .dock {
    background: var(--papier-2) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  .langmenu, .megamenu {
    background: var(--papier) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  .btn-2, .langbtn,
  .chip:not(.ok):not(.warn):not(.plan) {
    background: var(--papier-3) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  /* ⚠️⚠️ « Se connecter » porte la classe `btn-2` mais c'est un bouton PLEIN, à
     encre sombre depuis l'orange (17/09) : la règle du dessus lui donnait le
     gris levé et son texte tombait à 1,07:1 (`t-reglages`). Son aplat est déjà
     opaque, il n'a rien à perdre ici. */
  .entete #ctaAuth { background: var(--action) !important; }
  .barre-appel {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background: var(--papier);
  }
  .accords-boite::backdrop, .essai-fond {
    background: var(--papier-2) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  #toast { background: var(--papier-3); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .nappe { display: none; }
}

/* PLUS DE CONTRASTE : les encres secondaires se rapprochent de l'encre
   principale — vers le CLAIR — et le filet s'épaissit.
   ⚠️⚠️ `html:root[data-theme="dark"]` et pas `:root[data-theme="dark"]` : à
   spécificité égale, le bloc des jetons (plus haut) gagnerait encore sur les
   visiteurs réels, qui ont tous l'attribut. Mesuré par `t-reglages`. */
@media (prefers-contrast: more) {
  :root, html:root[data-theme="dark"] {
    --encre-2: #DBDBDB;
    --encre-3: #BDBDBD;
    --trait: rgba(192, 192, 192, .30);
    --trait-fort: rgba(192, 192, 192, .45);
  }
}

/* ------------------------------------------------------------ téléphone */
@media (max-width: 760px) {
  /* LA BARRE SUR DEUX RANGS : la marque et les outils en haut, la navigation
     dessous, en bande qui défile. */
  :root, :root[data-theme="dark"] { --entete-h: 104px; }
  .entete { height: var(--entete-h); }
  .entete .wrap {
    width: min(100% - 28px, var(--large));
    grid-template-columns: auto 1fr;
    gap: 8px 10px;
  }
  .entete .marque { grid-row: 1; grid-column: 1; }
  .entete .outils { grid-row: 1; grid-column: 2; justify-self: end; margin-left: 14px; }
  .entete .outils .btn, .entete .langbtn { white-space: nowrap; }
  /* ⚠️ 44 px de haut, mesurés par `t-iphone` : le bouton du coin est la
     cible la plus touchée du site, et 9 px de rembourrage le mettaient à 38 */
  .entete #ctaAuth { padding: 0 16px; min-height: 44px; }
  /* ⚠️ 48 et pas 44 pour les boutons de page : le bouton du message « le
     launcher se teste sur ordinateur » vit dans la scène que `mouvement.js`
     fait arriver INCLINÉE (rotateX 16°, échelle .93). `t-iphone` mesure le
     rectangle rendu : 44 px inclinés en font 39. */
  .btn { min-height: 48px; }
  /* ⚠️ Sans pilule autour de la bande : le fondu de défilement la
     découperait, et un contour coupé se lit comme un défaut. */
  .entete .menu {
    grid-row: 2;
    grid-column: 1 / -1;
    justify-self: stretch;
    justify-content: flex-start;
    overflow-x: auto;
    gap: 2px;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .entete .menu::-webkit-scrollbar { display: none; }
  /* ⚠️ 26 px : exactement ce que `site.js` ajoute pour sortir le lien actif
     du fondu. Bouger l'un sans l'autre remet le lien sous le dégradé. */
  .entete .menu.defile-suite {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  }
  .entete .menu.defile-debut.defile-suite {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 20px, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 20px, #000 calc(100% - 26px), transparent);
  }
  .entete .menu.defile-debut:not(.defile-suite) {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 20px);
    mask-image: linear-gradient(to right, transparent, #000 20px);
  }
  /* ⚠️⚠️ LES LIENS NE S'ÉLARGISSENT PAS AU TÉLÉPHONE : à 375 px, la rangée
     tenait à 7 px près avec 13 px de rembourrage et un corps de 14. Le point
     de l'onglet actif (14 px de plus) sort donc de la bande, la pilule
     intérieure suffit à dire « où suis-je ». */
  .entete .menu a { white-space: nowrap; flex: none; padding-inline: 13px; font-size: 14px; }
  .entete .menu a.on::before { display: none; }
  /* ⚠️ Le compte existe DEUX FOIS (le bouton du coin mène au même endroit) :
     il sort de la bande. `:not(.on)` : sur sa propre page, où `site.js`
     masque le bouton du coin, il reste le repère « où suis-je ». */
  .entete .menu a.menu-compte:not(.on) { display: none; }

  /* le plancher du pouce : 44 px, mesuré par `t-iphone` */
  .entete .menu a, .entete .marque, .pied nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  .entete .menu a { padding-block: 0; }
  .langbtn, .segment button, .btn-s, .lien-fleche,
  .choix button, .marque, .onglets button, #sgMoins, #sgPlus {
    min-height: 44px;
  }
  #sgMoins, #sgPlus { min-width: 44px; }
  .carte > a { min-height: 44px; }
  .carte > a .dl-tete { min-height: 44px; }
  .lien-fleche { display: inline-flex; align-items: center; }

  /* ⚠️ 16 px dans un champ, sinon l'iPhone zoome sur la page au focus */
  input[type="text"], input[type="email"], input[type="password"],
  input[type="number"], input[type="search"], input[type="tel"], input[type="url"],
  input, select, textarea,
  .identite input[type="text"], .identite input[type="email"], .identite input[type="password"] {
    font-size: 16px;
  }
  /* le plancher de lisibilité : rien sous 12,5 px */
  .champ > span, .identite .champ > span, .puce,
  .compare thead th, .compare .groupe td,
  #dlSha, .legende {
    font-size: 12.5px;
  }

  /* ⚠️⚠️ LE DÉGRADÉ RESTE VISIBLE AU TÉLÉPHONE (19/09). Il était masqué ici
     avec la toile ; or `nappe.js` a SA PROPRE garde (`max-width: 900px`),
     donc lever ce masque montre l’AFFICHE seule — une image de 7 Ko,
     aucun WebGL, aucune batterie. Ce que la décision d’origine voulait
     éviter, c’était la toile ANIMÉE sur un téléphone : elle ne monte
     toujours pas. */
  .nappe-toile { display: none; }

  .display { letter-spacing: -0.03em; }
  .hero .display { max-width: none; }
  .hero-duo .display { max-width: none; }

  /* ⚠️ SUR UN ÉCRAN ÉTROIT, ON N'EMBARQUE PAS UNE APPLICATION DE BUREAU : un
     message la remplace, et l'iframe `loading="lazy"` en `display: none`
     n'est même jamais demandée. */
  .scene { overflow-x: visible; max-width: calc(100% - 20px); }
  .cadre-app { display: none; }
  .sans-lanceur { display: block; }

  .claim { grid-template-columns: 1fr; gap: 4px; }
  .dock { flex-wrap: wrap; justify-content: flex-start; }
  .faq-item > .faq-r { padding-right: 22px; }

  section { padding-block: clamp(52px, 11vw, 80px); }
  /* ⚠️ `.wrap.tres-large` retire 48 px comme toutes les colonnes, et ce n'est
     plus une exception du téléphone : la règle de base disait 40, et entre
     761 et 1 100 px la colonne tombait à 20 px du bord pendant que la section
     d'à côté en tenait 24 (`t-alignement --large 390`, puis `--large 1024`
     sur assetbrowser.html, 15/09). */

  /* le tableau des tarifs défile, sa première colonne reste */
  .cadre-table {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  }
  .compare th:first-child, .compare td:first-child {
    position: sticky;
    left: 0;
    background: var(--papier-2);
    z-index: 1;
  }
  .compare { min-width: 560px; }

  .pied .wrap { display: block; padding-right: 0; }
  .pied nav { margin-left: 0; display: grid; grid-template-columns: 1fr; gap: 0; justify-items: start; }
  .pied .wrap > span { display: block; margin-top: 16px; }
}

@media (max-width: 520px) {
  .hero { padding-top: clamp(32px, 7svh, 52px); }
  .btn { padding: 12px 18px; }
  .btn-l { padding: 14px 22px; font-size: 14.5px; }
  .actions .btn { flex: 1 1 auto; }
  .ch-case { padding-inline: 14px; }
}

@media (max-width: 400px) {
  .entete .menu a { padding-inline: 11px; }
  .entete .langbtn #langCur { display: none; }
  .entete .langbtn { padding-inline: 0; min-width: 44px; gap: 0; justify-content: center; }
  .hero .display { font-size: clamp(2rem, 9vw, 2.5rem); }
  @media (min-width: 341px) {
    .entete .wrap { width: min(100% - 20px, var(--large)); }
  }
}

@media (max-width: 340px) {
  /* la marque garde son logo et perd son nom : 320 px ne tiennent pas tout */
  .entete .marque { font-size: 0; gap: 0; min-width: 44px; justify-content: center; }
  .entete .wrap { width: min(100% - 16px, var(--large)); }
  .entete .outils { margin-left: 4px; }
  .entete .outils .btn { padding-inline: 13px; }
}

/* ------------------------------------------------------------- tablette */
/* ⚠️⚠️ « ILLISIBLE SUR IPAD » (17/09) — LA BARRE DÉBORDAIT, ET SAFARI DÉZOOMAIT
   LA PAGE ENTIÈRE. Entre 761 et ~900 px, la barre d'une rangée demandait plus
   de place que l'écran n'en a : mesuré sur les sept pages, le bouton du coin
   sortait de 76 px à 768 (iPad), 34 à 810, 24 à 820 (iPad Air), 10 à 834
   (iPad Pro 11). Un seul élément plus large que l'écran, et Safari sur iPad
   réduit TOUTE la page pour la faire tenir — le texte de tout le site en
   devient petit.
   · la rangée reste UNE rangée, compacte : le lien « Compte » de la bande sort
     (le bouton du coin mène au même endroit — même règle qu'au téléphone), le
     sélecteur de langue ne garde que son icône, les liens se resserrent ;
   · ⚠️ ET ELLE NE PEUT PLUS DÉBORDER, QUELLE QUE SOIT LA LANGUE : la colonne
     du milieu descend jusqu'à zéro et la bande DÉFILE (le fondu de
     `site.js` dit qu'il en reste). Mesuré le 17/09 dans les dix langues : la
     rangée compacte tient à 768 px sans défiler ; le filet sert au libellé de
     demain, pas à celui d'aujourd'hui. */
@media (min-width: 761px) and (max-width: 1023px) {
  .entete .wrap { grid-template-columns: max-content minmax(0, 1fr) max-content; gap: 12px; }
  .entete .menu {
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .entete .menu::-webkit-scrollbar { display: none; }
  .entete .menu a { flex: none; padding-inline: 12px; }
  .entete .menu a.menu-compte:not(.on) { display: none; }
  .entete .langbtn #langCur { display: none; }
  .entete .langbtn { padding-inline: 0; min-width: 44px; gap: 0; justify-content: center; }
  .entete #ctaAuth { padding-inline: 16px; }
  .entete .menu.defile-suite {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  }
  .entete .menu.defile-debut.defile-suite {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 20px, #000 calc(100% - 26px), transparent);
    mask-image: linear-gradient(to right, transparent, #000 20px, #000 calc(100% - 26px), transparent);
  }
  .entete .menu.defile-debut:not(.defile-suite) {
    -webkit-mask-image: linear-gradient(to right, transparent, #000 20px);
    mask-image: linear-gradient(to right, transparent, #000 20px);
  }
}

/* ⚠️ LE DOIGT, À TOUTE LARGEUR (17/09) : un iPad en paysage (1 180, 1 366 px)
   n'est pas un téléphone, mais on le touche. Le plancher de 44 px des cibles de
   la barre et du pied ne vivait que sous 760 px. */
@media (hover: none) and (pointer: coarse) {
  .entete .menu a, .entete .langbtn, .entete #ctaAuth, .entete .marque {
    min-height: 44px;
  }
  .entete .menu a { padding-block: 0; }
}

/* ------------------------------------------------------------- le toucher */
/* le retour sous le doigt : ce qui se touche répond */
.menu a:active,
.accord a:active,
.pied a:active,
.lien-fleche:active,
.marque:active { opacity: .6; }
.marque, .langbtn { transition: transform .1s ease-out, color .18s, border-color .18s, background-color .18s; }
.marque:active, .langbtn:active { transform: scale(.97); }
.accord a:focus-visible,
.rassure a:focus-visible,
.sous-titre a:focus-visible { outline-offset: 1px; border-radius: 3px; }

/* ------------------------------------------------------ bascule de thème */
/* ⚠️⚠️ LE FONDU DE BASCULE, recopié tel quel par `sync-launcher-web.js` dans
   le launcher embarqué : 220 ms, ces propriétés. Bouger l'un, bouger l'autre.
   ⚠️ `!important` le temps du fondu seulement : sans lui, les transitions
   propres des composants reprennent la main et la surface se déchire. */
@media (prefers-reduced-motion: no-preference) {
  html.bascule-theme,
  html.bascule-theme *,
  html.bascule-theme *::before,
  html.bascule-theme *::after {
    transition: background-color 220ms ease, color 220ms ease,
                border-color 220ms ease, fill 220ms ease, stroke 220ms ease,
                box-shadow 220ms ease !important;
  }
}

/* le bouton de thème a été retiré des pages (un seul thème depuis le 09/09) :
   s'il revenait dans un vieux gabarit, il ne s'afficherait pas à moitié */
.themebtn { display: none; }

/* ============================================================================
   L'ASYMÉTRIE (2026-09-15) — « le site est trop symétrique de partout c'est
   chiant »
   ============================================================================
   Relevé avant de toucher : sur l'accueil, NEUF titres de section sur neuf
   étaient centrés, chacun suivi d'un bloc centré — rangée de quatre chiffres
   égaux, quatre vignettes égales, deux cartes égales, FAQ au milieu. La
   référence, elle, ne centre rien : texte à gauche, produit à droite qui
   déborde, preuves en bas à gauche.

   LES QUATRE GESTES, réutilisés partout plutôt qu'inventés par section :
     1. `.tete-sec` — le titre à gauche, le chapeau à droite, calé sur la
        dernière ligne du titre ;
     2. deux colonnes INÉGALES (jamais 1fr 1fr), qui alternent de côté d'une
        section à l'autre ;
     3. une image qui DÉBORDE d'un bord de l'écran, jamais des deux ;
     4. une GRANDE CASE dans chaque grille (mosaïque, escalier, chiffre
        vedette).

   ⚠️ SOUS 900 px TOUT REDEVIENT UNE COLONNE, alignée à gauche : sur un
   téléphone, deux colonnes de 170 px ne sont pas une composition, c'est une
   lecture en zigzag.
   ⚠️ `t-alignement` refuse le « presque aligné » (1 à 12 px) : les bords sont
   soit identiques (même grille), soit franchement différents.
   ========================================================================== */

/* -------------------------------------------------- 1. l'en-tête de section */
.tete-sec {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  column-gap: clamp(32px, 7vw, 120px);
  align-items: end;
  margin-bottom: clamp(38px, 4.8vw, 66px);
}
.tete-sec > * { grid-column: 1; }
.tete-sec > .tete-sec-p {
  grid-column: 2;
  grid-row: 1 / span 4;
  align-self: end;
  margin: 0;
  max-width: 46ch;
  font-size: 15px;
  line-height: 1.65;
  color: var(--encre-2);
}
.tete-sec > .legende { justify-self: start; }
.tete-sec .legende:has(+ .titre) + .titre { margin-top: 18px !important; }

/* le bloc du launcher : le titre et le cadre, centrés ensemble.
   ⚠️ `.scene-bloc` prend la largeur de la scène (max-content) et centre le
   tout ; la scène y perd sa propre marge de 20 px, sinon elle se recentrait à
   10 px du titre — le « presque aligné » que refuse `t-alignement`.
   ⚠️ Depuis le 16/09, le bloc est au milieu de la page à TOUTES les largeurs
   (§ « LE LAUNCHER AU MILIEU ») ; au-dessus de 1 400 px, il partait avant
   vers le bord droit.
   ⚠️ `max-width: 100%`, plus `100% - 20px` (15/09, nuit) : quand le cadre est
   plus large que la colonne (1 280 × 900 : cadre de 1 238 px dans 1 217), le
   bloc plafonné à 20 px de moins se centrait à 10 px de sa colonne — le
   « presque aligné » que `t-alignement --large 1280` a relevé ici ET sur
   assetbrowser.html. Plafonné à 100 %, il tombe sur le bord de la colonne. */
.scene-bloc { width: max-content; max-width: 100%; margin-inline: auto; }
.scene-bloc > .scene { max-width: 100%; margin-inline: 0; }
/* ⚠️ LE TITRE EST CENTRÉ SUR LE CADRE, ET PLUS GROS QUE LES AUTRES TITRES —
   demande de l'éditeur (16/09) : « le Essayez-le ici, sans rien installer. je
   le veux plus gros au milieu ». Il annonce le seul objet de la page qu'on
   peut TOUCHER : il a le droit d'être plus grand qu'un titre de section
   (2,85 rem) sans monter au niveau du héros (4,5 rem), qui reste le seul
   `.display` de l'accueil.
   ⚠️ Centré sur LE CADRE, pas sur la colonne : `.scene-bloc` épouse la largeur
   de la scène (`max-content`), donc centrer le texte dans le bloc le centre
   exactement sur la fenêtre montrée — et sur la page, depuis que le bloc y
   est au milieu à toutes les largeurs (16/09, § « LE LAUNCHER AU MILIEU »). */
.tete-scene {
  margin: 0 0 clamp(24px, 3.4vh, 38px);
  max-width: 100%;
  text-align: center;
  font-size: clamp(2.2rem, 4.4vw, 3.6rem);
}

/* ------------------------------------------ 2. la démonstration Everything */
.ev-grille {
  width: min(100% - 48px, 1320px);
  display: grid;
  grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  column-gap: clamp(40px, 5vw, 76px);
  align-items: center;
}
.ev-texte .titre { font-size: clamp(1.9rem, 2.6vw, 2.35rem); }
/* ⚠️⚠️ LES ÉTAPES SONT DES CHAPITRES (24/09) : « fais en sorte qu'on puisse
   sélectionner n'importe quel chapitre et ça nous avance dans la vidéo de
   présentation au chapitre concerné. Fais ça pour tout » (l'éditeur). Chaque
   étape est un BOUTON (`button.chap`) ; `chapitres.js` le lie à sa
   présentation, qui saute. La barre de chaque chapitre dit où il en est : le
   chapitre en cours se remplit en orange, ceux déjà joués restent pleins en
   gris, ceux qui viennent sont vides — la lecture d'une barre de chapitres
   vidéo.
   ⚠️ La barre est UN SEGMENT PAR CHAPITRE, séparés par un jour : une seule
   ligne continue ne dirait pas où un chapitre finit.
   ⚠️ `--chap-axe` dit à `chapitres.js` dans quel sens la barre avance : `y`
   dans une colonne, `x` dans une frise (`.chap-frise`, et `#vent` au-dessus
   de 1 000 px). Le script le relit au début de chaque chapitre.
   ⚠️ Pas de lueur, pas de pastille : un survol éclaircit le texte et pose un
   fond à peine plus clair, le focus clavier a son contour. */
.ev-etapes {
  --chap-axe: y;
  list-style: none;
  counter-reset: ev;
  margin: clamp(26px, 3vw, 36px) 0 0;
  padding: 0;
}
.ev-etapes li { counter-increment: ev; position: relative; }
.ev-etapes .chap {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 14px;
  width: 100%;
  margin: 0;
  padding: 10px 12px 10px 20px;
  border: 0;
  border-radius: 0 8px 8px 0;
  background: transparent;
  color: var(--encre-3);
  font: inherit;
  font-size: 15px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  transition: color .2s ease, background-color .2s ease;
}
.ev-etapes .chap::before {
  content: counter(ev, decimal-leading-zero);
  flex: none;
  font-size: 12px;
  font-weight: 500;
  color: var(--encre-3);
  font-variant-numeric: tabular-nums;
  transition: color .2s ease;
}
.ev-etapes .chap-t { min-width: 0; }
.ev-etapes .chap-barre {
  position: absolute;
  left: 0;
  top: 5px;
  bottom: 5px;
  width: 2px;
  border-radius: 2px;
  background: var(--trait);
  overflow: hidden;
  pointer-events: none;
}
.ev-etapes .chap-barre i {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--action);
  transform: scaleY(0);
  transform-origin: 0 0;
}
.ev-etapes li.fait .chap { color: var(--encre-2); }
.ev-etapes li.fait .chap-barre i { background: var(--encre-3); }
.ev-etapes li.on .chap { color: var(--encre); }
.ev-etapes li.on .chap::before { color: var(--bleu-clair); }
@media (hover: hover) {
  .ev-etapes .chap:hover { color: var(--encre); background: rgba(255, 255, 255, .045); }
  .ev-etapes .chap:hover::before { color: var(--encre-2); }
  .ev-etapes li.on .chap:hover::before { color: var(--bleu-clair); }
}
.ev-etapes .chap:focus-visible { outline: 2px solid var(--action); outline-offset: -2px; }
/* au téléphone, une affiche : la liste reste un sommaire, sans rien à cliquer */
.ev-etapes.chap-inerte .chap { cursor: default; }
.ev-etapes.chap-inerte .chap:hover { background: transparent; color: var(--encre-3); }
.ev-etapes.chap-inerte .chap-barre { display: none; }

/* LA FRISE : les chapitres en rangée, la barre au-dessus de chacun */
.ev-etapes.chap-frise {
  --chap-axe: x;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  column-gap: 12px;
}
.chap-frise .chap {
  display: block;
  padding: 16px 12px 12px 0;
  border-radius: 0 0 8px 8px;
}
.chap-frise .chap::before { display: block; margin-bottom: 6px; }
.chap-frise .chap-barre {
  left: 0;
  right: 0;
  top: 0;
  bottom: auto;
  width: auto;
  height: 2px;
}
.chap-frise .chap-barre i { transform: scaleX(0); }
/* dans une frise le texte part du bord de sa barre : un fond de survol le
   collerait à son bord gauche — le survol n'y éclaircit que le texte */
@media (hover: hover) {
  .chap-frise .chap:hover { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .ev-etapes .chap, .ev-etapes .chap::before { transition: none; }
}
.ev-cta {
  margin: clamp(28px, 3.2vw, 40px) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 24px;
}
.ev-cta .lien-fleche { width: fit-content; }
.ev-sous { margin: 12px 0 0; max-width: 34ch; font-size: 12.5px; line-height: 1.55; color: var(--encre-3); }
.ev-scene { min-width: 0; }
.ev-scene .ea { margin: 0; max-width: none; }
.ev-pied {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: clamp(24px, 3vw, 44px);
  align-items: start;
  margin-top: 22px;
}
.ev-pied .ea-sources { justify-content: flex-start; margin: 0; }
.ev-pied .ea-vrai { margin: 0; max-width: none; }
/* PRÉSENTATION ASSETBROWSER — la section `#bibliotheque` de l'accueil (15/09).
   ⚠️ UN BLOC D'UN SEUL TENANT, écrit par la session AssetBrowser directement
   dans `orbis.css` : la feuille est ASSEMBLÉE à partir de morceaux par la
   session Site, qui le reporte dans les siens avant son prochain assemblage.
   Tout ce qui sert cette section vit entre cet en-tête et « FIN PRÉSENTATION
   ASSETBROWSER » ; le reste de son dessin est celui de `#montage` (`.ev-*`,
   `.ea-*`), qu'on ne redéfinit pas.
   ⚠️ EN MIROIR DE LA DÉMONSTRATION : l'application à GAUCHE, le récit à
   droite — les deux colonnes inégales alternent de côté d'une section à
   l'autre (§ « L'ASYMÉTRIE »). Le texte reste premier dans le DOM : sous
   1 000 px, la colonne unique le lit avant l'application, comme `#montage`.
   ⚠️ La note sous le cadre s'aligne sur son bord GAUCHE ; sa largeur est en
   pixels, jamais en `ch` (la règle que `t-alignement` a imposée le 15/09). */
@media (min-width: 1001px) {
  .ev-grille.miroir { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); }
  .ev-grille.miroir > .ev-scene { grid-column: 1; grid-row: 1; }
  .ev-grille.miroir > .ev-texte { grid-column: 2; grid-row: 1; }
}
.ev-scene > .ea-vrai { margin: 22px 0 0; max-width: 720px; }
/* le bouton et le lien vers la page dédiée, sur une rangée qui passe à la
   ligne dans la colonne étroite — les mesures de `.nav-actions`, que portait
   la section remplacée */
#bibliotheque .ev-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 22px; }
/* ⚠️ L'ACTE 3 (les captures des logiciels) A QUITTÉ CETTE PRÉSENTATION LE
   16/09 : il est devenu la section `#logiciels`. Ses règles `.nb-dcc*` et
   `.nb-fantome*` vivent, renommées, dans le bloc « PRÉSENTATION DCC ». */
/* FIN PRÉSENTATION ASSETBROWSER */
/* PRÉSENTATION ANIMATED — la section `#vent` de l'accueil (16/09).
   ⚠️ UN BLOC D'UN SEUL TENANT, écrit par la session Animated directement dans
   `orbis.css`, avec l'accord de la session Site : la feuille est ASSEMBLÉE à
   partir de morceaux, et l'outil d'assemblage ne l'efface pas. Le reste du
   dessin est celui de `#montage` (`.ev-*`, `.ea-*`), qu'on ne redéfinit pas.
   ⚠️ La note sous le cadre porte SA marge : la règle jumelle vit dans le bloc
   AssetBrowser, et cette section ne doit pas dépendre d'un autre bloc.
   ⚠️ L'icône glissée est une FEUILLE USD (`.vt-fichier`) qui emprunte la
   boîte de `.eg-dossier` : aucune taille de plus à tenir ici. */
#vent .ev-scene > .ea-vrai { margin: 22px 0 0; max-width: 720px; }
/* ⚠️⚠️ LA PRÉSENTATION ANIMATED A SA PROPRE MISE EN PAGE (18/09).
   « Est ce que tu pourrais mettre sur le site la présentation de Animated dans
   un autre layout stp » — l'éditeur ; devant deux propositions (A : les étapes
   en frise sous un cadre plein ; B : le récit en bandeau au-dessus) : « A ».
   Les trois présentations de l'accueil étaient le MÊME dessin — récit dans une
   colonne de 360 px, application dans l'autre — et alternaient seulement de
   côté. Celle-ci passe en un seul bloc : le titre, l'application SUR TOUTE LA
   LARGEUR, puis les six étapes en frise, le bouton et la note en pied.
   ⚠️ Le cadre gagne sa taille NATIVE : 1 280 × 800 (`fenetre` du catalogue),
   soit l'échelle 1 au lieu de 0,69 dans la colonne — l'arbre, qui est le sujet
   de la section, est montré sans réduction.
   ⚠️⚠️ RIEN AU-DESSOUS DE 1 001 px : le téléphone (§ « AU TÉLÉPHONE, LA
   DÉMONSTRATION MONTE SOUS LE TITRE ») et la tablette gardent exactement leur
   mise en page, crochets compris.
   ⚠️ AUCUN HTML CHANGÉ : `display: contents` sort les deux colonnes de la
   grille — leurs enfants en deviennent les cases — exactement comme le fait
   déjà le bloc du téléphone. `camera-presentations.js` pose sa fenêtre autour
   de `.ea` : c'est alors `.ea-fenetre` qui est la case, d'où les deux
   sélecteurs partout où le cadre est placé. */
@media (min-width: 1001px) {
  #vent .ev-grille {
    width: min(100% - 48px, 1280px);
    grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
    column-gap: clamp(32px, 4vw, 60px);
    align-items: start;
  }
  #vent .ev-grille > .ev-texte,
  #vent .ev-grille > .ev-scene { display: contents; }

  #vent .ev-grille > .ev-texte > .legende { grid-column: 1; grid-row: 1; }
  #vent .ev-grille > .ev-texte > .titre { grid-column: 1; grid-row: 2; max-width: 20ch; }
  #vent .ev-grille > .ev-scene > .ea,
  #vent .ev-grille > .ev-scene > .ea-fenetre {
    grid-column: 1 / -1;
    grid-row: 3;
    margin-top: clamp(26px, 3vw, 38px);
  }
  #vent .ev-grille > .ev-texte > .ev-etapes { grid-column: 1 / -1; grid-row: 4; }
  #vent .ev-grille > .ev-texte > .ev-cta { grid-column: 1; grid-row: 5; }
  #vent .ev-grille > .ev-scene > .ea-vrai {
    grid-column: 2;
    grid-row: 5;
    margin: clamp(28px, 3.2vw, 40px) 0 0;
    max-width: none;
  }

  /* le cadre à sa taille native, 1 280 × 800, donc 16/10 : l'affiche de repos
     a la bonne boîte AVANT que le script ne pose la hauteur exacte, et rien ne
     saute au démarrage */
  #vent .ea { height: auto; aspect-ratio: 16 / 10; max-width: none; }

  /* LA FRISE (les chapitres de `.chap-frise`, recopiés pour la seule largeur
     où cette présentation est en frise : en dessous, c'est une colonne).
     ⚠️ La barre est portée par chaque chapitre, pas par la liste : sous
     1 240 px la frise passe sur deux rangées, et une seule ligne en haut de la
     liste laisserait la seconde rangée sans repère. */
  #vent .ev-etapes {
    --chap-axe: x;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    column-gap: 12px;
    margin-top: clamp(20px, 2.2vw, 28px);
  }
  #vent .ev-etapes .chap { display: block; padding: 16px 12px 12px 0; border-radius: 0; }
  #vent .ev-etapes .chap::before { display: block; margin-bottom: 6px; }
  #vent .ev-etapes .chap-barre { left: 0; right: 0; top: 0; bottom: auto; width: auto; height: 2px; }
  #vent .ev-etapes .chap-barre i { transform: scaleX(0); }
}
@media (min-width: 1001px) and (hover: hover) {
  #vent .ev-etapes .chap:hover { background: transparent; }
}
/* six cases de 160 px donneraient trois lignes de texte : deux rangées de
   trois se lisent mieux */
@media (min-width: 1001px) and (max-width: 1239px) {
  #vent .ev-etapes {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    row-gap: 10px;
  }
}
/* FIN PRÉSENTATION ANIMATED */


/* ------------------------------------------------------------ 3. les chiffres */
.ch-grille {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  column-gap: clamp(40px, 6vw, 100px);
  align-items: center;
}
.ch-grille > .chiffres { grid-column: 1; grid-row: 1; margin: 0; }
.ch-grille > .ch-tete { grid-column: 2; grid-row: 1; }
.ch-tete .ch-source { margin: 22px 0 0; max-width: 44ch; }
.ch-grille .chiffres {
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  grid-template-rows: repeat(3, auto);
  border-top: 0;
  border-bottom: 0;
}
.ch-grille .ch-case + .ch-case { border-left: 0; }
.ch-grille .ch-case:first-child {
  grid-row: 1 / span 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-left: 0;
  border-right: 1px solid var(--trait);
}
.ch-grille .ch-case:first-child .ch-n { font-size: clamp(3.4rem, 6.2vw, 5.8rem); letter-spacing: -0.055em; white-space: nowrap; }
.ch-grille .ch-case:nth-child(n + 2) { padding-block: clamp(18px, 2vw, 26px); }
.ch-grille .ch-case:nth-child(n + 3) { border-top: 1px solid var(--trait); }
.ch-grille .ch-case:nth-child(n + 2) .ch-n { font-size: clamp(2rem, 3.2vw, 2.8rem); }

/* --------------------------------------------------------- 4. les trois gestes */
/* ⚠️ Plus sur l'accueil depuis le 16/09 (la section est devenue `#logiciels`,
   bloc « PRÉSENTATION DCC ») : ces règles servent `assetbrowser.html`. */
.gestes-grille {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  column-gap: clamp(40px, 6vw, 100px);
  align-items: start;
}
.gestes-tete { position: sticky; top: calc(var(--entete-h) + 40px); }
.gestes.escalier { grid-template-columns: 1fr; gap: 14px; margin-top: 0; }
.gestes.escalier .geste {
  width: 80%;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  column-gap: 20px;
  align-items: start;
}
.gestes.escalier .geste .n { grid-row: 1 / span 2; margin: 0; }
.gestes.escalier .geste > b { margin-top: 5px; }
.gestes.escalier .geste:nth-child(2) { margin-left: 10%; }
.gestes.escalier .geste:nth-child(3) { margin-left: 20%; }

/* ⚠️ LES SECTIONS 5 ET 6 NE SONT PLUS (15/09, nuit) : la mosaïque des
   bibliothèques et « où ça ressort » ont quitté l'accueil à la demande de
   l'éditeur, et leurs règles sont parties avec elles. */

/* ----------------------------------------------------------- 7. AssetBrowser */
/* La section `#bibliotheque` : son dessin vit dans le bloc « PRÉSENTATION
   ASSETBROWSER », plus haut. La capture fixe `#navigateur` et ses règles
   `.nav-*` sont parties avec le commit qui l'a retirée (15/09). */

/* --------------------------------------------------------------- 8. le temps */
/* ⚠️ DEUX LARGEURS, UN SEUL HAUT. Un premier jet décalait la seconde carte
   vers le bas — d'abord par une marge, qui agrandissait la rangée des DEUX
   cartes en `subgrid` (la première naissait avec 60 px de vide en tête), puis
   par une translation. Mais des hauts décalés dans une même rangée, c'est ce
   que `t-alignement` refuse depuis le 30/08 (« aligné au mm près ») : l'écart
   passe par la largeur. */
.mosaique.duo.inegale { max-width: none; margin-inline: 0; grid-template-columns: minmax(0, 1.18fr) minmax(0, 1fr); }

/* ------------------------------------------------------------- 9. la clôture */
.acte-grille {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  column-gap: clamp(40px, 5vw, 80px);
  align-items: center;
}
.acte-texte .titre { font-size: clamp(2.2rem, 4.1vw, 3.5rem); }
.acte-texte .actions { justify-content: flex-start; margin-top: clamp(28px, 3vw, 40px); }
.acte-note { margin: 14px 0 0; font-size: 12.5px; color: var(--encre-3); }
.acte-grille .acte-affiche {
  margin: 0 calc((100vw - min(100vw - 48px, var(--large))) / -2 - 40px) 0 0;
  max-width: none;
  border-radius: var(--r-l) 0 0 var(--r-l);
}

/* Everything : montrer la préparation des matériaux avant le catalogue des formats. */
.acte.acte-exports > .wrap.acte-grille { grid-template-columns: minmax(0, 1fr); gap: 40px; }
.acte.acte-exports > .wrap.acte-grille .ef-flow { margin: 0; padding: 0; border: 1px solid #303030; border-radius: 24px; background: #0D0D0D; overflow: hidden; }
.ef-flow { line-height: 1.5; color: #E5E5E7; }
.prep-header { padding: 32px 36px 0; }
.prep-header h3 { margin: 0; font-size: clamp(23px, 2.2vw, 30px); font-weight: 600; letter-spacing: -.025em; line-height: 1.25; max-width: 34ch; }
.prep-steps { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, .95fr) minmax(0, 1.05fr); list-style: none; padding: 0; margin: 28px 0 0; }
.prep-steps > li { position: relative; min-width: 0; padding: 8px 36px 36px; }
.prep-steps > li + li { border-left: 1px solid #303030; }
.prep-stage { margin: 0 0 26px; display: flex; align-items: center; gap: 10px; color: #FFAD70; font-size: 13px; font-weight: 600; }
.prep-stage > span:first-child { width: 26px; height: 26px; display: grid; place-items: center; border: 1px solid #73513A; border-radius: 50%; font-size: 12px; flex: none; }
.prep-steps h4 { margin: 0 0 14px; font-size: clamp(20px, 1.7vw, 25px); font-weight: 600; line-height: 1.25; letter-spacing: -.02em; }
.prep-description { margin: 0; font-size: 14px; line-height: 1.65; color: #B5B5BB; }
.prep-files { margin-top: 24px; }
.prep-files > div { display: flex; gap: 12px; align-items: center; padding: 13px 0; border-top: 1px solid #292929; }
.prep-files svg { width: 30px; height: 30px; color: #B5B5BB; flex: none; }
.prep-files b { display: block; font-size: 14px; font-weight: 500; }
.prep-files small { display: block; margin-top: 4px; font-size: 11px; line-height: 1.6; color: #96969E; }
.prep-note { margin: 20px 0 0; color: #ACACB2; font-size: 12px; line-height: 1.65; }
.prep-work { background: #1C1713; }
.prep-work::before, .prep-result::before { content: '→'; position: absolute; top: 50%; left: -16px; display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid #4A392B; border-radius: 50%; background: #1C1713; color: #FFAD70; z-index: 1; }
.ef-flow .prep-logo { display: block; width: 64px; height: 64px; object-fit: contain; margin-bottom: 22px; }
.prep-actions, .prep-checks { list-style: none; margin: 0; padding: 0; }
.prep-actions li { padding: 12px 0; border-top: 1px solid #3A2E25; font-size: 15px; line-height: 1.55; }
.prep-actions li:first-child { padding-top: 0; border-top: 0; }
.prep-checks { margin-top: 24px; }
.prep-checks li { position: relative; padding: 8px 0 8px 23px; font-size: 14px; }
.prep-checks li::before { content: '✓'; position: absolute; left: 0; color: #FFAD70; }
.ef-details { padding: 0 36px; border-top: 1px solid #303030; }
.ef-details summary { list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 0; cursor: pointer; color: #E5E5E7; font-size: 13px; }
.ef-details summary::-webkit-details-marker { display: none; }
.ef-details summary:hover { color: #FFAD70; }
.ef-details summary:focus-visible { outline: 2px solid #FFAD70; outline-offset: 4px; }
.ef-details-icon { font-size: 20px; line-height: 1; }
.ef-details[open] .ef-details-icon { transform: rotate(45deg); }
.prep-catalog { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); gap: 44px; padding: 12px 0 24px; }
.prep-catalog h4 { margin: 0 0 18px; font-size: 18px; font-weight: 500; }
.prep-catalog h5 { margin: 18px 0 8px; color: #ACACB2; font-size: 12px; font-weight: 500; }
.ef-flow dl, .ef-flow dd { margin: 0; }
.ef-sources > div { padding: 13px 0; border-top: 1px solid #292929; }
.ef-sources dt { font-size: 14px; font-weight: 500; margin-bottom: 6px; }
.ef-sources dd { font-size: 12px; line-height: 1.8; color: #ACACB2; }
.ef-formats, .ef-scenes code, .ef-formats-list dd { font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace; }
.ef-scenes > div { display: grid; grid-template-columns: 80px minmax(0, 1fr); gap: 12px; padding: 12px 0; border-bottom: 1px solid #292929; }
.ef-scenes dt { font-size: 14px; font-weight: 500; }
.ef-scenes dd { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 5px 12px; }
.ef-scenes code { font-size: 12px; color: #FFAD70; }
.ef-scenes dd span { font-size: 12px; color: #ACACB2; }
.ef-formats-list > div { display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 12px; padding: 8px 0; }
.ef-formats-list dt { font-size: 12px; color: #ACACB2; }
.ef-formats-list dd { font-size: 12px; line-height: 1.6; overflow-wrap: anywhere; }
.ef-formats-list dd span { font: 11px sans-serif; color: #ACACB2; }
.ef-detail-body { padding: 20px 0 26px; border-top: 1px solid #292929; }
.ef-detail-body p { margin: 0 0 12px; font-size: 13px; line-height: 1.7; color: #ACACB2; max-width: 95ch; }
.ef-detail-body p:last-child { margin-bottom: 0; }
@media (min-width: 901px) {
  .acte-exports .acte-texte { display: flex; align-items: center; justify-content: space-between; gap: 32px; }
  .acte-exports .acte-texte .actions { margin-top: 0; }
}
@media (max-width: 1100px) {
  .prep-steps > li { padding-inline: 24px; }
  .prep-header, .ef-details { padding-inline: 24px; }
  .prep-stage { font-size: 12px; }
}
@media (max-width: 800px) {
  .prep-steps { grid-template-columns: minmax(0, 1fr); margin-top: 24px; }
  .prep-steps > li { padding: 28px; }
  .prep-steps > li + li { border-left: 0; border-top: 1px solid #303030; }
  .prep-stage { font-size: 13px; margin-bottom: 18px; }
  .prep-header { padding: 28px 28px 0; }
  .prep-header h3 { max-width: 22ch; }
  .prep-work::before, .prep-result::before { top: -16px; left: calc(50% - 15px); transform: rotate(90deg); }
  .ef-flow .prep-logo { float: right; width: 48px; height: 48px; margin: 0 0 12px 16px; }
  .prep-actions { clear: both; }
  .prep-catalog { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .ef-details { padding-inline: 28px; }
  .ef-scenes dd { flex-direction: column; align-items: start; }
  .ef-formats-list > div { grid-template-columns: minmax(0, 1fr); gap: 3px; }
}

/* ---------------------------------------------------------------- 10. la FAQ */
.faq-grille {
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.38fr);
  column-gap: clamp(40px, 6vw, 100px);
  align-items: start;
}
.faq-tete { position: sticky; top: calc(var(--entete-h) + 40px); }
.faq-tete .faq-sortie { margin: 26px 0 0; max-width: 32ch; line-height: 1.6; }
.faq-grille .faq { max-width: none; margin: 0; }

/* ------------------------------------------------------ 11. les autres pages */
/* LES HÉROS ET LES BANDEAUX tiennent la gauche : la lumière est à droite
   (`data-lueur="droite"`), le texte lui répond. */
.hero:not(.hero-duo),
.bandeau { text-align: left; }
.hero:not(.hero-duo) .display { margin: 22px 0 0; max-width: 18ch; }
/* sans surtitre au-dessus (17/09), le titre ouvre la colonne */
.hero:not(.hero-duo) .wrap > .display:first-child { margin-top: 0; }
.hero:not(.hero-duo) .sous-titre,
.bandeau .sous-titre { margin-left: 0; margin-right: 0; max-width: 54ch; }
.hero:not(.hero-duo) .actions,
.bandeau .actions { justify-content: flex-start; }
.bandeau .ban-essai { margin-inline: 0; }

/* TROIS CARTES, TROIS LARGEURS NON ÉGALES — la première mène.
   ⚠️⚠️ PAS DE MARCHES. Le premier jet faisait descendre les cartes d'un cran
   chacune : `t-alignement` a sorti trois « colonnes qui ne partent pas du même
   haut » (56 px). Il porte la demande du 30/08, « tout doit être aligné au mm
   près », et l'asymétrie ne la révoque pas : elle passe par les largeurs. */
@media (min-width: 901px) {
  .gestes:not(.escalier),
  .claims.inegales,
  .grille.g3.inegales { grid-template-columns: minmax(0, 1.34fr) minmax(0, 1fr) minmax(0, 1fr); }
}

/* la légende de la vitrine AssetBrowser, sous le bord gauche du cadre */
.scene-leg { margin: clamp(14px, 2vw, 20px) 0 0; max-width: 66ch; font-size: 13.5px; line-height: 1.65; color: var(--encre-2); }
/* la clôture en miroir (AssetBrowser) : l'image à gauche, qui déborde */
.acte-grille.acte-inverse { grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr); }
.acte-grille.acte-inverse .acte-affiche {
  margin: 0 0 0 calc((100vw - min(100vw - 48px, var(--large))) / -2 - 40px);
  border-radius: 0 var(--r-l) var(--r-l) 0;
}

/* UNE COLONNE ÉTROITE tient la gauche de la page, plus son axe — sauf une
   carte de formulaire centrée (réinitialiser, vérifier), qui garde le sien. */
section > .wrap.etroit:not(:has(> .carte.centre)) {
  margin-left: max(24px, calc((100% - var(--large)) / 2));
  margin-right: auto;
}

/* LES PAGES LÉGALES : le titre reste à gauche pendant la lecture */
.wrap.etroit:has(> .prose) { max-width: var(--large); }
.prose {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 290px) minmax(0, 70ch);
  column-gap: clamp(40px, 6vw, 100px);
  align-items: start;
}
.prose > * { grid-column: 2; }
.prose > h1 {
  grid-column: 1;
  grid-row: 1 / span 400;
  position: sticky;
  top: calc(var(--entete-h) + 36px);
  font-size: clamp(1.9rem, 2.6vw, 2.5rem);
  text-wrap: balance;
}
.prose > h2:first-of-type { margin-top: 36px; }
.prose > .foinote { justify-self: start; }

/* LES TARIFS : la carte recommandée est la plus LARGE — pas la plus haute
   (des hauts décalés dans la rangée, `t-alignement` les refuse) */
@media (min-width: 1081px) {
  .tarifs { grid-template-columns: minmax(0, 1fr) minmax(0, 1.16fr) minmax(0, 1fr) minmax(0, 1fr); }
}
.tarifs-note { margin: 22px 0 0; max-width: 72ch; font-size: 13px; color: var(--encre-3); }

/* -------------------------------------------------------- UNE SEULE COLONNE */
@media (max-width: 1000px) {
  .ev-grille { grid-template-columns: 1fr; row-gap: 34px; }
  .ev-pied { grid-template-columns: 1fr; row-gap: 14px; }
}
@media (max-width: 900px) {
  .tete-sec,
  .ch-grille,
  .gestes-grille,
  .acte-grille,
  .faq-grille { grid-template-columns: 1fr; row-gap: 30px; }
  .tete-sec > .tete-sec-p { grid-column: 1; grid-row: auto; }
  .ch-grille > .ch-tete { grid-column: 1; grid-row: 1; }
  .ch-grille > .chiffres { grid-row: 2; }
  .gestes-tete, .faq-tete { position: static; }
  .gestes.escalier .geste,
  .gestes.escalier .geste:nth-child(2),
  .gestes.escalier .geste:nth-child(3) { width: 100%; margin-left: 0; }
  .acte-grille .acte-affiche { margin: 0; border-radius: var(--r-l); }
  .mosaique.duo.inegale { grid-template-columns: 1fr; }
  .acte-grille.acte-inverse { grid-template-columns: 1fr; }
  .acte-grille.acte-inverse .acte-affiche { margin: 0; border-radius: var(--r-l); }
  .prose { grid-template-columns: 1fr; }
  .prose > h1 { grid-column: 1; grid-row: auto; position: static; }
  .prose > * { grid-column: 1; }
}
@media (max-width: 760px) {
  .ch-grille .chiffres { grid-template-columns: 1fr 1fr; grid-template-rows: none; }
  .ch-grille .ch-case:first-child { grid-column: 1 / span 2; grid-row: auto; border-right: 0; }
  .ch-grille .ch-case:nth-child(2) { border-top: 1px solid var(--trait); }
  .ch-grille .ch-case:nth-child(3) { border-left: 1px solid var(--trait); }
}

/* ============================================================================
   L'ASYMÉTRIE DE LA PAGE, PAS SEULEMENT DES SECTIONS (15/09, nuit)
   « le site sur la page d'acceuil est partout est trop symétrique j'avais
   esssayé de casser ce cote la avec le launchher a droite mais après ca
   redevient trop symétrique »
   ============================================================================
   Relevé à 1 920 px avant de toucher : le héros tient la grille de la barre
   (1 280 px, texte sous la marque) et laisse son produit déborder à droite —
   puis CHAQUE section suivante se recentrait dans une colonne de 1 180 ou de
   1 320 px, avec la même marge des deux côtés. Les colonnes inégales du §
   précédent vivaient DANS un bloc centré : de loin, la page redevenait un axe.

   LE GESTE : chaque section choisit un CÔTÉ, sur quatre lignes et pas une de
   plus — pour que deux bords soient identiques ou franchement différents,
   jamais « presque » (`t-alignement`) :
     --axe   le bord de la grille de la barre (1 280 px centrés), à gauche et
             à droite : là où tombent la marque et le bouton du compte ;
     --bord  la gouttière du bord de l'écran, à gauche et à droite.
   `.cote-d` va de l'axe gauche au bord droit, `.cote-g` du bord gauche à
   l'axe droit, `.grille-barre` d'un axe à l'autre.
   ⚠️⚠️ LE TEXTE NE QUITTE JAMAIS LA GRILLE DE LA BARRE. Ce qui part vers un
   bord, c'est ce qui SE REGARDE : un cadre d'application, une image, un
   panneau de chiffres, une carte. Une ligne de lecture à 40 px du bord de
   l'écran se lit mal ; un cadre à 40 px se lit comme une fenêtre posée.
   L'alternance, de haut en bas : héros →, Everything →, AssetBrowser ←,
   Animated →, le launcher AU MILIEU (16/09, § « LE LAUNCHER AU MILIEU »),
   chiffres ←, logiciels →, temps ←, clôture →, FAQ →.

   ⚠️ LES CÔTÉS NE JOUENT QU'AU-DESSUS DE 1 400 px. Plus bas, l'axe et la
   gouttière se rapprochent jusqu'à tomber à quelques pixels l'un de l'autre
   (à 1 366 px : 43 contre 33), et un portable a déjà des marges minces —
   c'est sur un grand écran que la colonne centrée se voyait. Entre 1 101 et
   1 399 px, les sections tiennent seulement la grille de la barre.
   ⚠️ `--axe` est en POUR-CENT de la section, jamais en `vw` : `100vw` compte
   la barre de défilement, et le texte tombait à 8 px de la marque. Il ne se
   lit donc que sur un ENFANT DIRECT de section (plus bas, 100 % ne serait
   plus la section).
   ⚠️ LES DÉBORDEMENTS JUSQU'AU BORD MÊME DE L'ÉCRAN (panneau des chiffres,
   carte du temps, image de clôture) s'écrivent `marge négative + padding de
   même valeur` : le fond part au bord, le contenu ne bouge pas d'un pixel. La
   valeur, `(100vw - 1280px) / 2`, dépasse le bord de la moitié de la barre
   de défilement — ce surplus est hors de l'écran, `overflow-x: clip` le coupe.
   ========================================================================== */
@media (min-width: 1101px) {
  main > section > .wrap.grille-barre,
  main > section > .wrap.cote-d,
  main > section > .wrap.cote-g,
  #bibliotheque > .ev-grille { width: min(100% - 48px, 1280px); max-width: none; margin-inline: auto; }
  #montage .ev-scene .ea,
  #bibliotheque .ev-scene .ea { max-width: 1300px; }
}
@media (min-width: 1400px) {
  main > section {
    --bord: clamp(32px, calc(3vw - 12px), 64px);
    --axe: max(var(--bord), calc((100% - 1280px) / 2));
  }
  main > section > .wrap.cote-d { width: auto; margin-left: var(--axe); margin-right: var(--bord); }
  main > section > .wrap.cote-g,
  #bibliotheque > .ev-grille { width: auto; margin-left: var(--bord); margin-right: var(--axe); }

  /* LES CHIFFRES ← : les nombres dans un panneau qui part du bord gauche. */
  #chiffres > .wrap.grille-barre > .chiffres {
    margin-left: calc((100vw - 1280px) / -2);
    padding-left: calc((100vw - 1280px) / 2);
    background-color: var(--papier);
    border: 1px solid var(--trait);
    border-left: 0;
    border-radius: 0 var(--r-l) var(--r-l) 0;
  }

  /* LE TEMPS ← : la carte d'Everything part du bord gauche. */
  #temps > .wrap.grille-barre .carte-gain:first-child {
    margin-left: calc((100vw - 1280px) / -2);
    padding-left: calc((100vw - 1280px) / 2 + clamp(24px, 2.2vw, 30px));
    border-left: 0;
    border-radius: 0 var(--r-l) var(--r-l) 0;
  }

  /* LA CLÔTURE → : l'image part au bord droit, depuis la grille de la barre. */
  .acte > .wrap.grille-barre .acte-affiche { margin-right: calc((100vw - 1280px) / -2); }
}

/* LE LAUNCHER AU MILIEU, ET AUSSI GRAND QUE L'ÉCRAN LE PERMET (16/09)
   « le launcher tout en bas doit etre au milieu en grand par sur le coté »
   — l'éditeur. Mesuré avant, à 1 920 × 960 : un cadre de 1 280 × 800 collé
   au bord droit, 578 px de vide à sa gauche contre 46 à sa droite.
   Le bloc est centré à toutes les largeurs (la section n'a plus de `.cote-d`).
   Au-dessus de 1 400 px de large, la TAILLE du cadre suit la hauteur de
   l'écran PAR PALIERS, jamais en continu :
     sous 880 px de haut    la règle de base (`.cadre-app`), 16:10 — au plus
                            1 210 px de large à ces hauteurs ;
     880 px et plus         1 280 × 800 : exactement la grille de la barre, ses
                            bords tombent sur la marque et le bouton du compte ;
     940 px et plus, sur    aussi grand que la hauteur VISIBLE sous l'en-tête
     1 600 px de large      le permet, de 1 344 à 1 560 px de large.
   ⚠️⚠️ POURQUOI DES PALIERS. Une largeur qui suit la hauteur en continu passe
   forcément entre 1 256 et 1 304 px, où ses bords tombent à 1-12 px de la
   marque et du bouton du compte — qu'on voit en même temps, l'en-tête est
   collé : le « presque aligné » que cette feuille refuse (§ « L'ASYMÉTRIE DE
   LA PAGE »). Mesuré à 1 920 × 910 : 1 298 px, bords à 7,5 px de la marque.
   Le cadre est donc SUR la grille, ou nettement hors d'elle (32 px de chaque
   côté au moins), jamais à côté.
   ⚠️ `t-alignement` NE LE VOIT PAS : il ne compare pas l'en-tête, et n'oppose
   que des bords distants de moins de 700 px en hauteur. Calibré — la variante
   continue sort VERTE à 1 920 × 910. Ce sont les paliers qui tiennent la
   règle, par construction.
   ⚠️ Le grand palier se borne à la hauteur visible (écran − en-tête − 24 px
   d'air) : une application qu'on essaie se voit ENTIÈRE quand on est dessus.
   Et à la largeur de l'écran moins ses deux gouttières et 64 px : ses bords
   restent à plus de 24 px de la gouttière des sections voisines.
   ⚠️ Des unités d'ÉCRAN (vw, svh), pas de pour-cent : la scène est en
   `max-content`, et une largeur en pour-cent y serait circulaire.
   ⚠️ La largeur MÈNE et `aspect-ratio` en tire la hauteur : la forme reste
   16:10 à chaque palier. */
@media (min-width: 1400px) and (min-height: 880px) {
  #cadreLauncher { width: 1280px; height: 800px; }
}
@media (min-width: 1600px) and (min-height: 940px) {
  #cadreLauncher {
    width: clamp(1344px, (100svh - var(--entete-h) - 24px) * 1.6, min(1560px, 100vw - 2 * var(--bord) - 64px));
    height: auto;
    aspect-ratio: 16 / 10;
  }
}

/* ============================================================================
   LA PAGE APPLICATIONS, REFAITE (15/09, nuit)
   « refait entierrement aussi la page des applications avec la nouvelle DA.
   Fais une belle présentation html pour chaque apps je veux pas de symétrie je
   veux que ca soit aussi très lisible donc assez gros »
   ============================================================================
   UNE APPLICATION = UN CHAPITRE, et sa présentation est du vrai texte : le
   dossier déposé et la livraison d'Everything fichier par fichier, les
   captures réelles d'AssetBrowser, l'arbre et le rig d'Animated avec ses
   quatre forces de vent à l'échelle. Le cartouche d'`applications.html` dit
   d'où vient chaque nom et chaque nombre.
   ⚠️⚠️ LISIBLE, DONC GRAND. Relevé sur l'ancienne page : texte des panneaux à
   13,5 px, étapes à 13,5, légendes à 12,5. Ici, aucun texte de lecture sous
   15 px (légendes et noms de fichiers), le corps à 17-18, les chapeaux jusqu'à
   22 px, les titres de chapitre jusqu'à 66 px.
   ⚠️ L'ASYMÉTRIE vient des classes de côté de l'accueil (`.cote-d`, `.cote-g`,
   `.grille-barre`, § « L'ASYMÉTRIE DE LA PAGE ») : Everything →,
   AssetBrowser ←, Animated →, et le sommaire descend en escalier. Sous
   1 100 px tout redevient une colonne, alignée à gauche.
   ⚠️ Toutes ces classes commencent par `pa-` : cinq collisions de classe dans
   l'histoire du site (`.plan` deux fois), une préfixée ne peut pas en créer.
   ⚠️ Les décalages passent par des MARGES, jamais par `transform` :
   `mouvement.js` anime les enfants de `[data-anim="monte"]` en translation,
   et sa translation remplacerait la nôtre.
   ========================================================================== */

/* ------------------------------------------------------------ l'ouverture */
.pa-ouverture { padding-block: clamp(40px, 7svh, 96px) clamp(40px, 6svh, 88px); }
.pa-ouverture-grille {
  display: grid;
  grid-template-columns: minmax(0, 1.36fr) minmax(0, .82fr);
  grid-template-rows: 1fr auto auto;
  column-gap: clamp(40px, 6vw, 120px);
  /* ⚠️ `end`, pas `start` : le sommaire se cale sur le BAS du texte, et une
     rangée alignée au début exigerait de ses colonnes un haut commun
     (`t-alignement`) que l'escalier refuse par construction */
  align-items: end;
}
.pa-ouverture-grille > * { grid-column: 1; }
.pa-ouverture-grille > .dock { grid-column: 2; grid-row: 1 / span 3; align-self: end; }
/* ⚠️ PLUS DE SURTITRE (17/09) : le titre et le chapeau prennent les deux
   DERNIÈRES rangées, la première (en `1fr`) garde le bas du texte calé sur le
   bas du sommaire. En auto, le titre montait dans la rangée libre. */
.pa-ouverture-grille > .pa-titre { grid-row: 2; }
.pa-ouverture-grille > .pa-lead { grid-row: 3; }
.pa-titre {
  margin: 0;
  max-width: none;
  font-size: clamp(2.8rem, 4.3vw, 4.3rem);
  line-height: 1.02;
  letter-spacing: -0.044em;
}
.pa-lead {
  margin: 30px 0 0;
  max-width: 44ch;
  font-size: clamp(1.18rem, 1.5vw, 1.5rem);
  line-height: 1.55;
  letter-spacing: -0.008em;
  color: var(--encre-2);
  text-wrap: pretty;
}

/* LE SOMMAIRE : le dock des trois applications, en cartes qui descendent en
   escalier. ⚠️ La classe reste `dock` seule sur le `<nav>` (`t-catalogue`) :
   tout son dessin passe par `.pa-ouverture .dock`. */
.pa-ouverture .dock {
  display: grid;
  gap: 12px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.pa-ouverture .dock a {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 92px;
  padding: 18px 26px 18px 22px;
  border-radius: var(--r-l);
  border: 1px solid var(--trait);
  background-color: var(--papier);
  color: var(--encre);
  transition: border-color .2s, background-color .2s;
}
.pa-ouverture .dock a:hover {
  border-color: rgba(179, 179, 179, .38);
  background-color: #101010;
}
.pa-ouverture .dock a img { width: 48px; height: 48px; flex: none; }
.pa-som { display: grid; gap: 3px; min-width: 0; }
.pa-som b { font-size: clamp(1.2rem, 1.45vw, 1.45rem); font-weight: 500; letter-spacing: -0.02em; line-height: 1.2; }
.pa-som span { font-size: 15.5px; line-height: 1.4; color: var(--encre-2); }
@media (min-width: 1101px) {
  .pa-ouverture .dock a:nth-child(2) { margin-left: 8%; }
  .pa-ouverture .dock a:nth-child(3) { margin-left: 16%; }
}

/* ------------------------------------------------------- un chapitre */
.pa-chap { padding-block: clamp(96px, 11vw, 176px) 0; }
.pa-tete {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  column-gap: clamp(40px, 6vw, 120px);
  align-items: end;
  margin-bottom: clamp(48px, 5.4vw, 84px);
}
.pa-marque {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 28px;
}
.pa-marque img { width: 44px; height: 44px; flex: none; }
.pa-marque b { font-size: clamp(1.25rem, 1.6vw, 1.55rem); font-weight: 500; letter-spacing: -0.02em; line-height: 1.2; }
.pa-h {
  font-size: clamp(2.4rem, 4.3vw, 4.15rem);
  line-height: 1.04;
  letter-spacing: -0.038em;
  font-weight: 500;
  max-width: 17ch;
  text-wrap: balance;
}
.pa-h3 {
  font-size: clamp(1.6rem, 2.3vw, 2.2rem);
  line-height: 1.12;
  letter-spacing: -0.028em;
  font-weight: 500;
  text-wrap: balance;
}
.pa-chapeau {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(1.15rem, 1.4vw, 1.4rem);
  line-height: 1.6;
  letter-spacing: -0.006em;
  color: var(--encre-2);
  text-wrap: pretty;
}
.pa-texte { margin: 0; font-size: 18px; line-height: 1.65; color: var(--encre-2); max-width: 46ch; }
.pa-leg { margin: 0; font-size: 15px; line-height: 1.65; color: var(--encre-3); max-width: 72ch; }
.pa-note { margin: 16px 0 0; font-size: 15px; line-height: 1.55; color: var(--encre-3); }
.pa-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin: 34px 0 0;
}
.pa-actions .lien-fleche { font-size: 16.5px; }

/* LE PASSAGE : le logo de l'application entre ce qui entre et ce qui sort */
.pa-passage { display: grid; justify-items: center; gap: 16px; }
.pa-passage img {
  width: 56px;
  height: 56px;
  filter: drop-shadow(0 12px 26px rgba(106, 106, 106, .55));
}
.pa-fleche {
  position: relative;
  display: block;
  width: clamp(44px, 4.6vw, 88px);
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(179, 179, 179, .15), var(--bleu-clair));
}
.pa-fleche::after {
  content: '';
  position: absolute;
  right: -1px;
  top: 50%;
  width: 9px;
  height: 9px;
  border-top: 2px solid var(--bleu-clair);
  border-right: 2px solid var(--bleu-clair);
  transform: translateY(-50%) rotate(45deg);
}

/* --------------------------------------- 01 · la livraison d'Everything */
.pa-livraison {
  display: grid;
  grid-template-columns: minmax(0, .9fr) auto minmax(0, 1.3fr);
  column-gap: clamp(18px, 2.4vw, 40px);
  row-gap: 22px;
  align-items: center;
}
.pa-livraison > .pa-leg { grid-column: 1 / -1; }
.pa-dossier {
  margin: 0;
  padding: clamp(24px, 2.6vw, 38px);
  border-radius: 22px;
  border: 1px solid var(--trait);
  background-color: var(--papier);
  min-width: 0;
}
.pa-sortie { border-color: rgba(179, 179, 179, .28); background-color: #0F0F0F; }
.pa-dossier-t {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 20px;
  font-size: 15px;
  font-weight: 500;
  color: var(--bleu-clair);
}
.pa-dossier-t::before {
  content: '';
  width: 7px;
  height: 7px;
  flex: none;
  border-radius: 50%;
  background: var(--bleu-clair);
}
.pa-racine,
.pa-fichiers { font-family: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace; }
.pa-racine {
  margin: 0 0 12px;
  font-size: 16px;
  color: var(--encre);
  overflow-wrap: anywhere;
}
.pa-fichiers {
  margin: 0;
  padding: 0 0 0 16px;
  list-style: none;
  border-left: 1px solid var(--trait-fort);
  font-size: 15px;
  line-height: 1.9;
  color: var(--encre-2);
}
.pa-fichiers li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pa-fichiers .ext { color: var(--bleu-clair); }
.pa-groupes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 30px clamp(20px, 2.4vw, 36px);
}
.pa-groupe-t { margin: 0 0 10px; font-size: 16px; font-weight: 500; line-height: 1.35; color: var(--encre); }

/* sept gestes contre un */
.pa-duel {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(16px, 2vw, 26px);
  margin-top: clamp(64px, 7vw, 112px);
}
.pa-main,
.pa-avec { padding: clamp(28px, 3.2vw, 52px); border-radius: 24px; }
.pa-main { border: 1px solid var(--trait); }
.pa-avec {
  border: 1px solid rgba(179, 179, 179, .34);
  background-color: #111111;
}
.pa-duel-t { margin: 0 0 20px; font-size: 15px; font-weight: 500; color: var(--encre-3); }
.pa-avec .pa-duel-t { color: var(--bleu-clair); }
.pa-etapes { margin: 0; padding: 0; list-style: none; counter-reset: pa; }
.pa-etapes li {
  counter-increment: pa;
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 12px 0;
  border-top: 1px solid var(--trait);
  font-size: 18px;
  line-height: 1.45;
  color: var(--encre-2);
}
.pa-etapes li::before {
  content: counter(pa, decimal-leading-zero);
  flex: none;
  font-size: 13px;
  font-weight: 500;
  color: var(--encre-3);
  font-variant-numeric: tabular-nums;
}
.pa-verdict { margin: 20px 0 0; font-size: 16.5px; line-height: 1.55; color: var(--encre-3); }
.pa-seul {
  margin: 4px 0 0;
  font-size: clamp(2.3rem, 4vw, 3.8rem);
  line-height: 1.04;
  letter-spacing: -0.038em;
  font-weight: 500;
  color: var(--encre);
}
.pa-avec .pa-verdict { max-width: 34ch; font-size: 18px; color: var(--encre-2); }
.pa-puces { display: flex; flex-wrap: wrap; gap: 9px; margin: 30px 0 0; padding: 0; list-style: none; }
.pa-puces li {
  padding: 9px 16px;
  border-radius: var(--r-pill);
  border: 1px solid var(--trait-fort);
  background: rgba(255, 255, 255, .03);
  font-size: 15px;
  font-weight: 500;
  color: var(--encre);
}

/* LA BANDE : CE QUI ENTRE, LA FLÈCHE, ET LE MUR QUI DÉFILE (16/09)
   Demandé deux fois par l'éditeur : « plus d'assets qu'on peut défiler […] une
   flèche animée qui va sur le thumbnail », puis « retravaille encore plus cette
   partie ». La première version était juste et INERTE : une rangée arrêtée, un
   fichier posé, une flèche discrète. Ce qui manquait n'était pas du contenu,
   c'était le MOUVEMENT — la conversion doit se voir se faire.
   ⚠️⚠️ CE QUI BOUGE, ET CE QUI L'ARRÊTE. Le mur avance tout seul (le train est
   écrit DEUX FOIS et on translate de la moitié : la boucle est invisible, et
   il n'y a pas une image de blanc au raccord) ; les formats s'allument l'un
   après l'autre ; une lumière court le long de la flèche. Le survol, le focus
   clavier et « mouvement réduit » arrêtent les trois — et sans animation le
   mur redevient une piste qu'on pousse à la main, les formats tous allumés :
   on ne montre pas la moitié d'une liste à qui a demandé que rien ne bouge.
   ⚠️ LE DÉFILEMENT EST UNE TRANSLATION, jamais un `scrollLeft` animé : la
   première est composée par le processeur graphique, le second repeint à
   chaque image — sur une page qui porte déjà trois présentations et la nappe.
   ⚠️ La durée est celle d'une LECTURE, pas d'un carrousel : 72 s pour trente
   cartes, soit une carte toutes les 2,4 s. Plus vite, on ne lit plus les noms. */
.pa-bande { margin-top: clamp(64px, 7vw, 112px); }
.pa-conv {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  align-items: center;
  column-gap: clamp(12px, 1.5vw, 24px);
}
.pa-source {
  display: grid;
  justify-items: center;
  gap: 10px;
  width: clamp(132px, 12.5vw, 172px);
  padding: 20px 14px;
  border: 1px solid var(--trait);
  border-radius: 22px;
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(179, 179, 179, .12), transparent 70%),
    rgba(255, 255, 255, .02);
  color: var(--bleu-clair);
}
.pa-fichier { display: block; width: 36px; height: 44px; }
.pa-src-t { font-size: 14.5px; line-height: 1.3; text-align: center; color: var(--encre); }
.pa-src-ext { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
/* ⚠️ Chaque pastille porte son rang (`--i`) et la feuille en dérive son retard :
   aucune ligne de script pour faire courir la lumière sur cinq formats. */
.pa-fmt {
  padding: 3px 8px;
  border: 1px solid var(--trait);
  border-radius: 999px;
  /* ⚠️ 12 px, PAS 11,5 : `t-iphone` a mordu ici aussi. Le plancher de
     lisibilite vaut pour TOUT texte visible, pas seulement pour les legendes. */
  font-size: 12px;
  line-height: 1.25;
  color: var(--encre-3);
  animation: pa-fmt 6s linear infinite;
  animation-delay: calc(var(--i) * 1.2s);
}
@keyframes pa-fmt {
  0%, 9% { color: var(--encre); border-color: rgba(179, 179, 179, .55); background: rgba(179, 179, 179, .14); }
  22%, 100% { color: var(--encre-3); border-color: var(--trait); background: transparent; }
}
.pa-fleche { color: var(--bleu-clair); }
.pa-fleche svg { display: block; width: clamp(56px, 7vw, 132px); height: 16px; }
.pa-fleche .pa-trait { opacity: .45; animation: pa-file 1.6s linear infinite; }
.pa-fleche .pa-pulse { animation: pa-pulse 1.9s ease-in-out infinite; }
@keyframes pa-file { to { stroke-dashoffset: -15px; } }
@keyframes pa-pulse {
  0% { transform: translateX(0); opacity: 0; }
  12% { opacity: 1; }
  78% { opacity: .85; }
  100% { transform: translateX(94px); opacity: 0; }
}
/* ⚠️ Le masque éteint les deux bords : sans lui, une carte se coupe NET contre
   le bord de l'écran et la boucle se voit au raccord. */
.pa-mur {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 28px, #000 calc(100% - 110px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 28px, #000 calc(100% - 110px), transparent);
}
.pa-train { display: flex; gap: 14px; width: max-content; animation: pa-defile 72s linear infinite; }
@keyframes pa-defile { to { transform: translateX(calc(-50% - 7px)); } }
.pa-mur:hover .pa-train,
.pa-mur:focus-within .pa-train { animation-play-state: paused; }
.pa-train figure {
  position: relative;
  margin: 0;
  width: clamp(150px, 14vw, 196px);
  aspect-ratio: 1 / 1;
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--trait);
  background: #151416;
  transition: transform .35s cubic-bezier(.2, .7, .3, 1), border-color .35s;
}
.pa-train figure:hover { transform: translateY(-6px); border-color: rgba(179, 179, 179, .5); }
.pa-train img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* ⚠️ DEUX LIGNES, PAS UNE ELLIPSE : à 196 px de carte, « KitBash3D — Enchanted
   Interiors » sortait « KitBash3D — En… », qui ne nomme plus rien. */
.pa-train figcaption b {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  white-space: normal;
  line-height: 1.25;
}
/* ⚠️ 12 px est le PLANCHER de lisibilité du site : `t-iphone` a mordu sur cette
   ligne à 11,5. Elle passe à 12,5 au téléphone, comme les légendes. */
.pa-train figcaption span { display: block; margin-top: 2px; color: var(--encre-3); font-size: 12px; }
@media (prefers-reduced-motion: reduce) {
  .pa-fleche .pa-trait { animation: none; }
  .pa-fleche .pa-pulse { animation: none; }
  .pa-fmt { animation: none; color: var(--encre); }
  .pa-train { animation: none; }
  /* plus de défilement automatique : le mur redevient une piste qu'on pousse */
  .pa-mur { overflow-x: auto; scroll-snap-type: x proximity; }
  .pa-train figure { scroll-snap-align: start; }
}
/* les logiciels et les moteurs que la livraison atteint — des NOMS, pas des
   logos de tiers (cartouche de `tools/pa-bande.py`) */
.pa-cibles { list-style: none; margin: 26px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 12px 32px; }
.pa-cibles li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.pa-cibles b {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--encre-3);
}
.pa-cibles span {
  padding: 7px 14px;
  border: 1px solid var(--trait);
  border-radius: 999px;
  font-size: 14.5px;
  line-height: 1.2;
  color: var(--encre);
  background: rgba(255, 255, 255, .02);
}
.pa-train figcaption,

.pa-arbre figcaption {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  padding: 7px 13px;
  border-radius: var(--r-pill);
  background: rgba(10, 10, 11, .82);
  border: 1px solid rgba(192, 192, 192, .18);
  font-size: 13.5px;
  font-weight: 500;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pa-bande > .pa-leg { margin-top: 18px; }

/* ------------------------------------------------- 02 · AssetBrowser */
.pa-ab {
  display: grid;
  grid-template-columns: minmax(0, 1.14fr) minmax(0, .86fr);
  column-gap: clamp(40px, 6vw, 120px);
  row-gap: 22px;
  align-items: center;
}
.pa-ab-visuel { position: relative; padding-bottom: 17%; min-width: 0; }
.pa-capture {
  margin: 0;
  line-height: 0;
  border-radius: 18px;
  overflow: hidden;
  background: var(--papier);
  box-shadow: var(--anneau);
}
.pa-capture img { width: 100%; height: auto; display: block; }
.pa-capture-grille {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 54%;
  box-shadow: var(--anneau);
}
.pa-capture-mur { width: 88%; }
.pa-ab-texte { min-width: 0; }
.pa-ab .pa-h { max-width: 14ch; }

.pa-geste {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr);
  column-gap: 18px;
  padding: 26px 0 4px;
  border-top: 1px solid var(--trait-fort);
}
.pa-geste + .pa-geste { margin-top: 18px; }
.pa-geste-n {
  font-size: clamp(1.9rem, 2.6vw, 2.5rem);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--bleu-clair);
  font-variant-numeric: tabular-nums;
}
.pa-geste > div > b { display: block; margin: 2px 0 10px; font-size: 20px; font-weight: 500; line-height: 1.3; letter-spacing: -0.016em; color: var(--encre); }
.pa-geste > div > p { margin: 0; font-size: 17px; line-height: 1.65; color: var(--encre-2); }
.pa-geste > div > p b { color: var(--encre); font-weight: 500; }

/* ----------------------------------------------------- 03 · Animated */
.pa-rig {
  display: grid;
  grid-template-columns: minmax(0, .78fr) minmax(0, 1fr) auto minmax(0, 1fr);
  column-gap: clamp(18px, 2.4vw, 40px);
  align-items: center;
}
.pa-rig-chiffre { min-width: 0; }
.pa-rig-n {
  display: block;
  font-size: clamp(3.4rem, 6.2vw, 6.2rem);
  font-weight: 400;
  line-height: .95;
  letter-spacing: -0.055em;
  color: var(--encre);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pa-rig-t { margin: 14px 0 0; max-width: 20ch; font-size: 18px; line-height: 1.45; color: var(--encre-2); }
.pa-rig-chiffre .pa-leg { margin-top: 24px; max-width: 34ch; }
.pa-arbre {
  position: relative;
  margin: 0;
  aspect-ratio: 1 / 1;
  border-radius: 22px;
  overflow: hidden;
  border: 1px solid var(--trait);
  background: #121113;
  min-width: 0;
}
.pa-arbre img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pa-arbre-rig { border-color: rgba(179, 179, 179, .34); }

.pa-vent {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  column-gap: clamp(40px, 6vw, 120px);
  align-items: center;
  margin-top: clamp(72px, 8vw, 128px);
}
/* ⚠️⚠️ LA COLONNE DU VENT : L'ARBRE AU-DESSUS, L'ÉCHELLE DESSOUS (16/09).
   Demande de l'éditeur : « en dessous je veux voir l'arbre animé avec les 4
   variants de vent ». Le module `forces-sapp.js` y joue quatre VIDÉOS du
   Carya ovata des tuiles — l'export d'Animated rendu dans Blender, une par
   force (`assets/vent-carya/forces.json`) — et la ligne en cours prend `.on`.
   ⚠️ La légende vit SOUS ce qui bouge, dans la MÊME colonne : posée à côté, on
   la lit une fois et plus jamais. Un mouvement sans échelle ne dit pas qu'il y
   a 16 m/s dans la tempête.
   ⚠️ LA TROISIÈME CARTE (16/09, soir) : la vidéo est rendue CARRÉE, sur le
   fond des deux tuiles du dessus (`#121113`), que `tools/vent-carya.py` LIT
   dans la règle `.pa-arbre` — changer l'un sans rendre l'autre fait rougir
   `t-forces-sapp`, qui compare les pixels du ciel à la couleur de la carte.
   Le module pose EN LIGNE `position`, `overflow` et le rapport LU dans le
   manifeste (1 000 × 1 000) : la feuille ne fixe aucun rapport ; elle donne
   l'arrondi, le filet et le fond de la carte. */
.pa-vent-scene { display: grid; gap: clamp(14px, 1.6vw, 22px); align-content: start; min-width: 0; }
.pa-vent-cadre { min-width: 0; border-radius: 22px; border: 1px solid var(--trait); background: #121113; }
/* les quatre images fixes de « mouvement réduit » : une par force */
.vt-fixes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.vt-fixes > * { width: 100%; height: auto; display: block; border-radius: 16px; border: 1px solid var(--trait); background: #151416; }
.pa-forces {
  display: grid;
  gap: 22px;
  margin: 0;
  padding: clamp(28px, 3.2vw, 52px);
  list-style: none;
  border-radius: 24px;
  border: 1px solid var(--trait);
  background-color: var(--papier);
}
.pa-forces li {
  display: grid;
  grid-template-columns: minmax(8.5em, auto) minmax(0, 1fr) minmax(5.5em, auto);
  align-items: center;
  column-gap: 20px;
  font-size: 18px;
}
.pa-force-n { font-weight: 500; color: var(--encre); transition: color .3s ease; }
/* ⚠️ La force en cours s'allume — une TRANSITION, pas une animation : rien ne
   boucle ici, c'est le module qui décide quand la ligne change, et sous
   « mouvement réduit » il ne change jamais. */
.pa-forces li.on .pa-force-n { color: var(--bleu-clair); }
.pa-forces li.on .pa-force-v { color: var(--encre); }
.pa-forces li.on .pa-force-barre::after { box-shadow: 0 0 20px rgba(179, 179, 179, .55); }
.pa-force-barre::after { transition: box-shadow .3s ease; }
.pa-force-v { text-align: right; color: var(--encre-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pa-force-barre { position: relative; height: 10px; border-radius: var(--r-pill); background: rgba(255, 255, 255, .06); overflow: hidden; }
.pa-force-barre::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: inherit;
  background: linear-gradient(90deg, rgba(106, 106, 106, .55), var(--bleu-clair));
}
/* à l'échelle des vitesses de l'application, sur 16 m/s (renderer.js) */
.pa-forces li:nth-child(1) .pa-force-barre::after { width: 12.5%; }
.pa-forces li:nth-child(2) .pa-force-barre::after { width: 34.375%; }
.pa-forces li:nth-child(3) .pa-force-barre::after { width: 62.5%; }
.pa-forces li:nth-child(4) .pa-force-barre::after { width: 100%; }
.pa-vent-texte .pa-h3 { margin: 0 0 18px; }
.pa-points { display: grid; gap: 18px; margin: 30px 0 0; padding: 0; list-style: none; }
.pa-points li { display: grid; gap: 4px; padding-left: 20px; border-left: 2px solid rgba(179, 179, 179, .4); }
.pa-points b { font-size: 18px; font-weight: 500; color: var(--encre); }
.pa-points span { font-size: 16.5px; line-height: 1.6; color: var(--encre-2); }

/* ------------------------------------------------------ où ça s'ouvre */
.pa-logiciels { padding-top: clamp(112px, 12vw, 192px); }
.pa-logiciels-grille {
  display: grid;
  grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr);
  column-gap: clamp(40px, 6vw, 120px);
  align-items: start;
}
.pa-logiciels-grille .pa-chapeau { margin-top: 26px; }
.pa-familles { display: grid; gap: 30px; }
.pa-famille { padding-top: 20px; border-top: 1px solid var(--trait); }
.pa-famille-t { margin: 0 0 14px; font-size: 15px; font-weight: 500; color: var(--encre-3); }
.pa-famille .dcc { justify-content: flex-start; gap: 10px; margin: 0; }
.pa-famille .dcc span { padding: 10px 19px; font-size: 16.5px; color: var(--encre); }

/* ------------------------------------------------------------ l'appel */
.pa-appel-grille {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  column-gap: clamp(40px, 6vw, 120px);
  align-items: end;
}
.pa-appel-h { max-width: 14ch; font-size: clamp(2.6rem, 4.8vw, 4.6rem); }
.pa-appel .pa-actions { justify-content: flex-start; }

/* ----------------------------------------- les côtés, au-dessus de 1 400 px */
@media (min-width: 1400px) {
  /* la bande part jusqu'au bord même de l'écran : la piste y défile, et ce
     qu'elle laisse dépasser est ce qui donne envie de la pousser */
  main > section > .wrap.cote-d.pa-bande { margin-right: 0; }
}

/* ------------------------------------------------------ une colonne */
/* ⚠️ LA LIVRAISON S'EMPILE DÈS 1 320 px : le nom le plus long du dossier
   d'entrée (40 caractères en chasse fixe) ne tient plus dans sa colonne en
   dessous, et on le couperait d'une ellipse plutôt que de réduire le corps. */
@media (max-width: 1320px) {
  .pa-livraison { grid-template-columns: minmax(0, 1fr); }
  .pa-livraison > .pa-passage { grid-auto-flow: column; justify-content: start; align-items: center; }
  .pa-livraison > .pa-passage .pa-fleche { transform: rotate(90deg); margin-left: 10px; }
}
@media (max-width: 1240px) {
  .pa-rig { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); row-gap: 34px; }
  .pa-rig > .pa-rig-chiffre { grid-column: 1 / -1; }
}
@media (max-width: 1100px) {
  .pa-ouverture-grille,
  .pa-tete,
  .pa-duel,
  .pa-ab,
  .pa-vent,
  .pa-logiciels-grille,
  .pa-appel-grille { grid-template-columns: minmax(0, 1fr); row-gap: 30px; }
  .pa-ouverture-grille { grid-template-rows: none; }
  .pa-ouverture-grille > .dock,
  .pa-ouverture-grille > .pa-titre,
  .pa-ouverture-grille > .pa-lead { grid-row: auto; }
  .pa-ouverture-grille > .dock { grid-column: 1; margin-top: 18px; }
  .pa-ab-texte { grid-row: 1; }
  .pa-vent-texte { grid-row: 1; }
  /* la piste garde sa forme : elle défile déjà, elle n'a pas besoin de
     se replier en grille */
  .pa-conv { grid-template-columns: auto minmax(0, 1fr); row-gap: 16px; }
  .pa-fleche { display: none; }
}
@media (max-width: 760px) {
  .pa-titre { font-size: clamp(2.4rem, 10vw, 3.2rem); }
  .pa-h { font-size: clamp(2rem, 8.4vw, 2.6rem); }
  .pa-chap { padding-top: clamp(72px, 18vw, 104px); }
  .pa-ouverture .dock a { min-height: 76px; padding: 14px 18px; gap: 14px; }
  .pa-ouverture .dock a img { width: 40px; height: 40px; }
  .pa-groupes { grid-template-columns: minmax(0, 1fr); gap: 24px; }
  .pa-rig { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 12px; }
  .pa-rig > .pa-passage { display: none; }
  .pa-conv { grid-template-columns: minmax(0, 1fr); row-gap: 14px; }
  .pa-source { width: auto; grid-auto-flow: column; justify-items: start;
    align-items: center; gap: 12px; padding: 12px 16px; }
  .pa-src-t, .pa-src-ext { text-align: left; }
  .pa-forces li { grid-template-columns: minmax(0, 1fr) auto; row-gap: 8px; font-size: 16.5px; }
  .pa-forces .pa-force-barre { grid-column: 1 / -1; grid-row: 2; }
  .pa-etapes li { font-size: 17px; }
  .pa-arbre figcaption, .pa-train figcaption { font-size: 12.5px; white-space: normal; line-height: 1.25; }
  .pa-train figcaption span { font-size: 12.5px; }
  /* au téléphone un nom de fichier passe à la ligne plutôt que d'être coupé
     d'une ellipse : la présentation n'a de sens que si on lit les noms */
  .pa-fichiers li { white-space: normal; overflow-wrap: anywhere; line-height: 1.5; padding-block: 3px; }
}

/* ------------------------------- les démonstrations sur un iPad en paysage */
/* ⚠️⚠️ SUR UN ÉCRAN TACTILE DE 1 001 À 1 400 px (iPad en paysage, iPad Pro), LA
   DÉMONSTRATION PREND TOUTE LA LARGEUR (17/09). En deux colonnes, l'application
   n'avait que 714 px : 0,55 sans caméra, et à l'échelle de la caméra (0,85) le
   corps d'Animated (898 points) ne tenait plus dans sa fenêtre — l'en-tête ou
   la ligne de temps coupés à chaque geste (19 % des textes). Pleine largeur,
   1 132 px à 1 180 : Animated à 0,88, Everything à 0,87, AssetBrowser à 0,79 —
   l'application ENTIÈRE, lisible, et `camera-presentations.js` ne se pose pas
   (seuil 0,72).
   ⚠️ Un iPad avec un trackpad annonce `(hover: hover)` : deux colonnes, comme
   un ordinateur. */
@media (hover: none) and (pointer: coarse) and (min-width: 1001px) and (max-width: 1400px) {
  /* ⚠️ `.miroir` aussi : son `minmax(0, 1fr) minmax(0, 360px)` pèse 0,2,0 et
     battait la règle seule — AssetBrowser restait dans une colonne de 360 px */
  .ev-grille,
  .ev-grille.miroir { grid-template-columns: minmax(0, 1fr); row-gap: 34px; }
  .ev-grille.miroir > .ev-scene,
  .ev-grille.miroir > .ev-texte { grid-column: auto; grid-row: auto; }
}

/* -------------------------------------------------- la lecture au téléphone */
/* ⚠️⚠️ « TOUT EST ILLISIBLE » SUR IPHONE (17/09). Mesuré à 390 px sur les
   cinq pages publiques, texte par texte : les PHRASES secondaires tenaient
   entre 12 et 13,5 px — la note sous chaque démonstration (~1 000 caractères
   à 13 px), la source des chiffres, les promesses d'AssetBrowser, la légende
   du launcher, l'explication de l'empreinte, les notes sous les boutons. Sur
   un ordinateur on les lit à 60 cm ; au téléphone ce sont des paragraphes
   entiers. Repère : les styles de texte d'iOS donnent 17 au corps, 15 au
   sous-titre, 13 à la note de bas de page et 12 à la légende.
   · une phrase qu'on lit monte à 15 px, une note d'une ligne à 14 ;
   · une étiquette (pastille, graduation, en-tête de tableau) à 13 ;
   · les cibles tactiles qui restaient sous 44 px (fil d'Ariane, adresse de
     contact, empreinte) gagnent une zone de toucher, pas une taille de texte.
   ⚠️ CE BLOC EST LE DERNIER DE LA FEUILLE, exprès : à spécificité égale la
   règle la plus TARDIVE gagne, et plusieurs de ces classes sont définies
   loin après le bloc « téléphone » (la note du launcher, les tarifs, la
   page Applications). Placé plus haut, il perdait en silence. */
@media (max-width: 760px) {
  .ea-vrai, .scene-leg, .claim span, .rassure span,
  .pr-lib span, .pr-vide {
    font-size: 15px;
    line-height: 1.6;
  }
  .ch-source, .ev-sous, .hero-note, .acte-note, .tarifs-note,
  .dl-note, .dl-meta, .legende, .estim-lecture small, .pr-note,
  .carte-gain .gain-lg, .bilan, .faq-sortie,
  .prose .maj, .prose .foinote, .ab-affiche figcaption, .sieges-n,
  .accord, .tiers-ou {
    font-size: 14px;
    line-height: 1.55;
  }
  /* ⚠️ `.ev-sous` était bornée à 34 caractères : à 14 px, trois mots par ligne */
  .ev-sous { max-width: 44ch; }
  .postes li, .empreinte > summary { font-size: 13.5px; }
  .postes em { font-size: 12.5px; }
  .ea-src, .graduations span, .estim-chip, .compare thead th, .compare .groupe td,
  .champ > span, .identite .champ > span, .geste .n, .puce, #dlSha,
  .pa-cibles b, .pa-fmt, .ac-t, .ac-moteurs span, .mega-titre, .mega-fam {
    font-size: 13px;
  }
  .pied { font-size: 15px; }
  /* la piste d'assets d'Applications : des cartes un peu plus larges, pour
     que le nom (deux lignes) reste à la taille des légendes du bureau */
  .pa-train figure { width: 172px; }
  .pa-arbre figcaption, .pa-train figcaption { font-size: 13.5px; }
  .pa-train figcaption span { font-size: 13px; }

  /* la zone de toucher, sans rien bouger à la mise en page : un rembourrage
     vertical sur un élément EN LIGNE agrandit la cible, pas la ligne */
  .fil a, .faq-sortie a { padding-block: 12px; }
  .fil a { padding-inline: 4px; margin-inline: -4px; }
  .empreinte > summary { min-height: 44px; }

  /* ⚠️⚠️ LE TABLEAU DES DONNÉES SE LIT DE HAUT EN BAS (17/09). Il était
     `display: block; overflow-x: auto` : trois colonnes dans 390 px, donc la
     troisième — la BASE LÉGALE — coupée net au bord de l'écran, et rien pour
     dire qu'on pouvait la faire glisser (« Consenter… », « Obligation
     légale » tronqués sur la capture du banc `t-affichage`). Un tableau de
     trois colonnes n'entre pas dans un téléphone : chaque ligne se lit donc
     en trois temps — la donnée, sa raison, sa base légale en note.
     ⚠️ L'en-tête de colonnes est masqué : empilé, il ne nomme plus rien, et
     chaque cellule se reconnaît à sa place et à son style.
     ⚠️ C'est la SEULE page qui porte un tableau de prose (mesuré) : les CGV,
     les conditions et les mentions légales n'en ont aucun. */
  .prose table, .prose tbody, .prose tr, .prose td { display: block; }
  .prose thead { display: none; }
  .prose table { overflow-x: visible; }
  .prose tr { padding: 14px 0; border-top: 1px solid var(--trait); }
  .prose td { padding: 0; border: 0; }
  .prose td:first-child { color: var(--encre); font-weight: 500; }
  .prose td + td { margin-top: 5px; }
  .prose td:nth-child(3):last-child { font-size: 13.5px; color: var(--encre-3); }
}

/* ⚠️⚠️ AU TÉLÉPHONE, LA DÉMONSTRATION MONTE SOUS LE TITRE (17/09 au soir).
   « fais en sorte que les présentations des applications rendent super bien
   sur iPhone car là c'est pas le cas » — l'éditeur. Filmé à 390 px : on lisait
   l'étiquette, le titre, SIX étapes, un bouton et une note avant d'apercevoir
   l'application, et la liste des étapes — qui dit ce qu'on est en train de
   regarder — restait hors de l'écran pendant toute la démonstration. Sur un
   ordinateur les deux colonnes se lisent d'un coup d'œil ; en une seule
   colonne, c'est l'ORDRE qui doit changer, pas la taille.
   `display: contents` sort les deux colonnes de la grille : leurs enfants en
   deviennent les cases, et chacun prend sa place — l'application se glisse
   entre le titre et les étapes, la note et le pied descendent sous le bouton.
   Mesuré après : le haut du cadre passe de 1 180 à 300 px du haut de la
   section, et le cadre ET les six étapes tiennent dans le même écran.
   ⚠️ Les deux éléments gardent leurs enfants et leurs crochets : `mouvement.js`
   anime `[data-anim="monte"] > *`, `camera-presentations.js` pose sa fenêtre
   autour de `.ea` (elle devient alors la case), et les quatre scripts de
   présentation ne cherchent que dans leur section.
   ⚠️ Un élément en `display: contents` N'A PLUS DE RECTANGLE : une sonde qui
   cadrait `.ev-scene` visait (0, 0). Les instruments mesurent la FENÊTRE
   (`.ea-fenetre, .ea`), ce qu'ils voulaient dire depuis le début. */
@media (max-width: 760px) {
  .ev-grille > .ev-texte,
  .ev-grille > .ev-scene { display: contents; }
  .ev-grille { row-gap: 18px; }
  /* ⚠️ L'ORDRE PAR DÉFAUT EST 0, DONC AVANT TOUT CE QUI EST NUMÉROTÉ : le
     chapeau de #montage, que rien ne nommait, passait devant son titre. Chaque
     colonne pose donc SA place par défaut — le texte avant le cadre, la scène
     après le bouton — et les pièces nommées la précisent. */
  .ev-grille > .ev-texte > * { order: 3; margin-top: 0; margin-bottom: 0; }
  .ev-grille > .ev-scene > * { order: 7; margin-top: 0; margin-bottom: 0; }
  .ev-grille > .ev-texte > .legende { order: 1; }
  .ev-grille > .ev-texte > .titre { order: 2; }
  .ev-grille > .ev-scene > .ea,
  .ev-grille > .ev-scene > .ea-fenetre { order: 4; }
  .ev-grille > .ev-texte > .ev-etapes { order: 5; }
  .ev-grille > .ev-texte > .ev-cta { order: 6; }
  .ev-grille > .ev-texte > .ev-sous { order: 8; }
  .ev-grille > .ev-scene > .ev-pied { order: 9; }
  /* les six étapes tiennent sous le cadre : le texte garde sa taille, c'est
     l'interligne qui se resserre */
  .ev-etapes .chap { padding: 8px 10px 8px 16px; gap: 12px; }
}

/* ==========================================================================
   LA PAGE EVERYTHING (everything.html)
   ⚠️ Prefixe `evp-` et non `ev-` : `.ev-grille`, `.ev-scene` et `.ev-texte`
   appartiennent aux PRESENTATIONS de l'accueil. Deux familles qui se
   ressemblent dans une feuille de 5 000 lignes finissent par se marcher
   dessus — ce depot a deja paye cinq collisions de classe, dont `.plan`
   deux fois.
   ========================================================================== */

/* Le rendu Karma en tete de page. Un bord OU une elevation, jamais les deux
   (regle de la passe << pas IA >>) : ici le filet, et rien d'autre. */
.evp-heros-cadre {
  margin: 0;
  border-radius: var(--r-l);
  overflow: hidden;
  border: 1px solid var(--filet);
  background: var(--papier);
}
.evp-heros-cadre img { display: block; width: 100%; height: auto; }

/* L'arborescence du dossier livre. Elle DOIT etre en chasse fixe : ce sont
   des noms de fichiers, et c'est l'alignement des tailles qui les rend
   lisibles. Elle deborde en defilant plutot que d'elargir la page. */
.evp-arbre {
  margin: 0;
  font: 500 13.5px/1.75 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--encre-2);
  white-space: pre;
  overflow-x: auto;
  tab-size: 2;
}
@media (max-width: 760px) { .evp-arbre { font-size: 12.5px; } }

/* Cuivre plus franc : même traitement pour l'affiche et la toile, sans
   changement de teinte ni rupture lors du chargement du ShaderGradient. */
.nappe { filter: saturate(2.5) contrast(1.16); }
.nappe::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: url('/assets/nappe/grain.svg') repeat;
  opacity: .24;
  mix-blend-mode: soft-light;
}
.nappe-live-frame .nappe[data-affiche] { background-image: none; }
.hero-duo .hero-cadre {
  position: relative;
  border: 1px solid rgba(245,245,247,.2);
  border-radius: 20px;
  padding: 7px;
  box-shadow: none;
}
.hero-duo .hero-cadre img { border-radius: 13px; }
.hero-interface {
  position: absolute; left: 7px; top: 7px;
  width: calc(100% - 14px); height: calc(100% - 14px);
  border: 0; border-radius: 13px; pointer-events: none; visibility: hidden;
}
.hero-cadre.interface-prete .hero-interface { visibility: visible; }
.hero-cadre.interface-prete picture { visibility: hidden; }
@media (min-width: 1101px) {
  body:has(.hero-duo) .entete > .wrap { width: min(100% - 96px, 1920px); }
}
.hero-duo h1 { letter-spacing: -.045em; text-wrap: balance; }
.hero-duo h1 .degrade { color: var(--encre); }
.hero-duo .sous-titre { color: #E0DCD8; }
/* Des repères lisibles dans la présentation, même sur un écran sombre. */
.scene-fond .legende { color: var(--lien, #FFAF78); }
.entete .menu a { color: #DEDEE2; }
.entete .menu a:hover, .entete .menu a[aria-current="page"] { color: #FFF; }
.hero-duo .chapeau { max-width: 42ch; line-height: 1.65; }
.btn { transition: background-color .16s ease, border-color .16s ease, color .16s ease; }
.btn:focus-visible { outline: 2px solid var(--action); outline-offset: 4px; }
@media (prefers-reduced-transparency: reduce) {
  .nappe { filter: none; }
}

/* One shared stage for the complete DCC demonstration. */
.dc-showcase{padding:100px 0;overflow:hidden;background:var(--papier)}
.dc-heading{max-width:900px;margin:0 auto 44px;text-align:center}
.dc-kicker{font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--encre-3);margin:0 0 24px}
.dc-heading h2{font-size:clamp(36px,4.8vw,68px);line-height:1.08;letter-spacing:-.04em;font-weight:550;text-wrap:balance;margin:0 0 24px}
.dc-intro{max-width:580px;margin:auto;font-size:18px;line-height:1.6;color:var(--encre-2)}
.dc-session{margin:0 auto 24px;border:1px solid #ffffff20;border-radius:10px;overflow:hidden;background:#171719}
.dc-toolbar{display:flex;align-items:center;gap:18px;padding:12px 16px}
.dc-hosts{display:flex;gap:4px}.dc-hosts button,.dc-play{font:inherit;font-size:13px;color:var(--encre-2);background:transparent;border:0;border-radius:5px;padding:10px 14px;cursor:pointer;white-space:nowrap}
.dc-hosts button[aria-pressed=true]{color:var(--encre);background:#ffffff13}.dc-play{margin-left:auto;border:1px solid #ffffff25}.dc-context{font-size:11px;color:var(--encre-3)}
.dc-play:hover,.dc-hosts button:hover{background:#ffffff16}.dc-showcase :focus-visible{outline:2px solid var(--bleu);outline-offset:-2px}
.dc-stage{position:relative;aspect-ratio:8/5;overflow:hidden;background:#202124}
.dc-world{position:absolute;width:1440px;height:900px;transform-origin:0 0}
.dc-screen{display:block;width:1440px;height:900px;max-width:none}
.dc-video,.dc-tile,.dc-pointer{position:absolute;display:none;max-width:none;pointer-events:none}
.dc-video{object-fit:fill}.dc-tile{width:64px;height:64px;object-fit:contain;opacity:.9}.dc-pointer{width:25px;height:32px;filter:drop-shadow(0 2px 3px #0008)}
.dc-session-controls{padding:15px 20px;min-height:50px}.dc-phase{font-size:13px;color:var(--encre-2);margin:0}
.dc-footer{display:flex;align-items:start;justify-content:space-between;gap:30px}.dc-footer p{font-size:11px;color:var(--encre-3);max-width:600px;margin:0;line-height:1.6}.dc-footer a{font-size:13px;white-space:nowrap}
@media(min-width:1600px){.dc-session{max-width:1440px}}
@media(max-width:760px){.dc-showcase{padding:65px 0}.dc-heading{margin-bottom:30px}.dc-intro{font-size:16px}.dc-toolbar{gap:6px;padding:8px;flex-wrap:wrap}.dc-hosts{gap:0;flex:1}.dc-hosts button{padding:9px 7px;font-size:11px}.dc-play{font-size:11px;padding:8px}.dc-context{display:none}.dc-session-controls{padding:12px}.dc-phase{font-size:11px}.dc-footer{flex-direction:column;gap:14px}}
/* LES CHAPITRES DE #logiciels (24/09) : la rangée d'onglets Houdini · Maya ·
   Blender · Solaris est devenue la frise de chapitres des autres présentations
   (`.ev-etapes.chap-frise`, voir « LES ÉTAPES SONT DES CHAPITRES »), sous le
   film. Un chapitre par film, lu dans `dcc.json` (`etape`) par
   `presentation-dcc.js` ; sa barre suit le temps RÉEL de la vidéo.
   ⚠️ Le contexte (version, format) passe dans la rangée de la phase, sous la
   frise : il dit ce que le film montre en ce moment. */
.dc-chapitres { margin: 0; padding: 16px 20px 2px; }
.dc-chapitres .chap { font-size: 14px; }
.dc-session-controls { display: flex; align-items: baseline; justify-content: space-between; gap: 18px; }
.dc-session-controls .dc-context { white-space: nowrap; }
@media (max-width: 760px) {
  /* ⚠️ `.ev-etapes.chap-frise` (0,2,0) pose `grid-auto-flow: column` : sans
     la troisième classe, les six chapitres restaient sur une rangée de 55 px */
  .ev-etapes.chap-frise.dc-chapitres { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 6px; padding: 12px 12px 0; }
  .ev-etapes.chap-frise.dc-chapitres .chap { font-size: 12.5px; padding: 12px 6px 8px 0; }
  .dc-session-controls .dc-context { display: none; }
}
/* LA LECTURE DE #logiciels ET DES LÉGENDES DE L'ACCUEIL (24/09). La note sous
   les films était à 11 px sur ordinateur, à côté d'un lien de 13 px posé sur
   une autre ligne de base (4 px d'écart, relevé par `t-alignement`) ; au
   téléphone, l'étiquette, la phase et la note restaient à 11 px, sous le
   plancher de 12 px du site (`t-iphone`), comme les petites légendes des
   formats (« FBX · OBJ · USD · Blender… », « Arnold », « V-Ray »). */
.dc-footer { align-items: baseline; }
.dc-footer p { font-size: 13px; }
@media (max-width: 760px) {
  .dc-heading .dc-kicker { font-size: 12px; }
  .dc-session-controls .dc-phase { font-size: 14px; }
  .dc-footer p { font-size: 14px; }
  .prep-files small, .ef-formats-list dd span { font-size: 12px; }
}
/* LA PASSE ANTI-IA DU 24/09 (« lance la passe anti IA », l'éditeur), mesurée
   par le détecteur du skill impeccable sur les sept pages publiques :
   · les grands titres étaient serrés à -0,055 / -0,058 em (passe « studio »
     du 20/09) : sous -0,05 em, les lettres se touchent, un signal de page
     générée. Ramenés à -0,04 em, la graisse affirmée reste ;
   · « ASSETBROWSER » au-dessus du titre des logiciels était la seule
     étiquette en CAPITALES ESPACÉES du site : elle prend le dessin des
     étiquettes d'application des autres sections (`.legende` + titre) ;
   · le contexte des films (11 px) et les légendes des formats (11 px) passent
     à 13 et 12 px sur ordinateur. */
.dc-heading .dc-kicker {
  font-size: 15px; font-weight: 500; letter-spacing: -0.01em;
  text-transform: none; color: var(--encre-2); margin-bottom: 14px;
}
.orbis-studio .dc-heading .dc-kicker { color: #FFAD70; }
.dc-session-controls .dc-context { font-size: 13px; }
.prep-files small { font-size: 12px; }

/* ==========================================================================
   TÉLÉPHONE ET TABLETTE — LA REFONTE DU 26/09
   ==========================================================================
   « tu me refais entièrement la partie sur mobile iPad tablette stp car la
   quand on descend il y'a plein de bug d'ui etc » — l'éditeur.

   ⚠️⚠️ CE QUI « BUGUAIT QUAND ON DESCEND », MESURÉ. Les bancs Chromium
   (t-iphone, t-tablette, t-affichage) étaient verts : ils ne voient pas la
   barre d'adresse de Safari, qui se replie au premier geste vers le bas et
   revient à chaque remontée. Une sonde qui l'imite (hauteur de fenêtre qui
   change pendant un défilement immobile, `dvh` piloté, `svh`/`vh` figés,
   ANCRAGE DE DÉFILEMENT COUPÉ comme dans Safari) a relevé 30 sauts de 5 à
   11 px sur 9 pages à 390 px : tout le contenu glissait sous le doigt à chaque
   repli. Cause unique : 21 mesures en `dvh`. Elles sont en `svh` (voir la
   règle au-dessus de `body`) ; la sonde ne relève plus rien.

   ⚠️ LES TROIS PALIERS de cette section, et pourquoi ceux-là :
     · téléphone          ≤ 640 px   (iPhone 320-430, petits Android)
     · tablette portrait  641-1 024  (iPad mini 744, iPad 810-834, Air 820,
                                      Pro 11 834, Pro 13 1 024)
     · iPad paysage       1 025-1 180 (iPad 1 080, Air/Pro 11 1 180)
   La feuille garde ses ~30 paliers historiques (760, 900, 1 000, 1 100…) : les
   règles ci-dessous passent PAR-DESSUS, à la fin, sans en retirer aucun — chaque
   ancien palier porte son pourquoi et des bancs qui le mesurent.
   ========================================================================== */

/* ⚠️⚠️ LE TABLEAU DES TARIFS NE DÉFILE PLUS DE CÔTÉ AU TÉLÉPHONE (26/09).
   Il faisait 560 px dans un écran de 390 : « Pro » coupé au bord, « Studio »
   et « Sur mesure » hors champ, « par e-mai… » tranché, et un doigt qui
   voulait descendre faisait glisser le tableau. Sous 641 px, chaque ligne
   devient DEUX rangs : son intitulé sur toute la largeur, puis les quatre
   valeurs en quatre colonnes égales, sous une rangée de noms de plans qui
   reste collée sous la barre tant que le tableau est à l'écran.
   ⚠️ Aucun HTML changé : `display: grid` sur les `tr`, la première case
   passe sur toute la ligne, la rangée des groupes aussi (`colspan` n'a plus
   de sens dans une grille : c'est `grid-column` qui le remplace).
   ⚠️ La colonne Pro reste éclairée : c'est toujours la 3ᵉ case. */
@media (max-width: 640px) {
  .cadre-table {
    overflow: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .compare { display: block; min-width: 0; table-layout: auto; font-size: 13.5px; }
  .compare thead, .compare tbody { display: block; }
  .compare tr { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* ⚠️ `sticky` sur le THEAD, pas sur sa rangée : un collant ne colle que
     dans son parent, et un thead a la hauteur de sa seule rangée */
  .compare thead {
    position: sticky;
    top: var(--entete-h);
    z-index: 3;
    background: var(--papier-2);
    border-bottom: 1px solid var(--trait);
  }
  .compare thead th {
    position: static;
    padding: 12px 4px 10px;
    font-size: 12.5px;
    line-height: 1.25;
    background: transparent;
  }
  .compare thead th:first-child { display: none; }
  /* ⚠️ Plus de colonne Pro éclairée ici : coupée par chaque intitulé, elle
     devenait un damier. Le nom « Pro » en orange et ses valeurs en blanc
     suffisent à la désigner. */
  .compare th:nth-child(3), .compare td:nth-child(3),
  .compare thead th:nth-child(3) { background: transparent; }
  .compare tbody td:nth-child(3) { color: var(--encre); font-weight: 500; }
  .compare tbody td {
    padding: 4px 6px 14px;
    border-top: 0;
    font-size: 12.5px;
    line-height: 1.3;
    hyphens: auto;
    -webkit-hyphens: auto;
  }
  .compare th:first-child, .compare td:first-child { position: static; width: auto; background: none; }
  .compare tbody td:first-child {
    grid-column: 1 / -1;
    padding: 14px 0 6px;
    border-top: 1px solid var(--trait);
    font-size: 14px;
    font-weight: 450;
  }
  .compare .groupe td,
  .compare tbody .groupe td:first-child {
    grid-column: 1 / -1;
    padding: 26px 0 8px;
    border-top: 0;
    font-size: 12.5px;
  }
}

/* ⚠️⚠️ L'AFFICHE DE REPOS COUVRE L'APPLICATION TANT QU'ELLE EST LÀ (26/09).
   Toutes largeurs, mais c'est sur iPad qu'on l'a vue : « Un arbre, son
   squelette, son vent », le bouton « Lancer la présentation » et le logo
   glissé posés PAR-DESSUS la zone de dépôt et le bouton « Exporter »
   d'Animated. Le script ajoute l'iframe APRÈS l'affiche et la rend visible dès
   son chargement ; l'affiche, elle, ne tombe que quand le lot est prêt
   (quelques secondes sur un réseau mobile). Entre les deux, le document de
   l'application, transparent, laissait voir l'affiche à travers lui : deux
   interfaces l'une dans l'autre. L'affiche passe donc DEVANT, sur son propre
   fond ; le jour où le script la cache, l'application est déjà prête dessous.
   ⚠️ Même fond que le cadre (`--papier`) : sans application chargée, rien ne
   change à l'œil. */
.ea-repos { z-index: 2; background: var(--papier); }

/* LA FENÊTRE DE LA CAMÉRA S'ESTOMPE SUR SES BORDS (tablette et téléphone, là
   où `camera-presentations.js` la pose). Elle montre une partie d'une
   application plus large qu'elle : un mot coupé net contre le bord (« èques »,
   « RT », relevés à 820 px) se lisait comme un défaut d'affichage. Un fondu de
   22 px vers le fond du cadre dit qu'il y a de l'application au-delà. */
.ea-fenetre.en-camera::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--papier), transparent 22px, transparent calc(100% - 22px), var(--papier));
}

/* ⚠️⚠️ AU DOIGT, CE QU'ON FAIT DÉFILER EST DÉJÀ LÀ (26/09). `mouvement.js`
   fait apparaître les sections en fondu quand elles franchissent 85 % de la
   hauteur d'écran. À la souris, c'est un accompagnement ; au pouce, un
   défilement lancé fait passer des blocs ENCORE TRANSPARENTS sous les yeux,
   puis les allume après coup : des trous qui se remplissent, lus comme un
   retard d'affichage. Sur un écran tactile, rien n'attend plus le défilement.
   ⚠️ En CSS et `!important` parce que GSAP écrit l'opacité en style en ligne ;
   c'est la même règle que le filet sans JavaScript (`html:not(.js)`). Le
   script n'est pas touché : sur ordinateur, tout reste comme avant. */
@media (hover: none) and (pointer: coarse) {
  [data-anim="monte"],
  [data-anim="monte"] > *,
  [data-stagger] > * { opacity: 1 !important; }
}

/* LES CHIFFRES DE L'ACCUEIL EN COLONNE UNIQUE (≤ 900 px) : le grand nombre sur
   toute la largeur, les trois petits en rangée dessous. La mise en page du
   bureau (le grand en bas à gauche, trois empilés à côté) laissait sur iPad un
   grand vide en haut à gauche ; celle du téléphone (deux par deux sous le
   grand) laissait le quatrième seul sur sa rangée. */
@media (max-width: 900px) {
  .ch-grille .chiffres { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: none; }
  .ch-grille .ch-case:first-child {
    grid-column: 1 / -1;
    grid-row: auto;
    padding: 0 0 clamp(22px, 4vw, 30px);
    border-right: 0;
  }
  .ch-grille .ch-case:nth-child(n + 2) {
    border-top: 1px solid var(--trait);
    border-left: 1px solid var(--trait);
    padding: clamp(18px, 3vw, 24px) clamp(12px, 2.4vw, 22px) 0;
  }
  .ch-grille .ch-case:nth-child(2) { border-left: 0; padding-left: 0; }
  .ch-grille .ch-case:nth-child(n + 2) .ch-t { font-size: 13.5px; }
}

/* LES CHAPITRES DES FILMS DES LOGICIELS AU TÉLÉPHONE : deux colonnes, plus
   trois. À 390 px, trois colonnes de 100 px coupaient « Vos bibliothèques,
   dans le panneau » sur quatre lignes à 12,5 px. */
@media (max-width: 640px) {
  .ev-etapes.chap-frise.dc-chapitres { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 16px; }
  .ev-etapes.chap-frise.dc-chapitres .chap { font-size: 13.5px; }
}

/* ⚠️⚠️ #vent ENTRE 1 001 ET 1 024 px (iPad Pro 13 en portrait, 1 024) : la
   présentation Animated y prend déjà sa mise en page de bureau (la grille
   dont `display: contents` sort les enfants), mais le message « Animated
   tourne sur ordinateur » (`.sans-app`, visible jusqu'à 1 024 px) n'y avait
   AUCUNE case : placé d'office, il se posait en face du titre, dans la
   colonne de droite, et creusait un trou de 700 px sous l'étiquette. Il
   prend ici la place que le bouton d'essai laisse vide, sous les boutons. */
@media (min-width: 1001px) and (max-width: 1024px) {
  #vent .ev-grille > .ev-texte > .sans-app {
    grid-column: 1 / -1;
    grid-row: 6;
    justify-self: start;
    width: min(100%, 640px);
  }
}

/* LA BARRE DU TÉLÉPHONE SUR /compte.html : CINQ LIENS, SERRÉS POUR TENIR.
   Le lien « Compte » sort de la bande sous 760 px, sauf sur sa propre page où
   il est la page en cours (`t-menu-tel` l'exige : c'est le seul chemin vers le
   compte, le bouton du coin y est masqué). La bande défilait alors jusqu'au
   lien actif et coupait « Accueil » en « eil » contre le bord : lisible comme
   un défaut, même sous son fondu. Cinq liens à 6 px de rembourrage, sans jour
   et en 13 px tiennent en entier dès 375 px en français ; plus étroit, ou
   dans une langue plus longue, la bande défile comme avant. */
@media (max-width: 760px) {
  .entete .menu:has(> a.menu-compte.on) { gap: 0; }
  .entete .menu:has(> a.menu-compte.on) > a { padding-inline: 6px; font-size: 13px; }
}
