/* ═════ Les habits du carrousel de cas d’usage — asset PARTAGÉ du
   chantier, à charger APRÈS site.css (qui porte la fenêtre .window, le
   caret, le trigger-badge et l’expanded-flash) sur toute page qui
   embarque carousel.js. Doctrine du moteur et contrat du markup — en
   tête de carousel.js. À la promotion, part dans site/assets/css/. */
/* Le bouton pause et la barre de progression s’ancrent en absolu sur la
   fenêtre — la règle vivait dans .page-main .demo de /text-expansion/,
   les landings ne l’avaient pas. La fenêtre du CARROUSEL fait 620 px
   partout (la largeur validée sur /text-expansion/) — la .demo de
   site.css reste à 580, taillée pour la mini-démo de la page d’attente
   en prod ; même spécificité, cette feuille se charge après, elle
   gagne. À 580, les libellés FR des onglets passaient sur TROIS lignes. */
.demo { position: relative; max-width: 620px; }
/* Le CORPS fixe sa base typographique — sans quoi le composant hérite de
   la page et ne rend PAS pareil d’une page à l’autre (relevé le 14/08 en
   instruisant la hauteur) : /text-expansion/ met sa colonne à 1,125 rem,
   les landings à 1 rem, donc toutes les tailles en `em` d’ici — étiquettes
   de formulaire, en-tête Finder, puces — sortaient 12 % plus grandes d’un
   côté que de l’autre, hauteur du carrousel comprise. Un composant
   partagé ne se laisse pas dimensionner par son hôte. */
.demo-body { font-size: 1rem; }
/* Le cas Coordonnées se joue en FORMULAIRE — étiquettes préexistantes, la
   frappe va DANS les champs (demande Jonathan). On ne tape pas les
   intitulés, on remplit. */
.demo-form { display: none; }
.demo-form.demo-form--on { display: flex; flex-direction: column; gap: 8px; }
.demo-champ { display: flex; align-items: center; gap: 10px; }
.demo-etiquette { flex: none; width: 96px; text-align: right; font-size: 0.82rem; color: var(--text-2); }
/* Variante « questions » (onglet Manipulations, structure Jonathan) — la
   question au-dessus en pleine largeur, la réponse en retrait dessous.
   L'en-tête porte la phrase SOURCE (marquée pour le voile ⌘C) et
   l'invite. Pas l'agencement de Coordonnées, à dessein. */
.demo-form--on.demo-form--questions { gap: 2px; }
.demo-form--questions .demo-champ { flex-direction: column; align-items: stretch; gap: 2px; }
/* L’intitulé est un LIBELLÉ DE CHAMP, pas une phrase du texte (demande
   Jonathan, 14/08) — gris et petit comme celui de Coordonnées, il cesse
   de rivaliser avec la frappe qu’il annonce. La variante « questions » ne
   garde donc de son ancien traitement que la position (au-dessus, pleine
   largeur) ; elle rejoint le registre de l’autre formulaire au lieu d’en
   inventer un second. Bénéfice de hauteur en prime : moins de repli. */
.demo-form--questions .demo-etiquette { width: auto; text-align: left; font-size: 0.8rem; color: var(--text-2); }
/* RÈGLE (re-mordue au dégraissage du 14/08) : le min-height d'une saisie
   CONTIENT le badge (~21 px : 0,9 em + paddings) — c'est le correctif
   historique de Coordonnées (32 px). En dessous, chaque badge tapé gonfle
   sa boîte et la colonne tressaute. 28 px border-box = badge + paddings
   + bordures, le plus mince qui ne bouge pas. */
.demo-form--questions .demo-saisie { margin-left: 16px; flex: none; min-height: 28px; padding: 1px 8px; }
.demo-form-entete { margin-bottom: 6px; }
.demo-form-entete .demo-copiable { display: inline; }
.demo-qsource { font-weight: 700; font-size: 1.05rem; }
.demo-qintro { color: var(--text-2); margin-bottom: 12px; }
/* Le line-height CONTIENT le contenu dans le min-height — en border-box,
   32 px laissent 24 px utiles (6 de padding, 2 de bordures). Le corps
   étant fixé à 1 rem par `.demo-body`, 1.3 donne 20,8 px et tout tient,
   badge compris. (Historique, à ne pas relire de travers : la marge était
   plus mince quand la fenêtre héritait des 1,125 rem de
   /text-expansion/ — 23,4 px utiles, et 1.35 en donnait 24,3, si bien
   que chaque rangée respirait de 0,3 px à l’insertion, visible sur
   certains champs seulement, retours Jonathan du 07/08, deux fois.
   Depuis que la base est absolue, le même réglage a 2,6 px de marge de
   plus.) Vérifier toute retouche à la mesure FRACTIONNELLE
   (getBoundingClientRect), jamais à l’offsetHeight, qui arrondit le
   débord. */
.demo-saisie { flex: 1; min-height: 32px; line-height: 1.3; display: flex; align-items: center; padding: 3px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-2); }
/* LE BADGE TAPÉ DANS UN CHAMP NE LE FAIT PAS GONFLER (05/10/2026, relevé par
   Grégoire : la hauteur du champ « augmente et passe à y quand tu tapes le
   circut dedans », puis « repasse à x » au texte posé). Le champ est une boîte
   flex et le badge un enfant DIRECT : il y est BLOCKIFIÉ, et sa marge
   intérieure compte dans sa hauteur. Les 0,19 em que site.css lui donne
   depuis le 23/08 compensent un badge EN LIGNE, dont la marge se peint sans
   compter dans la ligne. Ici, ils le portaient à 24,19 px pour 24 px utiles,
   dans les deux formulaires (Coordonnées, Manipulations) : chaque champ
   gonflait de 0,19 px le temps de la frappe, et les étiquettes des rangées
   suivantes descendaient d’autant. Subtil à l’œil, net au zoom. La keycap a
   la même exception dans une rangée flex (site.css, « SAUF EN ITEM FLEX ») :
   0,08 em, soit un badge de 21 px, celui pour lequel ces champs ont été
   calibrés. Preuve à la sonde (Chrome sans fenêtre, frame par frame) : même
   hauteur au champ vide, déclencheur tapé et texte posé. */
.demo-saisie > .trigger-badge { padding-block: 0.08em; }
/* Le plancher de la fenêtre est AUTO-MESURÉ par le moteur du carrousel —
   le plus haut des neuf états finaux, rendu puis mesuré avant le premier
   tour. Un plancher CSS en em ne suivrait ni la largeur ni le contenu. */
/* Les onglets du carrousel — tous les cas visibles, cliquables. L’ACTIF
   est en accent (état de sélection, le budget le permet) et suit aussi le
   défilement automatique. FER À GAUCHE sur la gouttière de la fenêtre
   (même largeur, 620) — deux lignes CENTRÉES de largeurs inégales
   faisaient un nuage aux alignements aléatoires (retour Jonathan,
   14/08) ; un fer commun donne le rythme, et la première ligne pleine
   dit « il y en a d’autres dessous ». La marge BASSE vit ici — sur la
   landing, la fenêtre n’a aucune marge haute (site.css) et les onglets
   lui étaient collés ; la relation onglets-fenêtre appartient à
   l’asset, pas aux pages. */
/* GOUTTIÈRE de 18 px (17/08/2026, relevé de Jonathan : en anglais, « Fine
   typography » restait accroché en bout de PREMIÈRE ligne, laissant 6 pastilles
   contre 3). Les 6 px d’origine dataient du jour où le premier onglet pesait
   150 px (« Réponses récurrentes ») ; à 81 px (« Messages »), l’air est redevenu
   disponible. Simulé sur les largeurs réelles, ligne par ligne : l’anglais bascule
   en 5/4 dès 14 px, et 18 px tient AUSSI si le libellé raccourcit (« Typography »,
   89 px) — le point de coupe cesse donc de dépendre du wording, ce qui est le
   vrai gain. Le français, lui, est en 5/4 à toute gouttière, mais à 2 px près :
   « Typographie soignée » (144) plus la ligne 1 (478) font 622 pour 620
   disponibles. Tout libellé français raccourci ferait donc basculer sa coupe. */
.demo-tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 18px; max-width: 620px; margin: 36px auto 14px; scroll-margin-top: 88px; }
/* CHAQUE onglet porte sa surface, pas seulement l’actif — c’est la
   correction du « c’est un peu le bazar » (Jonathan, 14/08). Avec un seul
   objet dessiné sur neuf, l’œil n’avait aucune forme à aligner et lisait
   des mots flottants ; neuf pastilles de même hauteur font des RANGÉES, et
   le ragged du retour à la ligne devient un rythme. La surface est celle
   du CORPS de la fenêtre (bg-card) : les onglets appartiennent visiblement
   à l’objet qu’ils pilotent. L’accent reste réservé à l’ACTIF (budget
   d’accent — un état de sélection). Corps à 0,78 rem et gouttière à 6 px
   pour que les libellés FRANÇAIS, 15 à 20 % plus longs que les anglais,
   tiennent sur DEUX lignes (mesuré : 1 158 px de pastilles à 0,85 rem
   débordaient sur trois lignes). */
.demo-tab { background: var(--bg-card); border: 1px solid var(--border); border-radius: 999px; padding: 4px 10px; font-size: 0.78rem; color: var(--text-2); cursor: pointer; font-family: inherit; }
.demo-tab:hover { color: var(--text); }
.demo-tab[aria-current="true"] { color: var(--accent-text); background: var(--accent-soft); border-color: transparent; }
.demo-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Le titre COMPLET du cas vit dans la barre de fenêtre (les onglets
   gardent leurs libellés courts, la place manque), flanqué des flèches de
   cas adjacent. En étroit il s’ellipse au lieu d’écraser les pastilles. */
.demo .window-bar { position: relative; }
/* ── LES FLÈCHES NE BOUGENT PAS SOUS LE CURSEUR (02/10/2026, retour de
   gnovel : « Let users spam-click your interface »). Posées contre un titre
   qui va de 7 à 46 signes, elles se déplaçaient à chaque cas — 130 px de
   course à 1 280 px — et le second clic d’une rafale tombait dans le vide.
   Le moteur honorait déjà chaque clic (naviguer relance sans verrou) : il
   suffisait qu’elles tiennent en place.
   LE TITRE VIT DANS UNE CASE DE LARGEUR FIXE, celle du plus long titre de la
   langue, et c’est le NAVIGATEUR qui la calcule : carousel.js empile tous les
   titres, invisibles, dans la case du titre affiché (les gabarits), et la
   piste prend la largeur du plus large. Rien n’est mesuré en JS : la case
   suit seule la fonte qui arrive (font-display: swap) et tout titre retouché
   dans CASES. Le titre s’y centre, les flèches l’encadrent.
   EN ÉTROIT, le groupe plafonne et la piste du titre descend avec lui
   (`minmax(0, max-content)`) : le titre s’abrège comme avant, et les flèches
   restent aux deux bouts du plafond, donc fixes là aussi.
   LA LARGEUR EST DITE, PAS DÉDUITE (`width: max-content`). Centré par
   `left: 50%`, le groupe n’a que la MOITIÉ de la barre pour son calcul
   automatique. Tant que le titre était un nowrap dans une boîte flex, son
   minimum valait son maximum et la question ne se posait pas ; avec une
   piste qui sait descendre à zéro, le calcul s’arrête à la demi-barre et
   abrège les titres longs en plein large (mesuré : 265 px de titre pour
   301 nécessaires).
   LE PLAFOND DÉGAGE LES PASTILLES : 140 px de réserve et non plus 120. À
   120, le groupe au plafond commençait à 60 px du bord quand la pastille
   verte finit à 67 — la pointe du chevron gauche y entrait de 2 px, sur les
   seuls titres longs. Figer les flèches aurait rendu ce contact permanent. À
   140, la pointe se pose à 8 px de la pastille, le pas des pastilles entre
   elles.
   TOUT EST PLACÉ EXPLICITEMENT, le titre et les flèches comme les gabarits :
   un élément placé passe AVANT les éléments automatiques, qui prennent les
   cases restées libres — gabarits seuls placés, le titre partait dans la
   troisième colonne.
   SANS JAVASCRIPT, ou avec un carousel.js plus ancien, pas de gabarits : le
   titre garde ses flèches contre lui, comme avant. ── */
.demo-case { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: grid; grid-template-columns: auto minmax(0, max-content) auto; align-items: center; column-gap: 6px; width: max-content; max-width: calc(100% - 140px); }
#demo-prev { grid-area: 1 / 1; }
#demo-next { grid-area: 1 / 3; }
#demo-case-title, .demo-case-gabarit { grid-area: 1 / 2; margin-left: 0; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.demo-case-gabarit { visibility: hidden; }
/* LES FLÈCHES PORTENT LA LIGNE DU TITRE (02/10/2026, Grégoire : « elles me
   semblent 1 ou 2 px trop hautes par rapport au texte »). Centrées dans la
   rangée, elles visaient le milieu de la LIGNE, donc la mi-hauteur des
   capitales. Chaque bouton prend désormais la police, le corps et
   l’interligne du titre : deux lignes identiques, centrées dans la même
   rangée, ont la même ligne de base, et le chevron s’y pose par
   `vertical-align: middle`, plus le `top` des chevrons de titre (doctrine
   près de `.chev`, dans site.css). D’où `display: block` et non
   `inline-flex` : dans un conteneur flex, `vertical-align` ne s’applique
   plus. Le bouton n’a plus de marge verticale : sa zone de clic prend la
   hauteur de la ligne, 22 px au lieu de 16.
   PUIS « TROP BASSES DE 1-2 PX » (03/10/2026, Grégoire, même titre) : posé à
   mi-hauteur d’x, là où SF centre ses propres ‹ ›, le chevron descendait de
   0,76 px sous la ligne de base, parce qu’il est plus grand que les
   minuscules et que ces guillemets sont petits. Ses deux relevés encadrent
   la bonne hauteur : à mi-chemin des minuscules et des capitales, la règle
   des chevrons plus grands que les minuscules. */
.demo-nav { background: none; border: 0; padding: 0 2px; cursor: pointer; color: var(--text-2); display: block; flex: none; font: inherit; font-size: 0.85rem; }
.demo-nav:hover { color: var(--text); }
.demo-nav:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.demo-nav .chev {
  width: 12px; height: 12px; position: relative;
  top: -0.045em;
  top: calc((1ex - 1cap) / 4);
}
.chev-gauche { transform: scaleX(-1); }
/* Play/Pause discret (demande Jonathan, 07/08), ancré sur .demo en
   position relative. Le bouton montre l’action disponible, pas l’état.
   La règle [hidden] doit RESTER après le display du bouton — sans elle,
   l’attribut serait écrasé et le bouton apparaîtrait sans JavaScript. */
.demo-pause { position: absolute; right: 8px; bottom: 6px; display: inline-flex; background: none; border: 0; padding: 4px; cursor: pointer; color: var(--text-2); opacity: 0.5; }
.demo-pause:hover { opacity: 1; }
.demo-pause:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; opacity: 1; }
.demo-pause svg { width: 14px; height: 14px; display: block; }
.demo-pause .dp-play { display: none; }
.demo-pause.demo-pause--paused .dp-play { display: block; }
.demo-pause.demo-pause--paused .dp-pause { display: none; }
.demo-pause[hidden] { display: none; }
/* MODE LANCEUR — sous « Réduire les animations », le bouton n’est plus une
   commande secondaire : il est le SEUL moyen de voir la démo (le reste du
   temps, la démo joue toute seule et il ne sert qu’à l’arrêter). Il quitte
   donc la discrétion, prend son libellé et se pose comme une pastille. Il
   redevient l’icône à demi effacée dès que la démo tourne. Aucune de ces
   règles ne s’applique sans la classe, donc rien ne change pour qui n’a pas
   le réglage. */
.demo-pause--lanceur { opacity: 1; gap: 6px; padding: 5px 11px; align-items: center;
  color: var(--text); background: var(--bg-card); border: 1px solid var(--border);
  border-radius: 999px; }
.demo-pause--lanceur:hover { border-color: var(--accent); color: var(--accent); }
.dp-label { font-size: 0.82rem; font-weight: 500; line-height: 1; white-space: nowrap; }
.demo-pause:not(.demo-pause--lanceur) .dp-label { display: none; }
/* La scène du carrousel respire un cran moins que la mini-démo de la page
   d’attente (site.css : 1,05 rem / 1,6) — le plancher est le PLUS HAUT des
   neuf cas, donc chaque ligne gagnée sur le cas le plus long rétrécit la
   fenêtre sur les neuf (demande Jonathan, 14/08 : « la hauteur est trop
   élevée »). Mesuré : 1,05/1,6 → 1/1,5 fait tomber « Dates dynamiques »,
   le plafond, de 544 à 489 px, sans retirer une ligne de copie. Le corps
   reste à 16 px. */
.demo-text { font-size: 1rem; line-height: 1.5; }
/* Transition de cas — le CONTENU fond et se dépose (170 ms), la fenêtre,
   le titre et les onglets ne bougent pas. Le feedback du clic reste
   immédiat (majOnglets part AVANT le fondu) — seul le corps tourne la
   page. La classe vit le temps du fondu de sortie — son retrait rejoue le
   trajet inverse sur le décor du cas suivant. Jamais posée sous
   prefers-reduced-motion (le lanceur court-circuite), jamais au seek de
   la barre (on se déplace DANS la page, on ne la tourne pas). */
.demo-body { transition: opacity 0.17s ease, transform 0.17s ease; }
.demo-body--fondu { opacity: 0; transform: translateY(4px); }
/* Barre de progression du player — un fil au bas de la fenêtre, cliquable
   pour se déplacer dans le cas courant. Le remplissage suit la frappe.
   Le FANTÔME (au survol) montre la destination RÉELLE du clic — la
   frontière de segment où la lecture reprendrait. Il rend visible le
   pas de la barre au lieu de laisser croire à un défilement continu —
   son bord avance par crans, à dessein (aucune transition). */
.demo-scrub { position: absolute; left: 0; right: 0; bottom: 0; height: 14px; background: none; border: 0; padding: 0; cursor: pointer; }
.demo-scrub::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--border); }
.demo-scrub-ghost { position: absolute; left: 0; bottom: 0; height: 3px; width: 0; background: var(--accent); opacity: 0; }
.demo-scrub:hover .demo-scrub-ghost { opacity: 0.3; }
.demo-scrub-fill { position: absolute; left: 0; bottom: 0; height: 3px; width: 0; background: var(--accent); transition: width 0.1s linear; }
.demo-scrub:hover::before, .demo-scrub:hover .demo-scrub-ghost, .demo-scrub:hover .demo-scrub-fill { height: 5px; }
.demo-scrub:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.demo-scrub[hidden] { display: none; }
.demo-puce { font-size: 1.25em; line-height: 1; }
/* Fenêtre Finder de l'onglet Dates — la liste, ses aînées datées, le champ
   de renommage à liseré accent (extension grise HORS du champ, comme le
   vrai Finder qui exclut « .pdf » de la sélection). */
/* La vignette est une CITATION du Finder, pas une fenêtre dans la fenêtre
   (demande Jonathan, 14/08 : « relativement gros là »). Rétrécie d’un
   cran — corps à 0,82 rem, rangées à 1 px de garde, icône à 12 — elle
   dit la même chose en ~45 px de moins, et le texte qui la suit reprend
   la vedette. Sa taille est ABSOLUE (rem), comme tout ce qui vit dans
   cette fenêtre. */
.demo-finder { display: none; padding: 2px; font-size: 0.82rem; }
.demo-finder--on { display: block; margin-bottom: 10px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.demo-finder-entete { font-size: 0.75rem; color: var(--text-2); padding: 0 6px 4px; border-bottom: 1px solid var(--border); margin-bottom: 2px; }
.demo-fichier { display: flex; align-items: center; gap: 7px; padding: 1px 6px; border-radius: 5px; }
.demo-fichier .demo-doc { width: 12px; height: 12px; flex: none; color: var(--text-2); }
.demo-fichier--cible { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.demo-renom-champ { display: inline-block; min-width: 8px; border: 2px solid var(--accent); border-radius: 4px; padding: 0 3px; margin: -2px 0; background: var(--bg-card); }
.demo-renom-ext { color: var(--text-2); }
/* Au commit, le champ disparaît EN ENTIER — une bordure transparente
   garderait ses 2 px et le padding ses 3 px : 5 px de fantôme qui
   désalignaient la ligne de ses aînées (capture Jonathan). */
.demo-renom-champ--valide { border: 0; padding: 0; margin: 0; background: none; }
/* Mise en scène du ⌘C — la portée { marque } s'illumine du voile de
   sélection le temps du { copier }, puis s'éteint. */
.demo-copiable { border-radius: 3px; transition: background 0.25s; }
.demo-copie { background: color-mix(in srgb, var(--accent) 28%, transparent); }

/* ── LE CARROUSEL EN ÉTROIT (21/08/2026, premier passage mobile) — DEUX
   leviers, tous deux mesurés à 375 px, et la première media query de cette
   feuille.

   1. LES ONGLETS DÉFILENT AU LIEU DE SE REPLIER (idée de Jonathan). À neuf
   onglets dans 327 px, le repli donnait QUATRE rangées, soit 122 px de
   pastilles avant même la fenêtre — contre 57 sur une seule ligne au large.
   En rail, ils tiennent en 25 px : **97 rendus**, et le hero passe de 1 845 à
   1 747. Le prix, à connaître : on ne voit plus que quatre onglets sur neuf
   d’un coup. Le repli, lui, les montrait tous — c’est de l’information
   perdue, compensée par l’onglet coupé au bord droit, qui dit qu’il y a une
   suite. Pas de fondu : il resterait affiché en fin de course, là où il n’y a
   plus rien à deviner (l’argument qui l’avait déjà écarté sur la vitrine).
   `proximity` et non `mandatory` : le calage aide sans jamais confisquer un
   geste, et l’onglet ACTIF doit rester atteignable au doigt libre.

   2. LE CORPS RESPIRE MOINS SUR LES CÔTÉS. Ses 24 px de padding latéral
   coûtaient double : la place elle-même, et les replis de texte qu’une
   colonne étroite provoque. À 14, le texte gagne 20 px de largeur et le
   PLANCHER de la fenêtre tombe de 60 px — il est auto-mesuré par le moteur,
   donc il enregistre ce gain tout seul, sans une ligne de JS.

   CE QUE CES DEUX LEVIERS NE FONT PAS : le plancher reste calibré sur le plus
   haut des neuf cas, or celui-ci est un cas à FORMULAIRE, plus haut que le
   plus haut des cas texte (596). Mesuré cas par cas à 375 px : Symboles 596,
   Messages 572, Mots du quotidien et Émojis 548, Typographie 476, et
   Autocorrection 308 — ce dernier laisse donc ~300 px de vide sous lui. Rendre
   à chaque cas sa hauteur naturelle récupérerait tout, mais ferait DANSER la
   page à chaque changement, ce qui est précisément le défaut que le plancher
   corrigeait. Si l’écart continue de gêner, la sortie est éditoriale (étoffer
   Autocorrection), pas technique. ── */
@media (max-width: 700px) {
  .demo-tabs {
    flex-wrap: nowrap; justify-content: flex-start;
    overflow-x: auto; scrollbar-width: none;
    scroll-snap-type: x proximity; margin-top: 24px;
  }
  .demo-tabs::-webkit-scrollbar { display: none; }
  .demo-tabs > * { flex: none; scroll-snap-align: start; }
  .demo-body { padding: 16px 14px; }
}

/* ── LE RAIL D’ONGLETS DIT QU’IL DÉFILE (21/08/2026, relevé de Jonathan :
   « rien n’indique visuellement qu’il est possible de scroller »).
   L’affordance d’origine était l’onglet COUPÉ au bord droit. Elle existe
   — mesuré, « Mots du quotidien » montre 95 de ses 128 px — mais elle ne
   suffit pas : une pastille tronquée à 74 % se lit comme une pastille
   entière, et la coupure tombe sur le bord de la colonne, là où l’œil
   attend une fin.
   UN FONDU, ET NON DES FLÈCHES : l’idiome des flèches existe sur le site
   (le ruban des collections, la vitrine), mais elles font 32 px de haut
   pour une barre qui en fait 25 — elles la déborderaient, et ajouteraient
   deux contrôles dans la zone la plus dense du hero. Le fondu est l’autre
   idiome maison, celui du plafond de /versions.
   PILOTÉ PAR LE DÉFILEMENT, ce qui lève la seule objection qu’on lui
   faisait : il ne reste plus affiché en fin de course, là où il n’y a plus
   rien à deviner. Les classes viennent de carousel.js ; sans JS, aucune
   n’est posée et le rail retrouve son aspect d’avant.
   Le masque est en coordonnées du BORDER-BOX, donc il reste immobile
   pendant que les onglets défilent dessous. Les pastilles estompées
   restent cliquables : un masque peint, il n’intercepte rien. ── */
@media (max-width: 700px) {
  .demo-tabs {
    --fondu-g: 0px;
    --fondu-d: 0px;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 var(--fondu-g),
                        #000 calc(100% - var(--fondu-d)), transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 var(--fondu-g),
                #000 calc(100% - var(--fondu-d)), transparent 100%);
  }
  .demo-tabs.a-gauche { --fondu-g: 26px; }
  .demo-tabs.a-droite { --fondu-d: 34px; }
}

/* ── LE CHEVRON DU RAIL (21/08/2026, deuxième passe — capture de Jonathan : « on
   peut vraiment penser que ça s’arrête à Émojis »).
   LE FONDU SEUL NE SUFFIT PAS, et la mesure dit pourquoi : il n’estompe que ce
   qui tombe SOUS lui. À partir de 615 px, « Émojis » est entier (60/60) et la
   coupure tombe dans la gouttière qui le suit — il ne reste plus que 9 px
   d’onglet sous le fondu à 630. L’affordance dépendait donc de la largeur de
   fenêtre, ce qui revient à ne pas en avoir.
   LE CHEVRON, LUI, EST TOUJOURS LÀ tant qu’il reste du contenu à droite. Il vit
   sur un CONTENEUR et non dans le rail, parce que le masque estompe tout ce
   qu’il contient — un chevron posé dedans se serait effacé avec le reste.
   `:has()` lui évite une classe de plus : il lit celle que carousel.js pose
   déjà sur le rail (l’idiome de `.nav-inner:has(.nav-menu)`).
   EN BORDURES ET NON EN SVG : il suit `currentColor` donc le thème, et l’angle
   droit d’une bordure est net comme les chevrons du site (miter, jamais round).
   NON CLIQUABLE, à dessein : c’est un indice, pas un contrôle. Un bouton
   demanderait 32 px de haut dans une barre qui en fait 25, et le geste naturel
   ici est le balayage, pas le clic. ── */
.demo-tabs-rail { position: relative; }
@media (max-width: 700px) {
  .demo-tabs-rail::after {
    content: ""; position: absolute; right: 2px; top: 50%;
    width: 7px; height: 7px;
    border-right: 2px solid var(--text-2);
    border-bottom: 2px solid var(--text-2);
    transform: translate(0, -50%) rotate(-45deg);
    opacity: 0; transition: opacity 140ms ease;
    pointer-events: none;
  }
  .demo-tabs-rail:has(.demo-tabs.a-droite)::after { opacity: 0.75; }
}
