/* ===== /creation-site — 5e monde, EN CONCEPTION (05/08/2026) ===============
 *
 * ⚠️ RIEN N'EST EN LIGNE.
 *
 * DIRECTION ARTISTIQUE — retenue par Lino le 05/08/2026 : **fond BLANC,
 * relativement minimaliste**. C'est le seul monde clair du site (sport,
 * immobilier, entreprise et cinéma sont sombres ou colorés), et c'est
 * cohérent avec ce qu'il vend ici : on ne décore pas une page qui parle de
 * savoir-faire en mise en page. La démonstration, c'est la page elle-même.
 *
 * Ce que « minimaliste » veut dire ici, concrètement :
 *   · une seule couleur d'accent, et elle ne sert qu'aux actions ;
 *   · des filets d'un pixel plutôt que des cartes à ombre ;
 *   · beaucoup de blanc, des titres larges, peu de niveaux de gris ;
 *   · AUCUN halo, aucune lueur, aucun néon — même règle que /realestate et
 *     /pro (Lino, 31/07 : le premium se joue sur l'espace et la typographie).
 * ⚠️ La première version de cette page (05/08 au matin) était SOMBRE avec un
 * halo coloré, calquée sur le composant fourni pour le module 3. Elle a été
 * refaite ici. Ne pas réintroduire de halo : c'était un accident de portage.
 *
 * ⚠️ La maquette d'admin du module 3 est passée en CLAIR le 05/08 au soir
 * (Lino). Elle était sombre pour se détacher ; ce sont maintenant le filet, le
 * cadre et l'ombre longue qui font ce travail. Elle garde malgré tout sa
 * propre palette (`--ad-*`) : c'est un écran DANS la page, pas la page.
 * ======================================================================== */

@import url("https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&display=swap");

.cs {
  /* ⚠️ `margin: 0` : cette page n'avait AUCUNE remise à zéro — elle héritait
     des 8 px de marge par défaut du <body>, ce qui la décalait entièrement et
     faisait déborder la page de 3 px horizontalement sur téléphone. Les autres
     mondes la posent dans leur <style> en ligne ; ici elle manquait. */
  margin: 0;
  --cs-bg:      #ffffff;
  --cs-bg-2:    #f7f7f5;   /* bandes alternées, à peine perceptibles */
  --cs-ink:     #14161a;
  --cs-ink-2:   #4b5058;   /* texte courant */
  --cs-muted:   #8b9098;   /* mentions, légendes */
  --cs-line:    #e6e6e2;
  --cs-line-2:  #d2d2cc;
  --cs-accent:  #2f4bd8;   /* bleu d'encre : la seule couleur de la page */
  --cs-accent-d:#1e34a8;

  /* la maquette d'admin — palette autonome, elle imite un écran.
     ⚠️ CLAIRE depuis le 05/08/2026 au soir (Lino). Elle reste une palette À
     PART et non les variables de la page : c'est un écran DANS la page, il
     doit pouvoir évoluer sans elle. */
  --ad-bg:      #ffffff;
  --ad-panel:   #f7f7f5;
  --ad-panel-2: #ffffff;
  --ad-ink:     #14161a;
  --ad-muted:   #82868e;
  --ad-line:    #e8e8e4;
  --ad-accent:  #2f4bd8;
  --ad-ok:      #1c7f55;
  --ad-warn:    #a4671d;

  background: var(--cs-bg);
  color: var(--cs-ink);
  /* ⚠️ PAS de `var(--sans)` dans cette pile. La variable est déclarée dans
     hero.css, que cette page ne charge pas : un `var()` non résolu invalide
     TOUTE la déclaration `font-family` et le titre repart en serif (constaté
     le 05/08/2026). On nomme les polices en clair.
     `--sans` est redéfinie ici parce que menu.css l'emprunte. */
  --sans: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-family: "Geist", system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Le menu commun est prévu pour des mondes SOMBRES : sa barre est un verre
   clair sur fond foncé. Sur blanc il devient invisible. On l'inverse ici, et
   seulement ici — menu.css reste sans dépendance de palette. */
.cs .menu-bar { background: rgba(255,255,255,.82); border-color: var(--cs-line); }
.cs .menu-brand { color: var(--cs-ink); }
.cs .menu-toggle span { background: var(--cs-ink); }
.cs .menu-toggle { border-color: var(--cs-line-2); }

/* ===== ossature commune ================================================= */
/* ⚠️ `overflow-x: clip` sur CHAQUE section : la piste du carrousel sort des
   marges de la page pour glisser d'un bord à l'autre, et sans cette coupe elle
   fait défiler la PAGE horizontalement sur téléphone. `clip` et non `hidden` :
   `hidden` créerait un conteneur de défilement, ce qui casserait le collage
   (`sticky`) de la scène du scrub, juste au-dessus. */
.cs-sec { padding: clamp(64px, 11vh, 132px) clamp(18px, 5vw, 40px);
  overflow-x: clip; }
.cs-sec--gris { background: var(--cs-bg-2); }
.cs-wrap { max-width: 1080px; margin: 0 auto; }
.cs-narrow { max-width: 720px; }

.cs-kicker { margin: 0 0 1rem; font-size: .72rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--cs-accent); }
.cs-h2 { margin: 0; font-size: clamp(1.7rem, 3.6vw, 2.7rem); font-weight: 600;
  letter-spacing: -.025em; line-height: 1.12; }
.cs-p { margin: 1rem 0 0; color: var(--cs-ink-2);
  font-size: clamp(1rem, 1.3vw, 1.09rem); line-height: 1.62; max-width: 62ch; }

/* Coupure de ligne DEMANDÉE, et sur téléphone seulement (Lino, 10/08/2026) :
   « Je vous donne les clefs, vous pilotez. » est une chute, elle doit partir à
   la ligne. Au-delà de 700 px la colonne est large et la coupure y laisserait
   un blanc au milieu du paragraphe — d'où le repli.
   ⚠️ Pas de `display: block` sur la phrase à la place : ce serait un second
   paragraphe, avec sa marge, là où Lino demande un simple retour à la ligne. */
.cs-br-tel { display: inline; }
@media (min-width: 700px) { .cs-br-tel { display: none; } }

/* ===== Apparitions AU SCROLL ===========================================
 * ⚠️ La première version animait au CHARGEMENT (`animation-delay`). Défaut
 * relevé par Lino le 05/08 : le temps d'arriver au module 4, son animation
 * était finie depuis longtemps — donc plus rien ne bougeait en descendant.
 * On déclenche désormais à l'ENTRÉE dans le champ de vision : c'est
 * creation-site.js qui pose `data-reveal`, le retard `--d`, puis `.is-in`.
 *
 * ⚠️ TOUT EST PRÉFIXÉ PAR `.js-cs`, classe posée sur <html> par ce même
 * script. Sans JS (ou si le script casse), aucune de ces règles ne s'applique
 * et la page reste entièrement lisible. Ne JAMAIS écrire ici une règle qui
 * masque sans ce préfixe : ce serait une page blanche au moindre pépin. */
.js-cs [data-reveal] { opacity: 0; transform: translateY(14px); }
.js-cs [data-reveal].is-in { opacity: 1; transform: none;
  transition: opacity .7s cubic-bezier(.2,.7,.2,1),
              transform .7s cubic-bezier(.2,.7,.2,1);
  transition-delay: var(--d, 0ms); }
@media (prefers-reduced-motion: reduce) {
  .js-cs [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* --- boutons : un plein, un souligné. Pas de troisième. --- */
.cs-actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }
.cs-btn { display: inline-flex; align-items: center; gap: .5rem;
  padding: .85rem 1.5rem; border-radius: 10px; border: 1px solid transparent;
  font: inherit; font-size: .95rem; font-weight: 600; cursor: pointer;
  text-decoration: none; transition: background .2s, border-color .2s, color .2s; }
.cs-btn-plein { background: var(--cs-accent); color: #fff; }
.cs-btn-plein:hover { background: var(--cs-accent-d); }
.cs-btn-clair { background: transparent; color: var(--cs-ink);
  border-color: var(--cs-line-2); }
.cs-btn-clair:hover { border-color: var(--cs-ink); }
.cs-btn svg { width: 17px; height: 17px; }

/* ===== MODULE 2 — le site ET les images ================================= */
.cs-duo { display: grid; gap: clamp(28px, 5vw, 64px);
  grid-template-columns: 1fr; align-items: start; }
@media (min-width: 900px) { .cs-duo { grid-template-columns: 1.05fr .95fr; } }
.cs-steps { list-style: none; margin: 2rem 0 0; padding: 0;
  display: flex; flex-direction: column; }
.cs-steps li { display: grid; grid-template-columns: 2.2rem 1fr; gap: .9rem;
  padding: 1.1rem 0; border-top: 1px solid var(--cs-line); }
.cs-steps li:last-child { border-bottom: 1px solid var(--cs-line); }
.cs-steps b { grid-column: 2; font-size: 1rem; font-weight: 600; }
.cs-steps span { grid-column: 1; grid-row: 1 / span 2;
  font-size: .78rem; font-weight: 600; color: var(--cs-accent);
  padding-top: .18rem; }
.cs-steps p { grid-column: 2; margin: .25rem 0 0; color: var(--cs-ink-2);
  font-size: .94rem; line-height: 1.55; }

/* ===== MODULE 3 — l'espace d'administration =============================
   Portage natif du bloc React + Tailwind + shadcn fourni par Lino, ramené à
   la DA claire : le titre en dégradé découpé et le halo ont sauté, la
   maquette et son cadre restent. */
/* ⚠️ `overflow-x: clip` : la piste du carrousel sort des marges de la page
   (marges négatives) pour glisser d'un bord à l'autre. Sans cette coupe, elle
   fait déborder la PAGE horizontalement sur téléphone. `clip` et non `hidden` :
   `hidden` créerait un conteneur de défilement, ce qui casserait tout élément
   collant à l'intérieur. */
.cs-admin { scroll-margin-top: 96px; overflow-x: clip; }
.cs-admin .cs-wrap { display: flex; flex-direction: column; align-items: center;
  text-align: center; }
.cs-badge { display: inline-flex; align-items: center; gap: .5rem;
  padding: .34rem .78rem; border-radius: 999px; border: 1px solid var(--cs-line-2);
  font-size: .78rem; line-height: 1; color: var(--cs-ink-2); }
.cs-badge a { display: inline-flex; align-items: center; gap: .28rem;
  color: var(--cs-accent); text-decoration: none; font-weight: 600; }
.cs-badge a:hover { color: var(--cs-accent-d); }
.cs-badge svg { width: 11px; height: 11px; }
.cs-admin .cs-h2 { margin-top: 1.4rem; max-width: 16ch; }
.cs-admin .cs-p { margin-left: auto; margin-right: auto; text-align: center; }
.cs-admin .cs-actions { justify-content: center; }

/* le cadre de la maquette : un filet et une ombre longue, pas de halo */
.cs-scene { width: 100%; margin-top: clamp(34px, 6vh, 70px); }
.cs-frame { border-radius: 16px; padding: 8px;
  background: var(--cs-bg-2); border: 1px solid var(--cs-line);
  box-shadow: 0 34px 70px -34px rgba(20, 22, 26, .42); }
/* maquette claire sur page claire : c'est le filet qui la délimite */
.cs-mockup { border-radius: 10px; overflow: hidden; background: var(--ad-bg);
  border: 1px solid var(--ad-line); }

.cs-bar { display: flex; align-items: center; gap: .5rem;
  padding: .6rem .8rem; border-bottom: 1px solid var(--ad-line);
  background: var(--ad-panel); }
.cs-dots { display: flex; gap: 6px; }
.cs-dots i { width: 10px; height: 10px; border-radius: 50%;
  background: #dcdcd6; }
.cs-url { flex: 1; max-width: 320px; margin: 0 auto; text-align: center;
  padding: .22rem .7rem; border-radius: 999px; background: #fff;
  border: 1px solid var(--ad-line); color: var(--ad-muted);
  font-size: .68rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ===== la maquette d'admin ==============================================
 * Dessinée en HTML/CSS, pas une capture. Trois raisons : elle est nette à
 * toute taille, elle se traduit, et elle ne pèse aucun fichier.
 * ⚠️ La capture de l'original (launchuicomponents.com/app-*.png) n'est PAS
 * reprise : travail d'un tiers, et surtout c'est l'admin DU CLIENT DE LINO
 * qu'on doit montrer, pas l'interface d'un autre produit.
 * Elle reste FLUIDE (jamais de `transform: scale`, qui rendrait le texte
 * flou) : sous 860 px la colonne de gauche disparaît et le tableau perd ses
 * colonnes secondaires, comme le ferait un vrai responsive. */
.cs-app { display: grid; grid-template-columns: 190px 1fr; min-height: 380px;
  text-align: left; color: var(--ad-ink); }
.cs-side { border-right: 1px solid var(--ad-line); background: var(--ad-panel);
  padding: .9rem .75rem; display: flex; flex-direction: column; gap: 1.1rem; }
.cs-side-brand { display: flex; align-items: center; gap: .5rem;
  font-weight: 700; font-size: .82rem; letter-spacing: -.01em; }
.cs-side-brand i { width: 22px; height: 22px; border-radius: 7px; flex: none;
  background: linear-gradient(140deg, var(--ad-accent), #b48cf8); }
.cs-nav { display: flex; flex-direction: column; gap: .12rem; }
.cs-nav a { display: flex; align-items: center; gap: .55rem;
  padding: .46rem .55rem; border-radius: 8px; text-decoration: none;
  color: var(--ad-muted); font-size: .78rem; font-weight: 500; }
.cs-nav a i { width: 14px; height: 14px; border-radius: 4px; flex: none;
  background: currentColor; opacity: .45; }
.cs-nav a.is-on { background: rgba(47,75,216,.08); color: var(--ad-ink); }
.cs-nav a.is-on i { opacity: .9; background: var(--ad-accent); }

.cs-main { display: flex; flex-direction: column; min-width: 0; }
.cs-top { display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: .8rem 1rem; border-bottom: 1px solid var(--ad-line); }
.cs-top h3 { margin: 0; font-size: .95rem; font-weight: 600; letter-spacing: -.01em; }
.cs-search { flex: 1; max-width: 260px; padding: .4rem .7rem; border-radius: 8px;
  background: var(--ad-panel); border: 1px solid var(--ad-line);
  color: var(--ad-muted); font-size: .72rem; }
.cs-avatar { width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: linear-gradient(140deg, #4d5a92, #7d8cf8); }

.cs-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem;
  padding: 1rem; }
.cs-stat { padding: .75rem .85rem; border-radius: 10px;
  background: var(--ad-panel-2); border: 1px solid var(--ad-line); }
.cs-stat span { display: block; color: var(--ad-muted); font-size: .66rem;
  letter-spacing: .06em; text-transform: uppercase; }
.cs-stat b { display: block; margin-top: .2rem; font-size: 1.32rem;
  font-weight: 700; letter-spacing: -.02em; }
.cs-stat em { font-style: normal; font-size: .68rem; color: var(--ad-ok); }

.cs-tablewrap { padding: 0 1rem 1rem; min-width: 0; }
.cs-tablehead { display: flex; align-items: center; justify-content: space-between;
  padding: .1rem 0 .55rem; }
.cs-tablehead h4 { margin: 0; font-size: .8rem; font-weight: 600; }
.cs-tablehead span { color: var(--ad-muted); font-size: .7rem; }
.cs-table { width: 100%; border-collapse: collapse; border-radius: 10px;
  overflow: hidden; background: var(--ad-panel-2);
  border: 1px solid var(--ad-line); }
.cs-table th, .cs-table td { padding: .58rem .75rem; text-align: left;
  font-size: .74rem; border-bottom: 1px solid var(--ad-line); }
.cs-table th { color: var(--ad-muted); font-weight: 600; font-size: .66rem;
  letter-spacing: .06em; text-transform: uppercase; background: var(--ad-panel); }
.cs-table tr:last-child td { border-bottom: 0; }
.cs-table td:first-child { font-weight: 600; }
.cs-tag { display: inline-block; padding: .16rem .5rem; border-radius: 999px;
  font-size: .64rem; font-weight: 600; letter-spacing: .03em; }
.cs-tag-ok   { color: var(--ad-ok);   background: rgba(28,127,85,.09);
               border: 1px solid rgba(28,127,85,.22); }
.cs-tag-warn { color: var(--ad-warn); background: rgba(164,103,29,.09);
               border: 1px solid rgba(164,103,29,.22); }
.cs-tag-off  { color: var(--ad-muted); background: var(--ad-panel);
               border: 1px solid var(--ad-line); }

@media (max-width: 860px) {
  .cs-app { grid-template-columns: 1fr; min-height: 0; }
  .cs-side, .cs-search { display: none; }
  .cs-stats { grid-template-columns: 1fr 1fr; }
  .cs-table th:nth-child(2), .cs-table td:nth-child(2),
  .cs-table th:nth-child(3), .cs-table td:nth-child(3) { display: none; }
}
@media (max-width: 520px) {
  .cs-stats { grid-template-columns: 1fr; }
  .cs-url { display: none; }
}

/* ===== MODULE 4 — les deux formules =====================================
 * ⚠️ Les deux formules partagent l'ESSENTIEL des prestations (Lino, 05/08).
 * D'où cette mise en page, et pas deux colonnes comparatives : le commun est
 * listé UNE FOIS, en grand, puis deux cartes courtes ne disent QUE ce qui
 * change. Deux colonnes qui répètent les mêmes dix lignes produisent l'effet
 * inverse de celui recherché — la formule la moins chère paraît déjà
 * complète, et le visiteur passe son temps à chercher la différence au lieu
 * de se projeter. */
.cs-inclus { margin-top: 2.4rem; padding: clamp(22px, 3vw, 34px);
  border: 1px solid var(--cs-line); border-radius: 16px; background: #fff; }
.cs-inclus h3 { margin: 0 0 1.2rem; font-size: .78rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--cs-muted); }
.cs-inclus ul { list-style: none; margin: 0; padding: 0;
  display: grid; gap: .7rem 2rem;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.cs-inclus li { display: grid; grid-template-columns: 1.1rem 1fr; gap: .6rem;
  font-size: .95rem; color: var(--cs-ink-2); line-height: 1.45; }
.cs-inclus li svg { width: 15px; height: 15px; margin-top: .22rem;
  color: var(--cs-accent); }
.cs-inclus li b { color: var(--cs-ink); font-weight: 600; }

.cs-formules { display: grid; gap: clamp(14px, 2vw, 22px); margin-top: 1.2rem;
  grid-template-columns: 1fr; }
@media (min-width: 860px) { .cs-formules { grid-template-columns: 1fr 1fr; } }
.cs-formule { padding: clamp(22px, 3vw, 34px); border-radius: 16px;
  border: 1px solid var(--cs-line); background: #fff;
  display: flex; flex-direction: column; }
/* ⚠️ La deuxième formule est simplement CERNÉE, pas remplie ni colorée : sur
   une page minimaliste, un filet d'accent suffit à dire « celle-ci ». */
.cs-formule--phare { border-color: var(--cs-accent); }
.cs-formule-num { font-size: .72rem; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--cs-muted); }
.cs-formule--phare .cs-formule-num { color: var(--cs-accent); }
.cs-formule h3 { margin: .6rem 0 0; font-size: clamp(1.35rem, 2.4vw, 1.75rem);
  font-weight: 600; letter-spacing: -.02em; }
.cs-formule > p { margin: .8rem 0 0; color: var(--cs-ink-2);
  font-size: .98rem; line-height: 1.6; }
.cs-formule .cs-plus { margin: 1.4rem 0 0; padding-top: 1.2rem;
  border-top: 1px solid var(--cs-line); }
.cs-plus span { display: block; font-size: .72rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--cs-muted);
  margin-bottom: .55rem; }
.cs-plus p { margin: 0; font-size: .95rem; color: var(--cs-ink);
  line-height: 1.55; font-weight: 500; }
.cs-formule .cs-btn { margin-top: auto; align-self: flex-start; }
.cs-formule .cs-actions { margin-top: 1.8rem; }

/* ===== MODULE 5 — le déroulé ============================================
 * ⚠️ LA SECTION A ÉTÉ SUPPRIMÉE DU HTML LE 10/08/2026 (Lino) : son contenu
 * vit maintenant derrière le « i » du contact. Ces règles sont CONSERVÉES —
 * elles ne coûtent rien, et elles remettent le module debout d'un seul coller
 * s'il doit revenir. Ne pas les nettoyer sans avoir vérifié que le HTML ne le
 * réutilise nulle part. */
.cs-flow { list-style: none; margin: 2.4rem 0 0; padding: 0;
  display: grid; gap: 1px; background: var(--cs-line);
  border: 1px solid var(--cs-line); border-radius: 16px; overflow: hidden;
  grid-template-columns: 1fr; }
@media (min-width: 760px) { .cs-flow { grid-template-columns: repeat(4, 1fr); } }
.cs-flow li { background: #fff; padding: clamp(20px, 2.4vw, 28px); }
.cs-flow h3 { margin: 0; font-size: 1.06rem; font-weight: 600;
  letter-spacing: -.01em; }
.cs-flow p { margin: .45rem 0 0; color: var(--cs-ink-2); font-size: .92rem;
  line-height: 1.55; }

/* ===== contact ========================================================== */
.cs-contact { scroll-margin-top: 96px; }
.cs-contact .ask-standalone { margin-top: 2.4rem; }

/* --- LA FENÊTRE « DEMANDER » AUX COULEURS DE LA PAGE (Lino, 10/08/2026) ---
 * ask.css est VOLONTAIREMENT AUTONOME : il ne connaît aucune palette, et le
 * sien est celui du monde Sport (corail, panneau chaud, ancre bleu-vert). Posé
 * tel quel sur le seul monde CLAIR du site, il ouvrait une fenêtre orange au
 * milieu d'une page bleu d'encre. On l'habille donc ici, comme /realestate et
 * /pro le font chacun pour eux — et sans toucher au composant partagé.
 *
 * ⚠️ Les deux variables ne suffisent PAS : ask.css garde trois valeurs de
 * corail ÉCRITES EN DUR, qu'aucune variable ne couvre — l'ombre du bouton
 * d'envoi, celle de la pastille « envoyé », et le halo de focus. Laissées
 * telles quelles, il restait trois taches orange dans une fenêtre bleue.
 * ⚠️ AUCUNE LUEUR, AUCUN HALO : règle de la page depuis le 05/08. Les ombres
 * colorées d'ask.css deviennent donc des ombres NEUTRES et discrètes, et le
 * panneau se tient sur un filet d'un pixel comme le reste de la page.
 * Seule l'ombre de portée du panneau reste marquée : elle ne décore pas, elle
 * décolle la fenêtre du contenu qui continue derrière. */
.cs .ask-modal { --ask-accent: var(--cs-accent); --ask-accent-2: var(--cs-accent-d); }
.cs .ask-panel {
  border-radius: 16px;
  border: 1px solid var(--cs-line);
  background: #fff;
  color: var(--cs-ink);
  box-shadow: 0 24px 60px rgba(20, 22, 26, .22);
}
.cs .ask-eyebrow { color: var(--cs-accent); }
.cs .ask-context { color: var(--cs-ink-2); }
.cs .ask-context b { color: var(--cs-ink); }
.cs .ask-field > span { color: var(--cs-muted); }
.cs .ask-field input,
.cs .ask-field select,
.cs .ask-field textarea {
  border-color: var(--cs-line-2); color: var(--cs-ink); border-radius: 10px;
}
.cs .ask-field input:focus,
.cs .ask-field select:focus,
.cs .ask-field textarea:focus { box-shadow: 0 0 0 3px rgba(47, 75, 216, .14); }
.cs .ask-close { background: var(--cs-bg-2); color: var(--cs-ink); }
.cs .ask-close:hover { background: var(--cs-line); }
/* le bouton d'envoi reprend `.cs-btn-plein` : un aplat, pas un dégradé */
.cs .ask-send {
  border-radius: 10px; background: var(--cs-accent); box-shadow: none;
}
.cs .ask-send:hover:not(:disabled) { background: var(--cs-accent-d); transform: none; }
.cs .ask-done-badge { background: var(--cs-accent); box-shadow: none; }
.cs .ask-done p { color: var(--cs-ink-2); }

/* ⚠️ LE VOLET DÉROULANT DOIT AVOIR L'AIR D'UN VOLET DÉROULANT. Un `<select>`
   à qui l'on ne donne rien garde la flèche du système, et elle ne suit pas la
   palette ; à qui l'on donne un fond, il perd la flèche sur WebKit et devient
   indistinguable d'un champ de saisie. On la redessine donc : un chevron en
   SVG intégré (aucune requête réseau), posé à droite, et la marge intérieure
   droite lui laisse la place.
   ⚠️ Le chevron est en `%23` et non `#` : dans une `url()` de data-URI, le
   dièse ouvrirait un fragment et la flèche disparaîtrait. */
.cs .ask-field select {
  appearance: none; -webkit-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234b5058' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px 16px;
}
/* tant que rien n'est choisi, le libellé se lit comme un placeholder */
.cs .ask-field select:invalid { color: var(--cs-muted); }

/* --- le « i » du contact (Lino, 10/08/2026) ------------------------------
 * Il porte le résumé de « Comment ça se passe », supprimé le même jour.
 * ⚠️ Le « i » est un inline-block DANS le titre : il suit donc le dernier mot
 * comme un caractère et reste collé à lui quelle que soit la largeur. Posé en
 * `position: absolute` à droite du bloc, il se retrouvait loin du texte dès
 * que le titre tenait sur une ligne courte.
 * ⚠️ `vertical-align` en `em` et non `super` : il se calcule ainsi sur le
 * corps du « i » lui-même, qui est fixe, et non sur celui du titre, qui varie
 * du simple au double entre le téléphone et l'ordinateur.
 *
 * ⚠️ LA BULLE EST ANCRÉE SUR LE TITRE, PAS SUR LE « i ». C'est le <h2> qui
 * porte le `position: relative`, et la bulle s'y cale par `left: 0; right: 0`
 * — donc sa largeur est celle du titre, plafonnée, et JAMAIS une largeur à
 * elle. Accrochée au « i » (large de 25 px), il aurait fallu lui donner une
 * largeur en `vw` et la rattraper à la main sur les petits écrans : elle
 * débordait par la droite quand le « i » tombait en fin de ligne, et par la
 * gauche quand la dernière ligne était courte. Ancrée au titre, le cas
 * n'existe plus, à aucune taille d'écran. Ne pas repasser le `relative` sur
 * `.cs-info`. */
.cs-h2--i { position: relative; }
.cs-info { display: inline-block;
  margin-left: .5rem; vertical-align: .38em; }

.cs-info-b { width: 1.55rem; height: 1.55rem; padding: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--cs-line-2); background: #fff;
  color: var(--cs-accent); cursor: pointer;
  /* le corps du « i » est FIXE : il ne doit pas enfler avec le titre.
     ⚠️ Polices nommées EN CLAIR, jamais `var(--sans)` — règle de la page :
     un `var()` non résolu invalide toute la déclaration (voir en-tête). */
  font: 600 .82rem/1 "Geist", system-ui, sans-serif;
  font-style: italic; letter-spacing: 0;
  transition: border-color .2s, background .2s, color .2s; }
.cs-info-b:hover,
.cs-info-b[aria-expanded="true"] { border-color: var(--cs-accent);
  background: var(--cs-accent); color: #fff; }
.cs-info-b:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 2px; }

/* ⚠️ `position: absolute` : la bulle ne pousse rien en s'ouvrant. Sans ça, un
 * simple survol ferait descendre tout le formulaire sous le titre.
 * ⚠️ `left: 0; right: 0` PLUTÔT QU'UNE LARGEUR : elle épouse le titre, donc la
 * colonne de la page, et ne peut pas déborder. `max-width` la retient sur les
 * grands écrans, où une ligne de 700 px serait illisible.
 * ⚠️ `text-align: left` est indispensable : la section contact est centrée, et
 * quatre phrases centrées sont illisibles. */
.cs-info-bulle { position: absolute; z-index: 30; box-sizing: border-box;
  top: calc(100% + 12px); left: 0; right: 0;
  /* `margin-inline: auto` avec left/right à 0 : la bulle reste centrée sous le
     titre une fois qu'elle bute sur son `max-width` */
  max-width: 34rem; margin-inline: auto; padding: 1rem 1.15rem;
  border-radius: 14px; border: 1px solid var(--cs-line);
  background: #fff; box-shadow: 0 22px 44px -22px rgba(20, 22, 26, .38);
  text-align: left; letter-spacing: normal; text-transform: none;
  font-size: .88rem; font-weight: 400; line-height: 1.5;
  color: var(--cs-ink-2); cursor: default; }
.cs-info-bulle[hidden] { display: none; }
.cs-info-bulle b { display: block; margin-bottom: .6rem;
  color: var(--cs-ink); font-size: .72rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; }
/* chaque temps du déroulé sur sa propre ligne, séparé par un filet — l'ordre
   compte, mais AUCUN CHIFFRE VISIBLE : règle de la page depuis le 05/08 */
.cs-info-bulle span { display: block; padding: .5rem 0;
  border-top: 1px solid var(--cs-line); }
.cs-info-bulle span:first-of-type { border-top: 0; padding-top: 0; }
.cs-info-bulle span:last-child { padding-bottom: 0; }
.cs-foot { padding: 2.4rem clamp(18px, 5vw, 40px) 3rem; text-align: center;
  border-top: 1px solid var(--cs-line); color: var(--cs-muted); font-size: .82rem; }
.cs-foot a { color: var(--cs-muted); }

/* ===== emplacements non écrits ==========================================
 * ⚠️ `grep data-brouillon creation-site.html` doit revenir VIDE avant toute
 * mise en ligne. */
[data-brouillon] { border: 1px dashed var(--cs-line-2); border-radius: 16px;
  padding: 2.4rem 1.4rem; text-align: center; color: var(--cs-muted); }
[data-brouillon] b { display: block; font-size: .82rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--cs-ink-2); }
[data-brouillon] p { margin: .5rem 0 0; font-size: .88rem; }

/* ===== Bouton « fumée » — d'après @lran1028 (21st.dev) ====================
 * Le shader et sa mécanique vivent dans smoky.js ; ici, l'habillage.
 * Le bouton est SOMBRE et le libellé blanc : la fumée est faite de bleu
 * Klein, de brun et de presque-noir. Sur un bouton clair, le libellé passerait
 * tantôt sur du blanc, tantôt sur de la fumée sombre — illisible la moitié du
 * temps. Sur fond sombre, la lisibilité ne dépend plus du hasard de l'animation.
 * ⚠️ Le fond `background` du bouton doit RESTER : c'est lui qu'on voit si
 * WebGL manque (smoky.js n'insère alors aucun canvas). */
.cs-btn-smoky { position: relative; isolation: isolate; overflow: hidden;
  background: #0d1017; color: #fff; border-color: transparent;
  padding: .95rem 1.9rem; border-radius: 12px; }
.cs-btn-smoky:hover { background: #14181f; transform: translateY(-1px); }
.cs-btn-smoky > span { position: relative; z-index: 1; }
.smoky-canvas { position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; display: block; pointer-events: none; }

/* ===== Widget « visiteurs » — d'après @aghasisahakyan1 (21st.dev) =========
 * Posé DANS le module de l'admin, à côté de la maquette : la maquette montre
 * l'écran, le widget montre ce qu'on y regarde en premier. C'est le seul
 * élément de la page qui a une ombre douce — assumé, il doit flotter. */
.cs-widget { width: min(340px, 100%); border-radius: 20px; padding: 8px;
  background: var(--cs-bg-2); border: 1px solid var(--cs-line);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); text-align: left; }
.cs-widget-in { background: #fff; border-radius: 14px; padding: 1.05rem 1.1rem .7rem; }
.cs-widget-h { display: flex; align-items: baseline; gap: .5rem; }
.cs-widget-h b { font-size: 1.9rem; font-weight: 700; letter-spacing: -.03em; }
.cs-widget-h span { color: var(--cs-muted); font-size: .88rem; font-weight: 500; }
.cs-chart { display: block; width: 100%; height: 96px; margin-top: .5rem; }
/* la courbe se dessine au chargement : `stroke-dasharray` = sa longueur, et
   on ramène le décalage à zéro. Longueur mise en dur (mesurée) — inutile de
   charger du JS pour un tracé qui ne change jamais. */
.cs-chart path { stroke: var(--cs-accent); stroke-width: 2.4; fill: none;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 300; stroke-dashoffset: 0; }
@keyframes cs-trace { from { stroke-dashoffset: 300; } to { stroke-dashoffset: 0; } }
/* ⚠️ Le tracé se déclenche à la RÉVÉLATION, pas au chargement. Sans le
   `.js-cs`, la courbe est simplement dessinée d'emblée : c'est le repli sans
   JS, et il vaut mieux qu'une courbe invisible. */
.js-cs .cs-chart path { stroke-dashoffset: 300; }
.js-cs .cs-widget.is-in .cs-chart path {
  animation: cs-trace 1.6s cubic-bezier(.4,0,.2,1) .3s forwards; }
@media (prefers-reduced-motion: reduce) {
  .js-cs .cs-chart path { stroke-dashoffset: 0; animation: none; }
}
.cs-days { display: flex; justify-content: space-between; padding: .3rem .1rem 0;
  color: var(--cs-muted); font-size: .74rem; }
.cs-widget-f { display: flex; align-items: center; gap: .55rem;
  padding: .7rem .5rem .3rem; font-size: .86rem; font-weight: 600; }
.cs-widget-f i { width: 22px; height: 22px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: var(--cs-accent); }
.cs-widget-f i svg { width: 12px; height: 12px; color: #fff; }

/* la maquette et le widget côte à côte au-delà de 980 px */
.cs-scene-duo { display: grid; gap: clamp(20px, 3vw, 34px); width: 100%;
  grid-template-columns: 1fr; align-items: center;
  margin-top: clamp(34px, 6vh, 70px); }
@media (min-width: 980px) { .cs-scene-duo { grid-template-columns: 1fr 340px; } }
.cs-scene-duo .cs-scene { margin-top: 0; }
.cs-scene-duo .cs-widget { justify-self: center; }

/* ===== Cartes de prix — d'après @lyanchouss (21st.dev), en CLAIR ==========
 * L'original est sombre, avec une grille en fond et une bascule
 * mensuel/annuel. La bascule a été RETIRÉE : on vend un site, une fois — un
 * choix mensuel/annuel n'aurait aucun sens et donnerait l'idée d'un
 * abonnement, exactement ce que la page promet de ne pas être.
 * La grille de fond est gardée, très pâle : c'est ce qui donne son caractère
 * au bloc sans ajouter de couleur. */
/* --- LE FOND BLEU TRÈS CLAIR DE LA SECTION (Lino, 10/08/2026) -------------
 * Le panneau animé du hero, repris tel quel et posé DERRIÈRE toute la
 * section : du haut de « Nos deux formules » au bas de la dernière carte, donc
 * jusqu'au contact — il n'y a plus rien entre les deux depuis que « Comment ça
 * se passe » a été supprimé.
 *
 * ⚠️ LE QUADRILLAGE A ÉTÉ RETIRÉ (`.cs-prix::before`, un maillage de 68 px
 * effacé sur les bords au masque radial). Il meublait un fond BLANC ; sous le
 * bleu, deux décors se superposaient derrière les mêmes cartes. Décision de
 * Lino le 10/08. Il reste entier dans git si le bleu devait repartir.
 *
 * ⚠️ BORDS FRANCS, sans fondu (sa demande) : c'est `overflow: hidden` de la
 * section qui coupe le panneau, exactement comme les bandes grises `--gris`
 * commencent et finissent net. Un fondu ferait dépendre le début du chapitre
 * de la hauteur de l'écran.
 *
 * ⚠️ LE FOND CSS DU PANNEAU DOIT RESTER : sans WebGL, velaris.js n'insère
 * aucun canvas et c'est lui — et lui seul — qu'on voit. Même règle que le
 * panneau du hero. Il reprend les mêmes teintes, en dégradé fixe.
 *
 * ⚠️ `z-index: 0` sur le fond ET `z-index: 1` sur le contenu : les cartes sont
 * blanches et opaques, elles passeraient devant de toute façon, mais le titre,
 * lui, est un texte nu — sans contexte d'empilement explicite, l'ordre du
 * document suffirait aujourd'hui et casserait au premier élément déplacé. */
.cs-prix { position: relative; overflow: hidden; }
.cs-prix-fond { position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(160deg, #eaf0ff 0%, #dfe7ff 45%, #d2ddff 100%); }
.cs-prix > .cs-wrap { position: relative; z-index: 1; }
.cs-prix-head { text-align: center; }
.cs-prix-head .cs-p { margin-left: auto; margin-right: auto; }

/* --- « Nos deux formules » (Lino, 10/08/2026) ----------------------------
 * C'était le CHAPEAU de la section (`.cs-kicker` : bleu, capitales, 0,72 rem).
 * Il en est devenu le TITRE, « en plus gros » — il garde donc son écriture en
 * capitales bleues, elle est seulement mise à l'échelle d'un titre. Le <h2>
 * « La différence, ce sont les images. » et son paragraphe ont été retirés.
 * ⚠️ L'interlettre en capitales laisse un blanc après la DERNIÈRE lettre :
 * `text-indent` le rattrape, sinon le titre n'est pas optiquement centré. */
.cs-prix-h { color: var(--cs-accent);
  font-size: clamp(1.35rem, 3.2vw, 2.1rem); font-weight: 600;
  letter-spacing: .1em; text-indent: .1em; text-transform: uppercase; }

.cs-cartes { display: grid; gap: clamp(14px, 2vw, 22px); margin-top: 2.6rem;
  grid-template-columns: 1fr; align-items: start; }
@media (min-width: 860px) { .cs-cartes { grid-template-columns: 1fr 1fr; } }
.cs-carte { background: #fff; border: 1px solid var(--cs-line);
  border-radius: 18px; padding: clamp(24px, 3vw, 36px);
  display: flex; flex-direction: column; }
/* ⚠️ La carte mise en avant est CERNÉE, pas remplie : sur une page
   minimaliste un filet d'accent suffit à dire « celle-ci ». */
.cs-carte--phare { border-color: var(--cs-accent); }
.cs-carte h3 { margin: 0; font-size: clamp(1.3rem, 2.2vw, 1.6rem);
  font-weight: 600; letter-spacing: -.02em; }
.cs-carte-sub { margin: .45rem 0 0; color: var(--cs-muted); font-size: .93rem; }
.cs-carte-prix { margin: 1.5rem 0 0; display: flex; align-items: baseline; gap: .5rem; }
.cs-carte-prix b { font-size: clamp(1.9rem, 3.4vw, 2.5rem); font-weight: 700;
  letter-spacing: -.035em; line-height: 1; }
.cs-carte-prix span { color: var(--cs-muted); font-size: .86rem; }
.cs-carte-note { margin: .5rem 0 0; color: var(--cs-muted); font-size: .82rem; }

/* --- l'option « création de logo » (Lino, 10/08/2026) --------------------
 * La seule case à cocher de la page. DÉPLACÉE EN BAS DE CARTE, juste au-dessus
 * du bouton, à la demande de Lino — elle était sous le prix.
 * ⚠️ `margin-top: auto` : c'est ELLE qui pousse maintenant le couple
 * option + bouton en bas de la carte. Le bouton, lui, a perdu son `auto` —
 * deux marges automatiques se seraient partagé l'espace et le bloc aurait
 * flotté au milieu du vide.
 * ⚠️ Le prix qu'elle modifie est TOUT EN HAUT de la carte, donc hors de
 * l'écran sur téléphone : d'où le total rappelé à droite de la case
 * (`.cs-opt-total`). Sans lui, cocher n'a l'air de rien faire. Si l'option
 * remonte un jour sous le prix, c'est ce total qui devient inutile.
 * ⚠️ Traitée comme une ligne de liste, pas comme un formulaire : ni cadre, ni
 * fond. Un champ dessiné au milieu de deux cartes de prix ferait croire à un
 * début de commande en ligne — or on ne vend pas un site en ligne, on demande
 * un rendez-vous. */
/* ⚠️ L'ENVELOPPE PORTE LE `margin-top: auto`, PAS LES CASES (10/08/2026, quand
   une deuxième option est arrivée). Deux marges automatiques dans le même
   conteneur en colonne se partagent l'espace restant : les deux cases se
   seraient écartées l'une de l'autre et le bloc aurait flotté au milieu du
   vide. Même raison qui avait fait retirer celle du bouton. */
.cs-opts { margin: auto 0 1rem; display: flex; flex-direction: column; }
.cs-opt { padding-top: 1.2rem;
  border-top: 1px solid var(--cs-line);
  display: flex; align-items: center; gap: .55rem;
  cursor: pointer; font-size: .88rem; color: var(--cs-ink-2);
  user-select: none; -webkit-user-select: none; }
/* Le total est en bout de ligne, comme sur un ticket — mais SUR SA PROPRE
   LIGNE depuis qu'il y a deux options (10/08/2026 au soir). Posé dans la case,
   il lui volait la moitié de la largeur : à 375 px, le libellé de
   l'hébergement tombait sur quatre lignes dans une colonne de 200 px. */
.cs-opt-total { align-self: flex-end; padding-top: .9rem;
  color: var(--cs-accent); font-weight: 700; white-space: nowrap; }
.cs-opt-total[hidden] { display: none; }
.cs-opt input { width: 17px; height: 17px; flex: none; margin: 0;
  accent-color: var(--cs-accent); cursor: pointer; }
.cs-opt b { color: var(--cs-ink); font-weight: 600; }
.cs-opt:hover { color: var(--cs-ink); }
/* l'anneau de focus doit rester visible : c'est le seul repère au clavier */
.cs-opt input:focus-visible { outline: 2px solid var(--cs-accent);
  outline-offset: 2px; }

/* l'intertitre qui annonce le tronc commun dans chaque carte. Discret
   volontairement : il sépare deux listes, il n'ouvre pas un chapitre. */
.cs-carte-lab { margin: 0 0 .9rem; font-size: .72rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--cs-muted);
  padding-top: 1.2rem; border-top: 1px solid var(--cs-line); }

.cs-carte hr { margin: 1.5rem 0; border: 0; border-top: 1px solid var(--cs-line); }
.cs-carte ul { list-style: none; margin: 0 0 1.8rem; padding: 0;
  display: flex; flex-direction: column; gap: .62rem; }
.cs-carte li { display: grid; grid-template-columns: 1.05rem 1fr; gap: .6rem;
  font-size: .93rem; color: var(--cs-ink-2); line-height: 1.45; }
.cs-carte li svg { width: 14px; height: 14px; margin-top: .2rem; color: var(--cs-accent); }
.cs-carte li b { color: var(--cs-ink); font-weight: 600; }
/* ⚠️ Le bouton n'a PLUS `margin-top: auto` : c'est `.cs-opt`, juste au-dessus,
   qui pousse désormais le bas de carte. Deux marges automatiques se seraient
   partagé l'espace restant et le couple aurait flotté au milieu du vide. */
.cs-carte .cs-btn { justify-content: center; }

/* --- LIRE UNE CARTE EN DEUX TEMPS (Lino, 10/08/2026) ---------------------
 * « Facilite la lecture. » Depuis que les huit lignes communes sont recopiées
 * dans chaque carte, la différence entre les deux formules — quatre lignes sur
 * douze — se noyait dans un mur de coches identiques. Deux traitements, et
 * volontairement DIFFÉRENTS l'un de l'autre :
 *
 *   le TITRE      → il change de couleur et gagne un filet d'accent.
 *   les 4 lignes  → elles passent sur un fond teinté, à l'encre pleine.
 *
 * Deux fois le même effet (deux fonds, ou deux couleurs) aurait mis les deux
 * choses sur le même plan ; on lit d'abord de quelle formule il s'agit, et
 * ensuite ce qu'elle a de particulier. Le tronc commun reste en dessous, plus
 * clair et plus petit : il rassure, il ne se compare pas. */
.cs-carte h3 { color: var(--cs-accent); }
.cs-carte h3::after { content: ""; display: block; width: 2.4rem; height: 2px;
  margin-top: .7rem; background: var(--cs-accent); border-radius: 2px; }

/* ⚠️ Les marges NÉGATIVES rattrapent la marge intérieure de la carte : le
   bloc teinté déborde jusqu'aux filets, sinon il flotte dans un cadre déjà
   cadré et l'effet ressemble à une erreur de gabarit. La valeur DOIT rester
   le miroir exact du `padding` de `.cs-carte` — les désaccorder décale le
   bloc d'un côté.
   ⚠️ Sélecteurs écrits `.cs-carte .cs-cle` et non `.cs-cle` seul : `.cs-carte
   ul` (une classe + un élément) est plus spécifique qu'une classe nue et
   reprendrait la main sur les marges. */
.cs-carte .cs-cle { margin-inline: calc(clamp(24px, 3vw, 36px) * -1);
  margin-bottom: 1.6rem; padding: 1.2rem clamp(24px, 3vw, 36px);
  background: var(--cs-bg-2); }
.cs-carte .cs-cle li { font-size: .98rem; color: var(--cs-ink); line-height: 1.5; }
.cs-carte .cs-cle li + li { margin-top: .75rem; }

/* le commun : un cran en dessous, en corps comme en couleur.
   ⚠️ SANS COCHES depuis le 10/08/2026 (Lino) — elles ont été retirées du HTML,
   pas masquées. La colonne d'icônes de `.cs-carte li` doit donc disparaître
   AUSSI : laissée en place, elle réservait 1,05 rem de vide à gauche et tout
   le tronc commun apparaissait décalé par rapport au reste de la carte.
   ⚠️ Les quatre lignes de `.cs-cle`, elles, gardent leurs coches : c'est ce
   contraste qui fait lire la différence en premier. */
.cs-carte .cs-commun { margin-bottom: 0; }
.cs-carte .cs-commun li { display: block; font-size: .88rem;
  color: var(--cs-muted); }
.cs-carte .cs-commun li b { color: var(--cs-ink-2); }


/* ===== Hero — panneau à dégradé animé (« Velaris ») ======================
 * Portage du composant fourni par Lino. Le shader vit dans velaris.js ; ici,
 * le cadre.
 *
 * ⚠️ UNE BANDE BLANCHE AU-DESSUS ET EN DESSOUS (demande de Lino, 05/08) : le
 * panneau ne touche jamais le haut ni le bas de la page. Il est aussi rentré
 * sur les côtés et arrondi — c'est ce que montre la démo du composant, et sur
 * une page minimaliste un panneau qui flotte se tient mieux qu'un bandeau
 * collé aux bords. Pour le passer pleine largeur : retirer le `max-width` et
 * le `border-radius`, rien d'autre.
 *
 * ⚠️ Le `background` en dégradé fixe DOIT rester : c'est lui qu'on voit si
 * WebGL manque (velaris.js n'insère alors aucun canvas). Il reprend les mêmes
 * teintes, en statique.
 *
 * ⚠️ Le hero « qui s'ouvre au scroll » qui occupait cette place a été retiré
 * le 05/08 au soir. Ne pas le réintroduire sans le redemander à Lino. */
/* ⚠️ LE PANNEAU GARDE SA TAILLE (Lino, 10/08/2026 — deux fois plutôt qu'une).
 * Une version intermédiaire l'avait RÉTRÉCI pour faire tenir le « Défiler »
 * sous lui dans le premier écran : refusé net. Le mot passe PAR-DESSUS le
 * panneau, en bas (voir `.cs-hint` plus bas). La hauteur ci-dessous est celle
 * d'origine — ne pas y toucher pour faire de la place à quoi que ce soit. */
.cs-hero { padding-top: clamp(96px, 15vh, 150px); }
.cs-velaris { position: relative; isolation: isolate; overflow: hidden;
  border-radius: 20px; min-height: clamp(430px, 66svh, 620px);
  display: grid; place-items: center;
  padding: clamp(38px, 7vw, 72px) clamp(20px, 5vw, 60px);
  background: radial-gradient(120% 90% at 30% 20%, #2f4bd8, #1b2f96 42%, #05070f); }
.velaris-canvas { position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; display: block; pointer-events: none; }
.cs-velaris-in { position: relative; z-index: 1; text-align: center;
  max-width: 760px; }

.cs-velaris-in h1 { margin: 0; color: #fff;
  font-size: clamp(2.1rem, 5.4vw, 3.9rem); font-weight: 600;
  letter-spacing: -.035em; line-height: 1.05;
  text-shadow: 0 2px 34px rgba(0,0,0,.32); }
.cs-velaris-in h1 em { font-style: normal; color: #b9c4ff; }
.cs-velaris-in .cs-p { margin: 1.3rem auto 0; color: rgba(255,255,255,.82);
  max-width: 46ch; text-shadow: 0 1px 20px rgba(0,0,0,.3); }
.cs-velaris-in .cs-actions { justify-content: center; margin-top: 2.1rem; }
/* le bouton fumée est presque noir : sur ce panneau sombre il se fondrait,
   d'où le liseré clair — il n'en a pas besoin sur le blanc du reste du site */
.cs-velaris .cs-btn-smoky { box-shadow: 0 0 0 1px rgba(255,255,255,.22),
                                        0 18px 40px -18px rgba(0,0,0,.7); }

/* la pastille du hero, sur verre */
.cs-velaris-in .cs-badge { border-color: rgba(255,255,255,.28);
  background: rgba(255,255,255,.1); color: rgba(255,255,255,.86);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  margin-bottom: 1.5rem; }
.cs-velaris-in .cs-badge a { color: #fff; }

/* la mention sous le panneau reste sur le blanc de la page */
.cs-hero-note { margin: 2.2rem auto 0; padding-top: 1.4rem;
  border-top: 1px solid var(--cs-line); color: var(--cs-muted);
  font-size: .88rem; max-width: 62ch; text-align: center; }

/* --- « Défiler » PAR-DESSUS le panneau (Lino, 10/08/2026) ----------------
 * ⚠️ IL EST DANS LE PANNEAU, EN BAS, PAS EN DESSOUS. Première version : posé
 * sous le panneau, sur le blanc — il tombait alors sous la ligne de flottaison,
 * et le rétrécissement du panneau qui aurait pu l'y ramener a été refusé. Il se
 * superpose donc au dégradé, comme sur /sport et /realestate où il se superpose
 * à la vidéo. Ne pas le ressortir du panneau.
 * ⚠️ Il clignote donc blanc ↔ bleu clair — les teintes du panneau sombre, et
 * non le bleu d'encre du texte de la page, qui y serait illisible.
 * ⚠️ `z-index: 1` : le canvas du shader est à 0. Sans ça, le mot passe dessous.
 * ⚠️ `pointer-events: none` : il couvre le bas du panneau et volerait sinon les
 * clics au bouton, qui est juste au-dessus.
 * ⚠️ La marge basse tient compte de `safe-area-inset` : sur un iPhone, l'écran
 * ne s'arrête pas au bord de la vitre.
 * ⚠️ `flex-direction: column` met la flèche SOUS le mot — scrollcue.css attend
 * d'être posé dans un élément en colonne. Et la flèche n'a pas de couleur à
 * elle (`currentColor`) : c'est l'animation sur `color` ci-dessous qui la fait
 * clignoter. Lui en donner une romprait ce lien. */
.cs-hint { position: absolute; z-index: 1;
  left: 50%; transform: translateX(-50%);
  bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  margin: 0; pointer-events: none;
  display: flex; flex-direction: column; align-items: center;
  font-size: .78rem; font-weight: 600;
  letter-spacing: .3em; text-indent: .3em;   /* rattrape l'interlettre finale */
  text-transform: uppercase;
  color: #fff;
  /* le panneau est sombre mais son dégradé s'éclaircit par endroits : l'ombre
     garantit le mot lisible partout, comme sur les autres mondes */
  text-shadow: 0 2px 16px rgba(0, 0, 0, .55);
  animation: cs-hint-flash 1.4s steps(1) infinite;
}
@keyframes cs-hint-flash {
  0%, 49%   { color: #fff; }
  50%, 100% { color: #b9c4ff; }
}
@media (prefers-reduced-motion: reduce) {
  .cs-hint { animation: none; }
}


/* ===== Fenêtre de paiement — 5e pièce du pack (Lino, 10/08/2026) ==========
 * Portage natif du « Dialog · Card details » d'@originui (shadcn/ui + Radix).
 * ⚠️ EN CLAIR. L'original est sombre ; les quatre autres pièces sont claires
 * depuis le 05/08, et une fenêtre sombre au milieu du carrousel se lirait
 * comme une erreur d'assemblage, pas comme un parti pris.
 * Elle reprend le vocabulaire du pack : coque `--cs-bg-2` à 8 px, intérieur
 * blanc, filets d'un pixel, ombre longue et basse. Aucune lueur.
 * ⚠️ AUCUN champ réel — que des <span>. C'est une illustration, et une vraie
 * saisie de carte bancaire sur une page vitrine n'aurait rien à y faire. */
.cs-paie { border-radius: 20px; padding: 8px; background: var(--cs-bg-2);
  border: 1px solid var(--cs-line);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); }
.cs-paie-in { position: relative; background: #fff; border-radius: 14px;
  padding: 1.35rem 1.35rem 1.25rem; }

/* la croix : elle dit « fenêtre », elle ne ferme rien */
.cs-paie-x { position: absolute; top: .7rem; right: .7rem;
  width: 1.55rem; height: 1.55rem; display: flex; align-items: center;
  justify-content: center; border-radius: 8px; color: var(--cs-muted);
  opacity: .6; }
.cs-paie-x svg { width: 14px; height: 14px; }

.cs-paie-ico { display: flex; align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  border: 1px solid var(--cs-line-2); color: var(--cs-ink-2); }
.cs-paie-ico svg { width: 16px; height: 16px; }

.cs-paie h4 { margin: .8rem 0 0; font-size: 1.05rem; font-weight: 600;
  letter-spacing: -.015em; }
.cs-paie-sub { margin: .3rem 0 1.15rem; font-size: .78rem; color: var(--cs-muted); }

.cs-paie-l { display: block; margin: 0 0 .35rem; font-size: .74rem;
  font-weight: 500; color: var(--cs-ink); }
.cs-paie-champ { position: relative; display: block; padding: .55rem .75rem;
  margin: 0 0 .8rem; border: 1px solid var(--cs-line-2); border-radius: 9px;
  background: #fff; font-size: .8rem; color: var(--cs-ink);
  min-height: 2.3rem; letter-spacing: .01em; }

/* la marque de la carte, à droite du numéro : deux disques qui se chevauchent,
   assez pour être lus comme un logo sans en imiter aucun */
.cs-paie-marque { position: absolute; top: 50%; right: .7rem;
  transform: translateY(-50%); width: 20px; height: 13px; border-radius: 3px;
  background:
    radial-gradient(circle at 34% 50%, #e9a13b 0 5.5px, transparent 5.6px),
    radial-gradient(circle at 66% 50%, #d0563f 0 5.5px, transparent 5.6px),
    #f4f4f1; }

/* expiration et CVC sur la même ligne, comme dans l'original */
.cs-paie-duo { display: flex; gap: .8rem; }
.cs-paie-duo > span { flex: 1 1 0; min-width: 0; }

.cs-paie-case { display: flex; align-items: center; gap: .5rem;
  margin: .1rem 0 1.05rem; font-size: .75rem; color: var(--cs-muted); }
.cs-paie-case i { flex: none; display: flex; align-items: center;
  justify-content: center; width: 15px; height: 15px; border-radius: 4px;
  background: var(--cs-accent); color: #fff; }
.cs-paie-case svg { width: 9px; height: 9px; }

.cs-paie-btn { display: block; padding: .62rem 1rem; border-radius: 9px;
  background: var(--cs-accent); color: #fff; text-align: center;
  font-size: .82rem; font-weight: 600; }

/* ===== Encart vidéo — 6e pièce du pack (Lino, 10/08/2026) =================
 * La seule pièce qui ne soit pas une maquette : elle montre un CLIENT, pas
 * l'espace d'administration. D'où l'absence de coque à 8 px et d'intérieur
 * blanc — elle emprunte la grammaire des tuiles du hub (image pleine, rayon,
 * ombre longue) et non celle des fenêtres du pack.
 * ⚠️ RIEN PAR-DESSUS : pas de titre, pas de voile, pas de pastille. Le module
 * a déjà six blocs de texte ; un septième au milieu des maquettes ferait un
 * mur. On regarde, on ne lit pas.
 * ⚠️ La vidéo est en POSITION ABSOLUE et non en `height: 100%` : l'encart est
 * étiré par la grille (`align-self: stretch`), sa hauteur n'est donc pas
 * définie au moment où l'enfant la réclamerait, et un pourcentage y retombe
 * sur `auto` — la vidéo reprenait sa hauteur naturelle et débordait. */
.cs-video { position: relative; overflow: hidden; border-radius: 20px;
  background: var(--cs-bg-2); border: 1px solid var(--cs-line);
  min-height: clamp(240px, 22vw, 320px);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); }
/* ⚠️ `object-position` à 42 % et non au centre : la source est en 16:9, le
   cadre est nettement plus large que haut, et un recadrage centré coupait le
   visage du boulanger — il est dans le tiers supérieur du plan. */
.cs-video-el { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 50%; display: block; }

/* ===== Carte d'avis — 7e pièce du pack (Lino, 10/08/2026) =================
 * Portage natif de « Card Testimonial » de @youcefbnm (21st.dev). Valeurs
 * relevées sur le bundle d'aperçu : carte 350 × 450, rayon 14, filet d'un
 * pixel, écarts de 24 px, étoiles de 16, citation 18/28 centrée, avatar 40.
 * Elle reprend la coque du pack (8 px de `--cs-bg-2`, intérieur blanc à 14) :
 * dans cette colonne elle fait face à la fenêtre de paiement, les deux doivent
 * se lire comme deux fenêtres du même espace. */
/* ⚠️ `display: flex` sur la coque et `flex: 1` sur l'intérieur blanc, à TOUTES
   les tailles. La carte est étirée dans les deux dispositions — par la rangée
   de la grille sur ordinateur, par la piste du carrousel sur mobile (toutes
   les cartes y prennent la hauteur de la maquette d'admin). Sans ça, seule la
   coque grise s'allonge et la boîte blanche flotte en haut.
   ⚠️ Les quatre pièces plus anciennes (connexion, visites, réglage, paiement)
   ont ce défaut sur MOBILE depuis leur création — il n'est corrigé ici que
   pour les avis. Le régler pour les autres est une ligne de plus, mais c'est
   un changement visible sur des maquettes déjà validées : à demander. */
.cs-avis { border-radius: 20px; padding: 8px; background: var(--cs-bg-2);
  border: 1px solid var(--cs-line); display: flex;
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); }
.cs-avis > .cs-avis-in { flex: 1; }
/* ⚠️ HAUTEUR IMPOSÉE ET CONTENU CENTRÉ, comme dans l'original (350 × 450,
   `justify-center`) : c'est une carte, pas un bloc qui épouse son texte. Deux
   raisons de la garder ici. Elle fait face à la fenêtre de paiement, et à
   296 px contre 519 elle avait l'air d'être tombée en haut de la colonne
   (constaté à 1440 px). Et un avis plus court ou plus long ne doit pas faire
   respirer la page différemment — la note du bas reste à la même place. */
.cs-avis-in { background: #fff; border-radius: 14px;
  min-height: 400px; padding: 1.7rem 1.35rem 1.35rem;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 1.15rem; text-align: center; }

/* La note : cinq étoiles vides, et la MÊME rangée en plein par-dessus, coupée
   à 90 % — soit 4,5 sur 5. C'est ce qui donne la demi-étoile sans dessiner un
   second glyphe, et changer la note revient à changer un pourcentage.
   ⚠️ `flex: none` sur les <svg> : sans lui, les cinq étoiles de la rangée
   pleine se compriment pour tenir dans les 90 % au lieu d'être coupées, et on
   obtient cinq étoiles étroites au lieu de quatre et demie. */
.cs-avis-note { position: relative; display: inline-flex; line-height: 0; }
.cs-avis-vide, .cs-avis-plein { display: flex; }
.cs-avis-vide  { color: var(--cs-line-2); }
.cs-avis-plein { position: absolute; top: 0; left: 0; width: 90%;
  overflow: hidden; color: var(--cs-ink); }
.cs-avis-note svg { flex: none; width: 16px; height: 16px; fill: currentColor; }

.cs-avis-cite { margin: 0; width: 88%; font-size: 1.02rem; line-height: 1.55;
  color: var(--cs-ink); }

.cs-avis-qui { display: flex; align-items: center; gap: .9rem; }
/* Deux initiales sur un disque — pas de photo. Voir la note du HTML : la démo
   d'origine hotlinke le portrait Unsplash d'une personne réelle. */
.cs-avis-ava { flex: none; display: flex; align-items: center;
  justify-content: center; width: 40px; height: 40px; border-radius: 50%;
  font-size: .74rem; font-weight: 600; font-style: normal; letter-spacing: .04em;
  color: #fff;
  background: linear-gradient(150deg, #4560e0, #2f4bd8 55%, #1e34a8); }
.cs-avis-id { text-align: left; }
.cs-avis-id b { display: block; font-size: 1.02rem; font-weight: 600;
  letter-spacing: -.015em; color: var(--cs-ink); }
.cs-avis-id em { display: block; margin-top: .1rem; font-style: normal;
  font-size: .76rem; color: var(--cs-muted); }

.cs-avis-n { margin: .1rem 0 0; font-size: .72rem; color: var(--cs-muted); }


/* ===== MODULE 2 — texte à gauche, encart CARRÉ à droite (Lino, 10/08/2026) ==
 * Le téléphone qui occupait la moitié droite est parti en bas du hub ; un
 * encart vidéo au format 1:1 le remplace, à sa demande. La disposition, elle,
 * ne change pas : deux colonnes au-delà de 900 px, texte à GAUCHE et image à
 * DROITE — mêmes emplacements que les en-têtes de /sport et /realestate.
 * Sous 900 px elles s'empilent, texte puis encart.
 * Le CSS du téléphone n'est plus ici : il vit dans `phone.css`, autonome. */
.cs-vitrine-in { display: block; }
.cs-vitrine-copy { min-width: 0; }
.cs-vitrine .cs-h2 { max-width: 22ch; }
.cs-vitrine .cs-p { max-width: 62ch; }

/* ⚠️ `aspect-ratio: 1` ET RIEN D'AUTRE POUR LA HAUTEUR. C'est le format
   demandé, et l'exprimer ainsi laisse la largeur commander : l'encart reste
   carré à toutes les tailles sans qu'on ait à recalculer une hauteur par
   media query. Ne pas lui donner de `height`, les deux se contrediraient.
   Il reprend la grammaire de l'encart du pack de maquettes — coque discrète,
   filet d'un pixel, ombre longue et basse, aucune lueur. */
.cs-carre { position: relative; overflow: hidden; border-radius: 20px;
  aspect-ratio: 1; width: 100%;
  margin: clamp(28px, 5vh, 48px) auto 0;
  background: var(--cs-bg-2); border: 1px solid var(--cs-line);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); }
/* La source est en 16:9 et le cadre est carré : `cover` rogne 44 % de la
   largeur. Le découpage a déjà été fait à l'encodage, décalé vers la gauche
   pour garder la commerçante — voir la note du HTML. `object-position` reste
   donc au centre : le recadrage est dans le fichier, pas dans le CSS. */
.cs-carre-el { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; }

@media (min-width: 900px) {
  /* Colonnes dimensionnées sur leur contenu et couple CENTRÉ : sinon le vide
     retombe au milieu de la page (même piège que sur /realestate). */
  .cs-vitrine-in { display: flex; align-items: center; justify-content: center;
    gap: clamp(36px, 5vw, 84px); }
  /* `flex: 1 1 40ch` et non `0 1` : le carré est large, la colonne de texte
     doit pouvoir se resserrer pour lui faire place au lieu de pousser le
     couple hors du conteneur. `min-width: 0` autorise ce rétrécissement. */
  .cs-vitrine-copy { flex: 1 1 40ch; min-width: 0; }
  /* ⚠️ LA HAUTEUR EST CELLE QU'AVAIT LE TÉLÉPHONE, ET C'EST LA CONSIGNE
     (Lino, 10/08/2026) : `min(68svh, 620px)`, la valeur exacte de `--ph-h`
     dans phone.css au-delà de 900 px. Comme le bloc est carré, cette valeur
     est écrite sur la LARGEUR et `aspect-ratio: 1` en déduit la hauteur —
     l'inverse marcherait aussi, mais poser la largeur laisse le flex faire
     son travail sans avoir à arbitrer entre deux dimensions imposées. */
  .cs-carre { flex: none; margin: 0; width: min(68svh, 620px); }
}
/* la vidéo occupe déjà tout l'écran en fin de course : le bas de section n'a
   pas besoin du grand rembourrage commun */
.cs-vitrine { padding-bottom: clamp(30px, 5vh, 56px); }

/* ⚠️ Le correctif mobile du 05/08 (`height: 76svh` sur la scène) a été RETIRÉ
   le 06/08 : il servait à resserrer une scène de 100 svh, mais la scène épouse
   désormais la hauteur du cadre partout. Le garder rallongeait à nouveau la
   scène de 500 px sur téléphone — exactement le vide qu'on venait d'enlever.
   Ne pas lui redonner de hauteur, ni ici ni ailleurs. */

/* ===== Carte de connexion — d'après « login-3 » de @ephraimduncan =========
 * Troisième pièce de la démonstration du module « Votre site, vous le
 * pilotez » : la maquette montre l'admin, le widget montre ce qu'on y
 * regarde, celle-ci montre par où on entre.
 *
 * ⚠️ Le « Single sign-on (SSO) » de l'original a été RETIRÉ : ça n'existe pas
 * chez une école de surf ou un restaurant. Ne pas le remettre pour coller au
 * composant — la maquette doit décrire l'admin DU CLIENT, pas un SaaS.
 *
 * Le lien de connexion par e-mail (« magic link ») est gardé, lui, et c'est un
 * argument : le client n'a aucun mot de passe à retenir. */
.cs-login { border-radius: 20px; padding: 8px; background: var(--cs-bg-2);
  border: 1px solid var(--cs-line);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); text-align: center; }
.cs-login-in { background: #fff; border-radius: 14px;
  padding: 1.5rem 1.35rem 1.25rem; }
.cs-login-mark { width: 30px; height: 30px; margin: 0 auto .9rem; border-radius: 9px;
  background: linear-gradient(140deg, var(--cs-accent), #7d8cf8); }
.cs-login h4 { margin: 0; font-size: 1.05rem; font-weight: 600; letter-spacing: -.015em; }
.cs-login-sub { margin: .3rem 0 1.1rem; font-size: .78rem; color: var(--cs-muted); }
.cs-login-sub b { color: var(--cs-ink); font-weight: 600; }
.cs-login-champ { display: block; text-align: left; padding: .58rem .75rem;
  border: 1px solid var(--cs-line-2); border-radius: 9px; font-size: .8rem;
  color: var(--cs-ink); background: #fff; min-height: 2.35rem; }
.cs-login-champ span { color: var(--cs-muted); }
/* le curseur de la saisie simulée — voir creation-site.js */
.cs-login-caret { display: inline-block; width: 1px; height: .95em;
  translate: 0 .12em; background: var(--cs-ink); margin-left: 1px;
  animation: cs-caret 1s steps(1) infinite; }
@keyframes cs-caret { 0%,49% { opacity: 1 } 50%,100% { opacity: 0 } }
.cs-login-btn { display: block; margin-top: .55rem; padding: .62rem;
  border-radius: 9px; background: var(--cs-ink); color: #fff;
  font-size: .82rem; font-weight: 600; }
.cs-login-alt { margin: .7rem 0 0; font-size: .76rem; color: var(--cs-ink-2); }
.cs-login-sep { display: flex; align-items: center; gap: .6rem; margin: 1rem 0 .8rem;
  color: var(--cs-muted); font-size: .66rem; letter-spacing: .12em; }
.cs-login-sep::before, .cs-login-sep::after { content: ""; flex: 1;
  border-top: 1px solid var(--cs-line); }
.cs-login-note { margin: 0; font-size: .68rem; color: var(--cs-muted); line-height: 1.45; }

/* ===== Les quatre pièces de la démonstration =============================
 * ORDINATEUR : une grille — la maquette d'admin à gauche sur toute la hauteur,
 * les trois petites cartes empilées à droite.
 * MOBILE : un carrousel horizontal (Lino, 06/08). Quatre maquettes empilées
 * faisaient une colonne interminable sur téléphone.
 *
 * ⚠️ LE `scroll-snap` ICI N'EST PAS CELUI QUI EST INTERDIT. La règle du site
 * (« ne jamais réintroduire de scroll-snap ») vise la cale VERTICALE qui était
 * posée dans le hero : son ancre bougeait quand la barre d'outils d'Instagram
 * coulissait, et le navigateur ré-alignait la page en boucle. Ici l'axe est
 * HORIZONTAL et le défilement est enfermé dans ce conteneur : il ne touche pas
 * au défilement vertical de la page, un balayage vers le bas passe au travers.
 * ⚠️ Le collage n'est activé qu'APRÈS la première interaction (`is-manuel`) :
 * sinon il se bat avec la dérive automatique et la ramène en arrière. */
/* ⚠️ `align-self: stretch` + `width: 100%` + `box-sizing` NE SONT PAS
   DÉCORATIFS. `.cs-admin .cs-wrap` est un conteneur flex en colonne avec
   `align-items: center` : un enfant y est dimensionné sur SON CONTENU. Sans
   ces trois lignes, la piste faisait 666 px de large sur un écran de 390 —
   elle débordait de la page au lieu de défiler à l'intérieur d'elle-même, et
   la dérive ne pouvait pas démarrer (constaté le 06/08). */
.cs-vitrines { display: grid; gap: clamp(14px, 2vw, 20px);
  align-self: stretch; width: 100%; box-sizing: border-box; min-width: 0; }
/* ⚠️ LES FLÈCHES N'EXISTENT QUE SUR MOBILE, et ce masquage est leur état PAR
   DÉFAUT — pas une exception dans une media query « ordinateur ». Au-delà de
   979 px les pièces sont une grille : il n'y a rien à faire défiler, et deux
   boutons flottaient au milieu de la maquette. C'est la règle mobile qui les
   rallume, jamais l'inverse. */
.cs-fleche { display: none; }
/* ⚠️ SUR ORDINATEUR, LES SEPT PIÈCES SONT PLACÉES À LA MAIN — plus une seule
   n'est laissée au placement automatique. Tant qu'il n'y avait qu'un élément
   positionné (la maquette d'admin), l'automatique suffisait ; avec l'encart
   vidéo et la carte d'avis, deux éléments explicites encadrent des éléments
   automatiques, et l'algorithme repart de la première ligne libre — les pièces
   de droite remontaient dans les trous. Sept déclarations valent mieux qu'un
   ordre implicite qu'un ajout futur casserait en silence.

   Colonne 1 : l'écran d'admin (rangées 1-2), l'encart vidéo (3), le paiement (4).
   Colonne 2 : connexion (1), visites (2), réglage (3), avis (4). */
@media (min-width: 980px) {
  /* ⚠️ TROIS COLONNES DEPUIS LE 10/08/2026, plus deux. La rangée du bas porte
     désormais TROIS pièces (paiement, puis les deux avis) : avec deux colonnes
     il n'y avait pas de ligne de grille où poser celle du milieu, et deux
     éléments ne peuvent pas partager une cellule. Les deux premières colonnes
     se recollent (`span 2`) pour les pièces larges — la maquette d'admin et
     l'encart vidéo —, si bien que la largeur totale du pack n'a pas bougé. */
  .cs-vitrines { grid-template-columns: minmax(340px, 1fr) 330px 330px;
    align-items: start; }
  .cs-vitrines > .cs-scene   { grid-column: 1 / span 2; grid-row: 1; }
  .cs-vitrines > .cs-login   { grid-column: 3; grid-row: 1; align-self: stretch; }
  .cs-vitrines > .cs-widget  { grid-column: 3; grid-row: 2; }
  .cs-vitrines > .cs-reglage { grid-column: 3; grid-row: 3; }
  /* ⚠️ QUAND UNE COQUE S'ÉTIRE, SON INTÉRIEUR BLANC DOIT SUIVRE. Les pièces du
     pack sont une coque colorée de 8 px et une boîte blanche dedans. Étirer la
     coque seule (la connexion, ici, qui monte de 357 à 533 px pour rejoindre la
     maquette d'admin) laissait 215 px de bande GRISE sous la boîte blanche —
     un trou de plus, pas un de moins. Le contenu se recentre dans la hauteur
     gagnée, et la carte se lit comme une fenêtre plus haute. */
  .cs-vitrines > .cs-login { display: flex; }
  .cs-vitrines > .cs-login > .cs-login-in { flex: 1;
    display: flex; flex-direction: column; justify-content: center; }
  /* ⚠️ L'ORDRE DE CES DEUX RÈGLES COMPTE. La deuxième carte porte les DEUX
     classes (`cs-avis cs-avis--2`) et les deux sélecteurs ont la même
     spécificité : c'est l'ordre d'écriture qui tranche. Inversées, les deux
     avis se retrouvent dans la même cellule, l'un par-dessus l'autre. */
  /* ⚠️ Les deux avis s'étirent sur la hauteur de la fenêtre de paiement : la
     rangée du bas porte trois pièces, et trois hauteurs différentes y font un
     escalier. Elles partent du même bord haut ET finissent au même bord bas. */
  .cs-vitrines > .cs-avis    { grid-column: 3; grid-row: 4; align-self: stretch; }
  .cs-vitrines > .cs-avis--2 { grid-column: 2; grid-row: 4; }
  /* ⚠️ LA LÉGENDE N'EST MASQUÉE QUE SUR ORDINATEUR, et surtout PAS retirée du
     HTML. Côte à côte, la même phrase écrite deux fois sous deux cartes
     jumelles se lit comme un bug ; une seule suffit à légender la paire, et
     c'est celle de droite qui la ferme. Mais sur mobile les cartes défilent
     UNE PAR UNE : celle qui n'aurait pas la phrase se lirait comme un
     témoignage sur le travail de Lino, ce qu'elle n'est pas. Chaque carte
     garde donc sa légende, et le carrousel les montre toutes les deux. */
  .cs-vitrines > .cs-avis--2 .cs-avis-n { display: none; }
  /* ⚠️ L'ENCART VIDÉO REMONTE SOUS LA MAQUETTE ET S'ÉTIRE (Lino, 10/08/2026).
     Il était en rangée 3 seulement, sous une maquette qui s'étalait sur deux
     rangées : il restait 126 px de blanc entre les deux — c'est la zone qu'il
     a hachurée. Il occupe maintenant les rangées 2 et 3, collé à la maquette,
     et `align-self: stretch` lui fait absorber toute la hauteur que les
     visites et le réglage laissent dans la colonne de droite. C'est LUI la
     pièce élastique du pack : les six autres gardent leur hauteur propre. */
  .cs-vitrines > .cs-video { grid-column: 1 / span 2; grid-row: 2 / span 2;
    align-self: stretch; }
  /* ⚠️ La fenêtre de paiement garde sa largeur de FENÊTRE : l'original
     d'@originui est plafonné à 400 px, et étalée sur toute la colonne elle ne
     se lit plus comme une boîte de dialogue mais comme un formulaire de page
     (constaté le 10/08/2026).
     ⚠️ Elle est CALÉE À GAUCHE depuis que les avis lui font face : centrée,
     elle laissait 156 px de vide à sa gauche et se retrouvait décalée par
     rapport à la maquette d'admin et à l'encart vidéo, qui commencent tous
     deux au bord de la colonne. */
  .cs-vitrines > .cs-paie { grid-column: 1; grid-row: 4; justify-self: start;
    width: min(100%, 400px); }
}
@media (max-width: 979px) {
  /* ⚠️ L'enveloppe ne sert QU'À porter les flèches — la piste défile, des
     flèches posées dedans partiraient avec elle. C'est elle qui reprend les
     contraintes de flex-enfant que `.cs-vitrines` portait avant (voir plus
     bas) : `.cs-admin .cs-wrap` est un flex en colonne centré, un enfant s'y
     dimensionne donc sur SON contenu, et la piste débordait au lieu de
     défiler. */
  .cs-piste { position: relative; align-self: stretch; width: 100%;
    box-sizing: border-box; }

  .cs-vitrines {
    display: flex; gap: 14px;
    /* ⚠️ CENTRÉES SUR UNE LIGNE HORIZONTALE (Lino, 10/08/2026). La piste était
       en `stretch` : toutes les fenêtres prenaient la hauteur de la plus haute
       (711 px, imposés par la maquette d'admin) — d'où 520 px de vide sous le
       widget visiteurs et 543 px sous le réglage, mesurés à 375 px. Chaque
       fenêtre épouse maintenant SON module, et `center` les aligne sur l'axe
       de la piste : autant de module au-dessus qu'en dessous de cette ligne.
       ⚠️ C'est ce `center` qui a rendu inutile le `align-self` que l'encart
       vidéo portait pour lui seul. Le remettre en `stretch` ramènerait les
       deux défauts d'un coup. */
    align-items: center;
    overflow-x: auto; overflow-y: hidden;
    /* les marges négatives font sortir la piste des marges de la page : les
       cartes glissent d'un bord à l'autre de l'écran, pas dans une boîte */
    margin-inline: calc(clamp(18px, 5vw, 40px) * -1);
    padding-inline: clamp(18px, 5vw, 40px);
    /* ⚠️ `width: auto` ANNULE le `width: 100%` de la règle de base, et ce
       n'est pas cosmétique : avec une largeur imposée, les marges négatives
       DÉPLACENT la piste sans l'élargir. Elle restait à 338 px dans un écran
       de 375, ses pièces à 300, et il manquait 37 px de largeur utile à chaque
       module — une partie exacte de la bande blanche que Lino a hachurée. */
    width: auto;
    scrollbar-width: none;
  }
  .cs-vitrines::-webkit-scrollbar { display: none; }
  .cs-vitrines.is-manuel { scroll-snap-type: x proximity; }
  /* ⚠️ UNE SEULE LARGEUR POUR TOUS, ET C'EST TOUTE LA LARGEUR UTILE (Lino,
     10/08/2026 : « cette bande blanche obstrue le visionnage des modules »).
     Les pièces faisaient 84 % et la maquette 94 % : le module calé à gauche
     laissait une bande morte à droite, et le voisin mordait à gauche. À 100 %,
     un module occupe l'écran entre ses deux marges — plus de bande, et plus de
     place pour le contenu.
     ⚠️ `min-width: 0` : sans lui un élément flex refuse de descendre sous sa
     largeur de contenu minimale — le tableau de la maquette imposerait la
     sienne et ferait de nouveau déborder la piste. */
  /* ⚠️ `box-sizing: border-box` : plusieurs pièces portent une marge
     intérieure (8 px pour la carte de connexion). En `content-box`, elle
     s'AJOUTE aux 100 % et la pièce dépasse de la largeur utile — les modules
     n'avaient déjà pas tous la même largeur avant ça (300, 302, 318 mesurés). */
  .cs-vitrines > * { flex: 0 0 100%; min-width: 0; box-sizing: border-box;
    scroll-snap-align: center; }

  /* ⚠️ LA MARGE HAUTE DE LA MAQUETTE D'ADMIN EST ANNULÉE ICI. Elle vaut
     48,72 px et sert la GRILLE de l'ordinateur ; dans une piste centrée elle
     décalait le module de 48 px sous l'axe — mesuré : 307 px au-dessus de la
     ligne contre 356 en dessous. Les modules doivent être à cheval sur la
     ligne, autant au-dessus qu'en dessous (demande de Lino). Toute pièce à
     qui l'on ajoute une marge verticale doit la perdre ici aussi. */
  .cs-vitrines > * { margin-block: 0; }

  /* ⚠️ UN SEUL AVIS SUR MOBILE (Lino, 10/08/2026) : celui de Sophie B., qui
     ferme le carrousel. Celui de Karim T. (`--2`) est masqué ICI SEULEMENT —
     sur ordinateur la grille en montre toujours deux. Masqué et non supprimé :
     `display: none` le sort aussi du comptage des flèches, qui lisent les
     enfants visibles. */
  .cs-vitrines > .cs-avis--2 { display: none; }

  /* --- les deux flèches, discrètes (sa demande) ---
     ⚠️ Elles sont sur l'axe de la piste, donc sur la même ligne horizontale
     que les modules. Verre clair et filet fin : la page n'a ni ombre portée ni
     halo, elles ne doivent pas être les premières à en porter.
     ⚠️ Posées PAR-DESSUS les bords des modules, à dessein : les sortir de la
     piste aurait rogné la largeur utile qu'on vient de récupérer. */
  .cs-fleche { position: absolute; z-index: 3; top: 50%;
    transform: translateY(-50%);
    width: 36px; height: 36px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%; border: 1px solid var(--cs-line);
    background: rgba(255, 255, 255, .82);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    color: var(--cs-ink-2); cursor: pointer;
    opacity: .72; transition: opacity .2s, border-color .2s, color .2s; }
  .cs-fleche:hover { opacity: 1; color: var(--cs-ink); border-color: var(--cs-line-2); }
  .cs-fleche:focus-visible { opacity: 1; outline: 2px solid var(--cs-accent);
    outline-offset: 2px; }
  .cs-fleche svg { width: 17px; height: 17px; }
  /* elles mordent sur la marge de la page, pas sur le module */
  .cs-fleche--g { left: -2px; }
  .cs-fleche--d { right: -2px; }
  /* ⚠️ L'ENCART VIDÉO REPREND LA GÉOMÉTRIE DES TUILES DU HUB (Lino, 10/08/2026) :
     même largeur utile, même hauteur `clamp(190px, 30vh, 280px)`, même rayon de
     18 px que `.screen` dans index.html. Les valeurs sont RECOPIÉES et non
     partagées : hero.css n'est pas chargée par cette page. Si les tuiles du hub
     bougent, il faut les reporter ici à la main. */
  /* ⚠️ `align-self: center` A ÉTÉ RETIRÉ : la piste entière est en
     `align-items: center` depuis le 10/08/2026, il faisait doublon. Il ne
     servait qu'à sauver cette pièce du `stretch` général, qui n'existe plus.
     ⚠️ LA HAUTEUR RESTE CELLE DES TUILES DU HUB, et la largeur suit
     maintenant la règle commune (100 %). Mesuré à 375 px : une tuile fait
     345 × 244, soit un rapport de 1,42, et c'est POUR CE RAPPORT que la vidéo
     a été recadrée. À 284 px de large l'encart tombait à 1,15 — presque carré —
     et `cover` mangeait 65 % de l'image : il ne restait qu'une épaule de
     boulangère. À 100 % de la largeur utile, le rapport est tenu. */
  .cs-vitrines > .cs-video {
    height: clamp(190px, 30vh, 280px); border-radius: 18px; padding: 0; }
  .cs-vitrines > .cs-video .cs-video-el { border-radius: 18px; }
}

/* ===== Ce qui rend les maquettes VIVANTES ================================
 * Elles ne doivent pas arriver toutes faites : elles se REMPLISSENT quand
 * elles apparaissent — les entrées du menu, les compteurs, les lignes du
 * tableau, la courbe, les champs du formulaire. C'est ce qui fait la
 * différence entre une capture d'écran et une démonstration.
 *
 * ⚠️ Tout est sous `.js-cs` et derrière `.is-in` (posé par l'observateur de
 * creation-site.js). Sans JS, rien n'est masqué : les maquettes s'affichent
 * complètes, d'un coup. C'est le bon repli.
 * ⚠️ Les retards sont en `nth-child` et pas en JS : une ligne ajoutée au
 * tableau prend sa place dans la cascade sans qu'on touche à quoi que ce soit. */
@keyframes cs-pop { from { opacity: 0; transform: translateY(9px); }
                    to   { opacity: 1; transform: none; } }

.js-cs .cs-scene .cs-nav a,
.js-cs .cs-scene .cs-stat,
.js-cs .cs-scene .cs-table tbody tr,
.js-cs .cs-widget .cs-days span,
.js-cs .cs-login .cs-anim,
.js-cs .cs-avis .cs-anim { opacity: 0; }

.js-cs .cs-scene.is-in .cs-nav a,
.js-cs .cs-scene.is-in .cs-stat,
.js-cs .cs-scene.is-in .cs-table tbody tr,
.js-cs .cs-widget.is-in .cs-days span,
.js-cs .cs-login.is-in .cs-anim,
.js-cs .cs-avis.is-in .cs-anim {
  animation: cs-pop .5s cubic-bezier(.2,.7,.2,1) both; }

/* les cascades : menu, compteurs, lignes du tableau */
.js-cs .cs-scene.is-in .cs-nav a:nth-child(1) { animation-delay: .10s }
.js-cs .cs-scene.is-in .cs-nav a:nth-child(2) { animation-delay: .16s }
.js-cs .cs-scene.is-in .cs-nav a:nth-child(3) { animation-delay: .22s }
.js-cs .cs-scene.is-in .cs-nav a:nth-child(4) { animation-delay: .28s }
.js-cs .cs-scene.is-in .cs-nav a:nth-child(5) { animation-delay: .34s }
.js-cs .cs-scene.is-in .cs-nav a:nth-child(6) { animation-delay: .40s }
.js-cs .cs-scene.is-in .cs-stat:nth-child(1) { animation-delay: .34s }
.js-cs .cs-scene.is-in .cs-stat:nth-child(2) { animation-delay: .46s }
.js-cs .cs-scene.is-in .cs-stat:nth-child(3) { animation-delay: .58s }
.js-cs .cs-scene.is-in .cs-table tbody tr:nth-child(1) { animation-delay: .74s }
.js-cs .cs-scene.is-in .cs-table tbody tr:nth-child(2) { animation-delay: .84s }
.js-cs .cs-scene.is-in .cs-table tbody tr:nth-child(3) { animation-delay: .94s }
.js-cs .cs-scene.is-in .cs-table tbody tr:nth-child(4) { animation-delay: 1.04s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(1) { animation-delay: .55s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(2) { animation-delay: .62s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(3) { animation-delay: .69s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(4) { animation-delay: .76s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(5) { animation-delay: .83s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(6) { animation-delay: .90s }
.js-cs .cs-widget.is-in .cs-days span:nth-child(7) { animation-delay: .97s }
/* ⚠️ PAS de `nth-of-type` ici. Les éléments de la carte ont des balises
   DIFFÉRENTES (div, h4, p, span, span, p) et `nth-of-type` compte par balise :
   la cascade s'effondrait en deux paliers au lieu de six. Le retard est donc
   écrit sur chaque élément dans le HTML (`--ad`). */
.js-cs .cs-login.is-in .cs-anim,
.js-cs .cs-avis.is-in  .cs-anim { animation-delay: var(--ad, 0s); }

@media (prefers-reduced-motion: reduce) {
  .js-cs .cs-scene .cs-nav a, .js-cs .cs-scene .cs-stat,
  .js-cs .cs-scene .cs-table tbody tr, .js-cs .cs-widget .cs-days span,
  .js-cs .cs-login .cs-anim,
  .js-cs .cs-avis .cs-anim { opacity: 1; animation: none; }
  .cs-login-caret { animation: none; }
}

/* ===== Lettres qui roulent — d'après « Text Roll » de @ibelick =============
 * Structure et valeurs reprises du bundle d'aperçu (voir creation-site.js).
 * Deux copies de chaque lettre : l'une part en tournant vers le haut, l'autre
 * arrive du bas 0,2 s plus tard. Entre les deux, la lettre est sur la tranche.
 *
 * ⚠️ `backface-visibility: hidden` est INDISPENSABLE sur les deux copies :
 * sans lui, on voit le dos de la lettre pendant la rotation — elle apparaît
 * en miroir au milieu du mouvement.
 *
 * ⚠️ L'écart par lettre est de 0,035 s, pas les 0,1 s de l'original : notre
 * titre fait 41 caractères contre 17 dans sa démo. Voir la note dans le JS. */
.cs-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ⚠️ UNE BOÎTE PAR MOT. Les lettres étant des `inline-block`, la ligne pouvait
   casser entre deux d'entre elles — et comme les espaces sont insécables,
   c'était la seule coupure possible. `nowrap` enferme le mot ; le vrai espace
   posé entre deux boîtes par creation-site.js redonne au navigateur la seule
   coupure qui a du sens. */
.cs-roll-w { display: inline-block; white-space: nowrap; }
.cs-roll-c { position: relative; display: inline-block;
  perspective: 10000px; transform-style: preserve-3d; }
/* ⚠️ La lettre des deux copies animées vient de `attr(data-c)`, PAS du DOM :
   sinon chaque caractère existait en trois exemplaires et le titre rendu
   devenait « UUUnnneee vvviiitttrrriiinnneee ». C'est ce que Google aurait lu. */
.cs-roll-out, .cs-roll-in { position: absolute; left: 0; top: 0;
  display: inline-block; backface-visibility: hidden; }
.cs-roll-out::before, .cs-roll-in::before { content: attr(data-c); }
.cs-roll-out { transform-origin: 50% 25%; }
.cs-roll-in  { transform-origin: 50% 100%; }
/* la troisième copie, invisible, tient la largeur de la lettre */
.cs-roll-cale { visibility: hidden; }

/* Au repos (JS présent, pas encore révélé) : la lettre « qui part » est en
   place, celle « qui arrive » est couchée. Rien ne bouge tant que le titre
   n'est pas à l'écran. */
.js-cs [data-roll] .cs-roll-out { transform: rotateX(0deg); }
.js-cs [data-roll] .cs-roll-in  { transform: rotateX(90deg); }
.js-cs [data-roll].is-in .cs-roll-out {
  animation: cs-roll-out .5s ease-in both;
  animation-delay: calc(var(--i) * .035s); }
.js-cs [data-roll].is-in .cs-roll-in {
  animation: cs-roll-in .5s ease-in both;
  animation-delay: calc(var(--i) * .035s + .2s); }
@keyframes cs-roll-out { from { transform: rotateX(0deg); } to { transform: rotateX(90deg); } }
@keyframes cs-roll-in  { from { transform: rotateX(90deg); } to { transform: rotateX(0deg); } }

/* --- texte mot à mot --- */
.js-cs [data-mots] .cs-mot { display: inline-block; opacity: 0;
  transform: translateY(10px); }
.js-cs [data-mots].is-in .cs-mot {
  animation: cs-pop .55s cubic-bezier(.2,.7,.2,1) both;
  animation-delay: calc(var(--i) * .038s); }

/* ⚠️ Le voile générique de révélation est NEUTRALISÉ sur ces deux-là : sans
   ça, le bloc entier arrive en fondu PENDANT que ses lettres roulent — deux
   animations sur le même élément, et le roulement ne se voit plus. */
.js-cs [data-reveal][data-roll],
.js-cs [data-reveal][data-mots] { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js-cs [data-roll] .cs-roll-out { transform: none; animation: none; }
  .js-cs [data-roll] .cs-roll-in  { display: none; }
  .js-cs [data-mots] .cs-mot { opacity: 1; transform: none; animation: none; }
}


/* ===== Réglage — d'après « Radio Group · Row with icon » d'@originui =======
 * Quatrième pièce de la démonstration. Trois cartes à icône, une seule
 * retenue, et le choix se DÉPLACE tout seul quand le bloc apparaît (voir
 * creation-site.js) : une capture montre un réglage, celle-ci montre qu'on
 * le change — c'est toute la promesse du module. */
.cs-reglage { border-radius: 20px; padding: 8px; background: var(--cs-bg-2);
  border: 1px solid var(--cs-line);
  box-shadow: 0 20px 44px -26px rgba(20,22,26,.4); }
.cs-reglage-in { background: #fff; border-radius: 14px; padding: 1.1rem 1.1rem 1rem; }
.cs-reglage-t { margin: 0 0 .8rem; font-size: .82rem; font-weight: 600; }
.cs-choix { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
.cs-choix-c { display: flex; flex-direction: column; align-items: center; gap: .4rem;
  padding: .7rem .3rem; border-radius: 11px; text-align: center;
  border: 1px solid var(--cs-line-2); background: #fff;
  font-size: .68rem; font-weight: 600; color: var(--cs-ink-2);
  transition: border-color .35s, background .35s, color .35s; }
.cs-choix-c svg { width: 17px; height: 17px; }
/* ⚠️ La carte retenue est CERNÉE et à peine teintée, pas remplie : c'est la
   même règle que les cartes de prix et les pastilles du hub — sur une page
   minimaliste, un filet d'accent suffit à dire « celle-ci ». */
.cs-choix-c.is-on { border-color: var(--cs-accent); color: var(--cs-accent);
  background: rgba(47,75,216,.05); }
.cs-reglage-n { margin: .8rem 0 0; font-size: .72rem; color: var(--cs-muted); }

/* la cascade d'apparition des trois cartes */
.js-cs .cs-reglage .cs-choix-c { opacity: 0; }
.js-cs .cs-reglage.is-in .cs-choix-c { animation: cs-pop .5s cubic-bezier(.2,.7,.2,1) both; }
.js-cs .cs-reglage.is-in .cs-choix-c:nth-child(1) { animation-delay: .14s }
.js-cs .cs-reglage.is-in .cs-choix-c:nth-child(2) { animation-delay: .24s }
.js-cs .cs-reglage.is-in .cs-choix-c:nth-child(3) { animation-delay: .34s }
@media (prefers-reduced-motion: reduce) {
  .js-cs .cs-reglage .cs-choix-c { opacity: 1; animation: none; }
}
