/* Polices AUTO-HEBERGEES. Sans @font-face, "Playfair Display" retombait sur
   Georgia chez qui ne l'a pas installee : la page de vente ne se composait pas
   pareil d'une machine a l'autre, et le H1 serif — qui porte tout le hero —
   changeait de dessin. Les fichiers sont ceux du design-system de la marque,
   copies par le build ; l'italique est un FICHIER, pas une oblique simulee.
   Le corps reste en sans-serif systeme : la loi 2 du releve demande une
   sans-serif de corps, pas une police particuliere, et ne rien charger pour
   le corps est un chargement de moins avant le premier mot lu. */
@font-face{font-family:"Playfair Display";src:url("fonts/PlayfairDisplay.ttf") format("truetype");
  font-weight:400 900;font-style:normal;font-display:swap}
@font-face{font-family:"Playfair Display";src:url("fonts/PlayfairDisplay-Italic.ttf") format("truetype");
  font-weight:400 900;font-style:italic;font-display:swap}
@font-face{font-family:"Caveat";src:url("fonts/Caveat.ttf") format("truetype");
  font-weight:400 700;font-style:normal;font-display:swap}

/* Site Anchored V3 — tokens et lois du releve Mehdi (references/RELEVE-MEHDI-PRELANDER.md).
   Adaptation actee au prelander v2.3 : CTA gold #F2BC4B texte #1B1420,
   mots-cles du H1 en #E9B44C italique, terracotta retrograde en accent secondaire.

   PLUS AUCUN NOIR (13/08). Le site portait une « nuit » #0A0912 — 0,3 % de
   luminance, une couleur qui n'existe nulle part dans la marque : ni dans
   tokens.json, ni sur une couverture, ni sur une page de livre. Un noir de
   navigateur pose sous des illustrations aquarellees, et la marque perdait son
   grain a chaque bande sombre.
   Les surfaces sombres du site sont desormais LE PRUNE DE LA MARQUE — le meme
   #4A3651 que le panneau des couvertures et que l'encadre des versets dans les
   livres, verbatim depuis brands/anchored/design-system/tokens.json. Il ne s'en
   derive pas de nuance plus sombre : les profondeurs se font au filet et a
   l'ombre, jamais en assombrissant un token (shoot_site.py refuse au build
   toute couleur de fond sous 10 % de luminance qui ne soit pas un token). */
:root{
  /* --- verbatim tokens.json (palette de la marque) --- */
  --prune:#4A3651; --creme:#F8F5EE; --ink:#2E2A30; --paper:#FDFCF8;
  --sage:#8A9A7B; --terracotta:#C57B57;
  /* --- derivees : des melanges des tokens ci-dessus, aucune teinte nouvelle */
  --creme-2:color-mix(in srgb,var(--terracotta) 7%,var(--creme));   /* = paper-warm */
  --ink-soft:color-mix(in srgb,var(--ink) 72%,var(--creme));
  --sur-prune:color-mix(in srgb,var(--creme) 84%,transparent);      /* corps sur prune */
  /* 72 % et pas 62 : sous le prune (plus clair que l'ancienne nuit), le pied de
     page tombait a 4,3:1 — sous le seuil AA pour du 13,5 px, et c'est la que
     vivent les mentions legales. */
  --sur-prune-soft:color-mix(in srgb,var(--creme) 72%,transparent); /* mentions */
  /* --- accent de conversion (adaptation actee v2.3, hors palette print) --- */
  --gold:#F2BC4B; --gold-soft:#E9B44C;
  /* l'or DES LIVRES (tokens.css) : plus sourd que l'or de conversion, ce qui
     est exactement ce qu'on veut d'une barre d'annonce — elle doit se
     distinguer de la nav sans disputer le clic au bouton. */
  --gold-brand:#C9A24B;
  /* --plum : ancien nom du prune, garde pour les regles qui l'utilisent */
  --plum:var(--prune);
  --serif:"Playfair Display",Georgia,serif;
  --sans:"Nunito Sans",-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --wrap:1080px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{font-family:var(--sans);color:var(--ink);background:var(--creme);
     font-size:17px;line-height:1.62;-webkit-font-smoothing:antialiased}
/* `height:auto` n'est pas cosmetique, c'est LA correction du gate. Les images
   portent width/height en attributs (bon pour le CLS) ; sans `height:auto`, la
   hauteur attribuee — 1024 px — reste une hauteur CSS pendant que `max-width`
   ramene la largeur a celle de la colonne. Le navigateur remplit alors la boite
   en `object-fit: fill` : un carre de 1024 s'affichait 329 x 1024, soit 68 %
   d'ecrasement. Les onze images du site etaient dans ce cas. */
img{max-width:100%;height:auto;display:block}
a{color:inherit}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 22px}

/* Loi 2 du releve : corps en SANS-SERIF, titres en serif avec mots-cles
   colores et italiques a l'interieur. Jamais de serif en corps sur une LP. */
h1,h2,h3{font-family:var(--serif);font-weight:700;line-height:1.16;margin:0 0 .5em}
h1{font-size:clamp(31px,5.1vw,52px)}
/* UN TITRE QUI SE REPARTIT SUR SES LIGNES, ET NON SUR UN SEUL TITRE DU SITE.
   Le navigateur coupe au dernier mot qui rentre : sur le titre de l'accueil,
   cela donnait « A loud evening isn't weak » puis « faith — » seul sur sa
   ligne. Un mot orphelin sous une ligne pleine se lit comme une coquille, et il
   tombait sur le mot qui porte l'antithese. `balance` demande au moteur
   d'egaliser les lignes plutot que de remplir la premiere.
   CLASSE ET NON REGLE GLOBALE, et c'est la raison qui compte : `h1` s'applique
   aux vingt pages, et une repartition differente ferait bouger le titre de
   chacune — y compris ceux qui tombent deja juste. On ne redessine pas dix-neuf
   pages pour en reparer une. La classe se pose la ou l'orphelin a ete mesure.
   NON SUPPORTE = AUCUN EFFET, jamais une casse : un navigateur qui ignore
   `text-wrap` coupe comme avant. C'est une amelioration progressive, pas une
   dependance. */
.balance{text-wrap:balance}
h2{font-size:clamp(25px,3.6vw,38px)}
h3{font-size:clamp(19px,2.2vw,23px)}
em.key{font-style:italic;color:var(--gold-soft);font-weight:700}
.dark em.key{color:var(--gold-soft)}
/* LES DEUX SURFACES CLAIRES, pas une seule. La regle ne connaissait que
   `.light` : sur `.light-2`, le mot-cle retombait sur l'or de base — 1,6:1 sur
   le creme chaud, c'est-a-dire illisible, la ou AA-large demande 3:1. Le defaut
   n'existait pour personne tant que `em.key` ne vivait que sur `.light` ou sur
   le prune ; les advertorials ont pose la promesse de remboursement sur
   `.light-2`, et le mot qui porte la phrase — « Then decide. » — a disparu.
   Aucune porte ne pouvait le voir : shoot_site.py ne juge que les fonds sombres
   et le blanc pur. Le precedent est juste au-dessous, sur `.pill`. */
.light em.key,.light-2 em.key{color:var(--plum)}
/* surlignage « selection de texte » sur 2-3 mots des H2 clairs */
.hl{background:linear-gradient(transparent 12%,rgba(242,188,75,.42) 12%,
    rgba(242,188,75,.42) 88%,transparent 88%);padding:0 5px;border-radius:3px}
p{margin:0 0 1.05em}
strong{font-weight:800;color:var(--ink)}
.dark strong{color:var(--creme)}

/* --- barre d'annonce + nav ---------------------------------------------- */
/* Les deux etaient prune : deux bandes de la meme couleur empilees, que l'oeil
   lit comme un seul bandeau epais — la loi 4 du releve (UNE barre au-dessus du
   hero) etait respectee dans le code et perdue a l'ecran. Un filet n'y suffit
   pas : deux aplats identiques restent deux aplats identiques.
   La barre prend donc l'or de la marque sur texte encre, et il ne reste plus
   qu'UNE bande prune pleine : la nav. */
.topbar{background:var(--gold-brand);color:var(--ink);text-align:center;
        font-size:13.5px;letter-spacing:.03em;padding:9px 16px;font-weight:700}
.nav{background:var(--prune);color:var(--creme);display:flex;align-items:center;
     justify-content:space-between;gap:18px;padding:14px 22px;flex-wrap:wrap}
/* LA MARQUE = ANCRE + MOT, sur une seule ligne de base. `inline-flex` et non
   deux elements poses cote a cote : alignes sur la ligne de texte, le dessin
   depasserait par le bas et la barre grandirait sans raison.
   `width:auto` PARTOUT, et c'est une contrainte de porte autant que de gout :
   la hauteur est ce qu'une barre impose, la largeur en decoule. Une largeur
   ecrite a la main serait arrondie au pixel, et la porte des ratios — qui
   compare le cadre RENDU au ratio naturel du fichier a 2 % pres — verrait une
   image legerement ecrasee. En la laissant au navigateur, le rapport est exact
   par construction.
   La version posee est celle dessinee pour fond sombre (6,7:1 sur le prune) ;
   logo-mark, sombre, y donnerait 2,2:1. Raisonnement complet dans _nav.html. */
.nav__brand{font-family:var(--serif);font-size:23px;font-weight:700;
            text-decoration:none;letter-spacing:.01em;
            display:inline-flex;align-items:center;gap:11px}
.nav__mark{width:auto;height:32px;display:block;flex:none}
/* `flex-wrap` + `nowrap` sur chaque entree : a 390 px, le menu passait a la
   ligne AU MILIEU des intitules — « The / Books », « Get in / Touch ». Un menu
   se replie entre ses entrees, jamais dans un mot. */
.nav__links{display:flex;align-items:center;flex-wrap:wrap;gap:8px 18px;font-size:14.5px}
.nav__links>a,.nav__menu>summary{white-space:nowrap}
.nav__links a{text-decoration:none;opacity:.86}
.nav__links a:hover{opacity:1;text-decoration:underline}

/* --- le menu « The Books » ------------------------------------------------ */
/* `<details>` et pas un survol : un deroulant au survol n'existe pas sur un
   telephone, et 90 % du trafic est mobile. Celui-ci s'ouvre au clic comme au
   clavier, sans JavaScript — et si le CSS ne charge pas, il s'ouvre quand meme,
   en poussant le contenu vers le bas. Une nav qui degrade en liste est une nav
   qui marche. */
.nav__menu{position:relative}
.nav__menu>summary{list-style:none;cursor:pointer;opacity:.86;
                   padding:4px 0;user-select:none}
.nav__menu>summary::-webkit-details-marker{display:none}
.nav__menu>summary::after{content:"⌄";margin-left:.35em;font-size:1.15em;
                          line-height:0;vertical-align:.18em}
.nav__menu[open]>summary{opacity:1}
.nav__menu>summary:focus-visible{outline:2px solid var(--gold);outline-offset:3px;
                                 border-radius:4px}
/* Le panneau se pose SUR la page au lieu de la pousser : une nav qui grandit de
   90 px au clic fait sauter le hero, et l'oeil perd la ligne qu'il lisait. */
.nav__panel{position:absolute;top:calc(100% + 12px);left:-12px;z-index:40;
            min-width:214px;padding:8px;border-radius:14px;background:var(--prune);
            border:1px solid color-mix(in srgb,var(--creme) 20%,transparent);
            box-shadow:0 20px 46px rgba(30,20,40,.38)}
.nav__panel a{display:block;padding:10px 12px;border-radius:9px;opacity:.92;
              white-space:nowrap}
.nav__panel a:hover{opacity:1;text-decoration:none;
                    background:color-mix(in srgb,var(--creme) 13%,transparent)}

/* --- barre collante de la landing (bloc 0) ------------------------------- */
/* La promesse et le bouton restent a l'ecran sur toute la page. Sur une landing
   de cette longueur — cinq raisons, deux formulaires, une FAQ — une lectrice
   convaincue au milieu du parcours n'avait plus rien a toucher avant six ecrans
   plus bas. Le CTA est une ANCRE : aucune sortie du site avant le catalogue. */
.lpbar{position:sticky;top:0;z-index:45;background:var(--prune);color:var(--creme);
       box-shadow:0 6px 18px rgba(30,20,40,.18)}
.lpbar__in{max-width:var(--wrap);margin:0 auto;padding:6px 18px;display:flex;
           align-items:center;gap:16px}
.lpbar__brand{font-family:var(--serif);font-size:21px;font-weight:700;
              display:inline-flex;align-items:center;gap:9px}
.lpbar__mark{width:auto;height:28px;display:block;flex:none}
.lpbar__say{font-size:13.5px;color:var(--sur-prune);letter-spacing:.02em;
            margin-right:auto}
/* 48 px de haut : c'est la cible tactile minimale, et ce bouton est le premier
   CTA de la page la plus mobile du funnel. */
.lpbar__cta{margin-left:auto;display:inline-flex;align-items:center;min-height:48px;
            padding:0 20px;border-radius:999px;background:var(--gold);color:var(--ink);
            font-weight:800;font-size:14.5px;text-decoration:none;white-space:nowrap}
.lpbar__cta:hover{filter:brightness(1.05)}

/* --- prix de lancement : une PHRASE, plus un chiffre barre ---------------- */
/* Le 49 $ etait affiche barre a cote du 35 $. Il n'a jamais ete facture : c'est
   un prix d'ancrage fictif, la premiere ligne de l'audit. Le chiffre reste,
   mais il redevient ce qu'il est — une intention future, ecrite en toutes
   lettres et sans le style qui la faisait passer pour un passe. */
.launch-note{font-size:14.5px;color:var(--ink-soft);margin:-.5em 0 1.05em;
             letter-spacing:.01em}
.dark .launch-note{color:var(--sur-prune)}

/* --- le mecanisme du prix d'accueil -------------------------------------
   « $9 with the welcome code » etait ecrit seul : la mention nommait un code
   sans dire d'ou il vient, et une visiteuse froide y lisait un prix qu'elle ne
   pouvait pas atteindre. Le bloc porte donc les DEUX prix sur une ligne forte,
   puis le mecanisme en une phrase, puis le chemin — un lien discret vers la
   landing, qui ne doit pas disputer le clic au bouton d'achat juste dessous. */
.welcome-note{font-size:15.5px;line-height:1.55;color:var(--ink-soft);
              margin:-.35em 0 .4em;
              border-left:3px solid color-mix(in srgb,var(--sage) 55%,transparent);
              padding-left:14px}
.welcome-note strong{font-size:16.5px;color:var(--ink)}
.welcome-note__go{margin:0 0 .6em;font-size:15px;font-weight:700}
.welcome-note__go a{color:var(--plum);text-underline-offset:4px}
/* Sur une carte produit, la meme phrase n'a pas de filet : la carte en est
   deja un, et deux cadres emboites se lisent comme une erreur. */
.card__note{margin:0 0 .7em;font-size:14px;line-height:1.5;color:var(--ink-soft)}

/* --- sections ----------------------------------------------------------- */
/* Loi 1 : le sombre est une PONCTUATION — texte et CTA uniquement, jamais
   d'image. Toutes les images vivent sur les sections claires. Et une
   ponctuation ne se repete pas quatre fois : DEUX sections sombres par page au
   maximum (le hero et le bloc d'offre sur le prelander ; la mission sur la
   home). Le prelander en avait quatre — la page se lisait en bandes noires, et
   chacune retirait a la suivante le peu d'effet qui lui restait.
   Sur prune, le texte est CREME ou OR, jamais blanc pur : le blanc pur vibre
   sur un fond colore et ne se trouve nulle part dans la marque. */
.dark{background:var(--prune);color:var(--creme)}
.dark p{color:var(--sur-prune)}
.dark h1,.dark h2{color:var(--creme)}
.light{background:var(--creme)}
.light-2{background:var(--creme-2)}
.sec{padding:clamp(48px,7vw,86px) 0}
/* Une bande de service — bandeau de reassurance, CTA d'ancre, mention legale.
   Elle porte une ligne, pas une idee : lui donner le rembourrage d'une section
   en ferait un chapitre. */
.sec--thin{padding:clamp(24px,3.2vw,38px) 0}
.center{text-align:center}
.lede{font-size:clamp(17px,2vw,19.5px)}
.narrow{max-width:730px;margin-left:auto;margin-right:auto}

/* pill uptitle : gris clair sur sombre, sauge sur clair */
.pill{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.13em;
      text-transform:uppercase;padding:7px 15px;border-radius:999px;margin-bottom:16px}
.dark .pill{background:color-mix(in srgb,var(--creme) 14%,transparent);color:var(--sur-prune)}
.light .pill,.light-2 .pill{background:color-mix(in srgb,var(--sage) 22%,transparent);
                            color:color-mix(in srgb,var(--sage) 42%,var(--ink))}

/* --- CTA : garantie ECRITE DANS le bouton ------------------------------- */
/* Le texte du bouton etait un #1B1420 : encore un presque-noir, invente. Sur
   l'or, l'encre de la marque porte le meme contraste. */
.cta{display:inline-block;background:var(--gold);color:var(--ink);text-decoration:none;
     font-weight:800;border-radius:999px;padding:16px 30px;text-align:center;
     line-height:1.25;box-shadow:0 10px 26px color-mix(in srgb,var(--ink) 30%,transparent)}
.cta small{display:block;font-weight:700;font-size:12.5px;opacity:.78;margin-top:3px}
.cta:hover{filter:brightness(1.05)}
.cta-row{margin:26px 0 0}
.pay{margin:14px 0 0;font-size:12.5px;letter-spacing:.06em;opacity:.62}
/* Sur le prune, cette ligne ne porte plus seulement « paiement securise » : elle
   porte la mention de prix de lancement, qui a remplace le chiffre barre. Une
   mention de conformite ne se lit pas a 62 % d'opacite sur un fond colore. */
.dark .pay{opacity:.84}

/* --- images : un CADRE, un ratio, jamais un fichier pose ----------------- */
/* Chaque image du site vit dans un cadre dont le ratio est declare ici et
   PRODUIT par engine/scripts/site_images.py : le fichier sort deja au ratio de
   son cadre. `object-fit:cover` n'a donc rien a recadrer — il est la comme
   garantie, pour que le jour ou une image reviendra au mauvais format, elle
   soit rognee et non etiree. La deformation n'est plus un etat possible. */
.media{overflow:hidden;border-radius:18px;background:var(--creme-2);
       box-shadow:0 22px 54px rgba(30,20,40,.17)}
.media img{width:100%;height:100%;object-fit:cover}
.media--sq{aspect-ratio:1/1}
.media--tall{aspect-ratio:4/5}
.media--wide{aspect-ratio:3/2}
.media--4x3{aspect-ratio:4/3}
/* Un detail de page est du CREME sur du creme : sans un filet, il se dissout
   dans la section et le lecteur voit un vide la ou on lui montre une preuve.
   Le filet dit « ceci est une page », il n'encadre pas une illustration. */
.media--art{aspect-ratio:16/9;border-radius:14px;border:1px solid rgba(46,42,48,.12);
            box-shadow:0 16px 38px rgba(30,20,40,.13)}
/* une PAGE se montre en page : pas de cadre a ratio impose, pas de rognage —
   sa hauteur suit sa largeur, et l'ombre porte le papier. */
.page-shot{max-width:560px;margin:0 auto;border-radius:6px;overflow:hidden;
           border:1px solid rgba(46,42,48,.12);
           box-shadow:0 26px 64px rgba(30,20,40,.22)}
.duo{display:grid;grid-template-columns:1fr 1fr;gap:34px;align-items:center}
.duo>*{min-width:0}
.benefit{display:grid;grid-template-columns:1fr 1fr;gap:38px;align-items:center;
         padding:26px 0}
.benefit:nth-child(even) .benefit__art{order:-1}
.benefit h3{margin-bottom:.35em}
.benefit p:last-child{margin-bottom:0}
.benefit__art{position:relative;min-width:0}
.note-hand{font-family:"Caveat",cursive;font-size:19px;color:var(--terracotta);
           margin:10px 0 0;text-align:center}
/* --- la legende d'un VISUEL PRODUIT, en deux temps ------------------------
   Sur grand ecran elle est exactement la meme chose qu'une `.note-hand` : nom
   et detail sur une ligne, en Caveat terracotta. Sous 480 px elle se dedouble —
   le NOM du produit passe en serif gras a taille de titre, le detail reste
   manuscrit mais plus grand.
   POURQUOI : a 390 px, 19 px de Caveat sur une ligne et demie ne se lisent pas,
   et une legende qu'on ne lit pas ne nomme rien. Sur /bundles c'est grave d'un
   cran de plus — c'est la seule page ou les Cards et les Rituals existent, et
   leur nom n'y figure qu'ici et dans le tableau. Une vignette sans nom lisible
   ne vend pas un produit, elle decore une section.
   `.note-hand` reste pour les legendes qui ne nomment PAS un produit (« page 9
   — a Sabbath night »). Deux objets, deux classes : les fondre obligerait la
   seconde a inventer un nom de produit qu'elle n'a pas. */
.cap{font-family:"Caveat",cursive;font-size:19px;color:var(--terracotta);
     margin:10px 0 0;text-align:center}
@media(max-width:480px){
  .cap{margin-top:12px}
  .cap__name{display:block;font-family:var(--serif);font-size:21px;font-weight:700;
             color:var(--plum);line-height:1.25;margin-bottom:3px}
  .cap__sep{display:none}
  .cap__detail{display:block;font-size:20px;line-height:1.3}
}

/* Le trio compose de la Quiet Collection. Pas de `.page-shot` : ce n'est pas
   UNE page, c'est trois pages posees sur leur propre fond creme — un filet
   autour dirait « une image », alors que ce qu'on montre est un etalage. Le
   fichier porte deja ses ombres portees ; le cadre n'ajoute qu'un rayon. */
.trio{border-radius:14px;overflow:hidden}
.trio img{width:100%;height:auto;display:block}
/* Une `<figure>` hors `.gallery` garde la marge par defaut du navigateur —
   `1em 40px`. Quatre-vingts pixels pris sur la largeur, invisibles dans le
   code et bien reels a l'ecran : le trio flottait au milieu de sa colonne avec
   du vide de chaque cote, et sur telephone il rentrait de 40 px sur les deux
   bords pendant que le texte, lui, allait au bout. */
.duo>figure{margin:0}

/* --- FAQ a plat, numerotee (pas d'accordeon) — et les suites numerotees --- */
/* `.steps` PARTAGE la composition de la FAQ au lieu de la recopier : meme liste
   a plat, meme numero dore, meme largeur de lecture. Ce ne sont simplement pas
   des questions — ce sont des etapes (les cinq gestes d'une soiree, les quatre
   controles d'un verset). Un seul jeu de regles, deux noms, pour qu'on ne
   cherche pas la question dans un `.faq__q` qui n'en est pas une. */
.faq,.steps{display:grid;gap:22px;max-width:800px;margin:0 auto}
.faq__q,.steps__t{font-family:var(--serif);font-size:20px;font-weight:700;margin:0 0 .3em}
.faq__n,.steps__n{color:var(--gold-soft);margin-right:.4em}

/* --- grille produits (home, panneaux plats) ----------------------------- */
.grid3{display:grid;grid-template-columns:repeat(auto-fit,minmax(268px,1fr));gap:24px}
/* DEUX colonnes, pour ce qui va par paires ou par quatre : quatre panneaux dans
   `.grid3` donnent 3 + 1, c'est-a-dire un orphelin, et un orphelin se lit comme
   un accident. Le minimum est `min(420px,100%)` et non `420px` : un minimum
   plus large que son conteneur ne se replie pas, il DEPASSE — et un depassement
   de 74 px sur un telephone est exactement ce que shoot_site.py refuse. */
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(420px,100%),1fr));gap:24px}
.card{border-radius:18px;overflow:hidden;background:var(--paper);display:flex;
      flex-direction:column;box-shadow:0 14px 34px rgba(30,20,40,.1)}
/* le cadre image d'une carte n'a ni ombre ni rayon propres : c'est la carte qui
   les porte, sinon on voit deux cadres emboites. */
.card .media{border-radius:0;box-shadow:none}
.card__body{padding:18px 20px 22px;display:flex;flex-direction:column;flex:1}
/* les trois cartes n'ont pas le meme nombre de lignes : sans cela, les prix et
   les liens ne s'alignaient pas d'une carte a l'autre. */
/* --- LE COUPLE DE PRIX SOUS CONDITION -------------------------------------
   19 barre, 9 en evidence, la condition COLLEE au 9. Le point median d'avant
   (« $19 · $9 with the welcome code ») posait les deux prix sur le meme plan :
   rien ne disait lequel on paie, et un couple de prix separes par un point se
   lit comme une fourchette. Le trait dit le mouvement.
   LA CONDITION EST SUR LA MEME LIGNE, ET C'EST UNE PORTE, pas un choix de mise
   en page : `barreConditionnel` refuse tout barre du 30-Day dont « welcome
   code » ne serait pas dans le meme fragment. 9 $ n'existe qu'avec le code —
   un barre pose seul annonce un rabais ouvert a tout le monde. */
.card__price{font-weight:800;color:var(--plum);margin-top:auto}
.card__price s{font-weight:400;opacity:.55;margin-right:5px}
.card__price-now{font-size:19px;font-weight:800;color:var(--plum)}
/* La condition ne se met pas en petit gris : elle fait partie du prix, et une
   mention de 12 px sous un chiffre est ce qu'on ne lit pas. */
.card__price-cond{font-weight:700;color:var(--ink-soft);white-space:nowrap}
.cond s{font-weight:400;opacity:.55;margin-right:5px}
.cond__now{font-size:21px;font-weight:800;color:var(--plum)}
.cond__if{font-weight:700;color:var(--ink)}
/* Dans un `.price` a 30-40 px, la condition ne peut pas suivre la taille du
   chiffre — elle ferait deux lignes de titre. Elle reste INLINE (la porte lit
   un fragment, pas un rendu) et redescend a la taille du corps. */
.price .cond__now{font-size:inherit}
.price .cond__if{font-family:var(--sans);font-size:16px;font-weight:700;color:var(--ink-soft)}
.card__go{margin:0;font-weight:700}
.panel{border-radius:20px;padding:34px 30px}
.panel--sand{background:color-mix(in srgb,var(--gold) 15%,var(--creme))}
.panel--sage{background:color-mix(in srgb,var(--sage) 18%,var(--creme))}
.panel--rose{background:color-mix(in srgb,var(--terracotta) 13%,var(--creme))}

/* --- landing du guide : les cinq pratiques ------------------------------- */
/* La vignette d'une pratique est FONDUE sur le creme dans l'image elle-meme
   (derive_web_assets.py cuit le degrade dans le fichier). Elle n'a donc ni
   cadre, ni ombre, ni ratio impose : un `.media` la rognerait et lui
   redessinerait le bord franc que la doctrine interdit. Elle vit sur `.light`
   — et seulement la : sur le creme-2, son fondu dessinerait un rectangle. */
/* Le fondu cuit dans le fichier suppose un bord CLAIR : derive_web_assets.py
   ne rebalance pas les scenes de nuit, et celle du « 2 A.M. Note » arrive donc
   avec des coins sombres — un rectangle net sur le creme, exactement ce que la
   doctrine interdit. Le masque radial finit le travail cote page, sans toucher
   au fichier : la vignette ne se retouche pas, elle se pose. */
.vignette{width:100%;max-width:480px;margin:0 auto;
  -webkit-mask-image:radial-gradient(closest-side at 50% 50%,#000 72%,transparent 100%);
          mask-image:radial-gradient(closest-side at 50% 50%,#000 72%,transparent 100%)}
.practices-list{margin-top:34px}
/* Trois zones nommees, et non deux colonnes avec un ordre bricole : c'est ce
   qui permet a la meme structure de donner « texte a gauche, image a droite »
   sur un bureau et « titre, image, texte » sur un telephone — sans que la
   vignette flotte a cote d'une colonne de texte a moitie large. */
.practice{display:grid;grid-template-columns:1fr 1fr;gap:8px 30px;
          grid-template-areas:"head art" "body art";align-items:center;padding:14px 0}
.practice__head{grid-area:head;align-self:end}
.practice__body{grid-area:body;align-self:start}
.practice__art{grid-area:art}
.practice:nth-child(odd){grid-template-areas:"art head" "art body"}
.practice h3{margin-bottom:.25em}
.practice p:last-child{margin-bottom:0}
.practice__n{display:inline-grid;place-items:center;width:30px;height:30px;
             border-radius:50%;background:var(--terracotta);color:var(--creme);
             font-weight:800;font-size:14px;margin-bottom:10px}
/* la reference du verset, de la main de la marque */
.verse-ref{font-family:"Caveat",cursive;font-size:18px;color:var(--terracotta);
           margin:0 0 .5em}

/* --- galerie de pages : le papier, pas un cadre -------------------------- */
.gallery .page-shot{max-width:none;margin:0}

/* --- rail d'apercus (« A peek inside ») ---------------------------------- */
/* UN RAIL, PAS UNE GRILLE. Cinq pages A4 dans une grille de telephone donnent
   cinq timbres de 60 px : on montre qu'il existe des pages, on ne montre pas ce
   qu'elles disent. Ici elles gardent une taille lisible et c'est le doigt qui
   avance — `scroll-snap` pour qu'une page s'arrete au centre plutot qu'a moitie
   sortie. Le debordement est INTERIEUR au rail : la page, elle, ne defile pas
   horizontalement (shoot_site.py le mesure a 390 px).
   `tabindex="0"` parce qu'un conteneur defilant doit pouvoir l'etre au clavier ;
   les vignettes sont deja des <button>, donc atteignables une a une. */
.peek{display:flex;gap:18px;overflow-x:auto;overscroll-behavior-x:contain;
      scroll-snap-type:x mandatory;padding:6px 2px 16px;margin:26px -2px 0;
      scrollbar-width:thin;
      scrollbar-color:color-mix(in srgb,var(--prune) 45%,transparent) transparent}
.peek:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:8px}
.peek__item{margin:0;flex:0 0 min(268px,74%);scroll-snap-align:center}
.peek .page-shot{max-width:none;margin:0;width:100%}
.peek__hint{text-align:center;font-size:13.5px;letter-spacing:.05em;color:var(--ink-soft);
            margin:6px 0 0}

/* --- formulaire de capture ---------------------------------------------- */
/* Les champs etaient stylas EN LIGNE dans le gabarit : trois attributs style
   recopies, donc trois occasions de diverger. */
.optin{margin:20px 0 0}
.optin p{margin:0 0 14px}
.optin label{display:block;font-size:14px;font-weight:700;letter-spacing:.02em}
.optin input{width:100%;margin-top:6px;padding:13px 14px;font:inherit;font-size:16px;
             border:1px solid color-mix(in srgb,var(--ink) 26%,var(--creme));
             border-radius:10px;background:var(--paper);color:var(--ink)}
.optin input:focus{outline:2px solid var(--sage);outline-offset:1px;border-color:var(--sage)}
.optin .cta{width:100%;border:0;font:inherit;font-weight:800;font-size:17px;cursor:pointer}
.optin .cta small{font-size:12.5px;font-weight:700}
.dark .optin label{color:var(--creme)}
.optin--wide{max-width:520px;margin-left:auto;margin-right:auto;text-align:left}
/* ---- LE FORMULAIRE D'AVIS -------------------------------------------------
   Il reutilise `.optin` plutot que d'ouvrir un deuxieme jeu de champs : c'est
   le meme geste, la meme largeur, et deux styles de formulaire sur un site qui
   n'en a que deux finiraient par diverger. Ne s'ajoute ici que ce que la
   capture d'email n'a pas — une zone de texte, une note sous un champ, une
   rangee de notes, une case a cocher.
   La zone de texte reprend la bordure et le focus des champs a l'identique :
   `font:inherit` d'abord, sinon le navigateur y remet sa police monospace. */
.optin textarea{width:100%;margin-top:6px;padding:13px 14px;font:inherit;font-size:16px;
                line-height:1.55;resize:vertical;
                border:1px solid color-mix(in srgb,var(--ink) 26%,var(--creme));
                border-radius:10px;background:var(--paper);color:var(--ink)}
.optin textarea:focus{outline:2px solid var(--sage);outline-offset:1px;border-color:var(--sage)}
/* UNE CASE D'UNE LETTRE A LA TAILLE D'UNE LETTRE. `.optin input` met tous les
   champs en pleine largeur, ce qui est juste pour un email et absurde pour une
   initiale : une boite de 520 px pour un caractere se lit comme un champ qu'on
   a oublie de remplir. `size="1"` ne suffisait pas — la largeur explicite le
   remporte. Le `ch` suit la police du champ plutot qu'une valeur en pixels.
   SELECTEUR `.optin input.optin__char` ET NON `.optin__char` SEUL : la regle
   qu'il doit battre est `.optin input`, qui vaut une classe PLUS un element.
   Une classe seule perd a specificite egale-moins-un, et la case restait large
   sans qu'aucune porte ne s'en apercoive — une largeur n'est pas une erreur.
   `display:block` en plus de la largeur : sans lui la case, devenue etroite,
   remonte sur la ligne de son propre libelle — « Last initial [ ] » alors que
   les autres champs posent le libelle AU-DESSUS. Deux dispositions dans un
   formulaire de cinq champs se lisent comme un defaut, pas comme une nuance. */
.optin input.optin__char{display:block;width:5ch;text-align:center;
                         text-transform:uppercase}
/* 15 px et non 13 : c'est le plancher que la porte mobile de build.mjs mesure a
   390 px, et elle a raison — cette note porte une CONSIGNE (« juste la
   lettre »), pas une mention legale. Une consigne qu'on ne lit pas produit un
   champ qu'on remplit mal. */
.optin__hint{margin:-8px 0 16px;font-size:15px;line-height:1.5;opacity:.72}
/* La rangee de notes. `fieldset` sans bordure : il est la pour la legende, qui
   est ce qu'un lecteur d'ecran annonce avant les cinq boutons — sans lui, on
   entend « 5 » puis « 4 » sans jamais savoir de quoi il s'agit. */
.rating{margin:0 0 16px;padding:0;border:0}
.rating legend{padding:0;font-size:14px;font-weight:700;letter-spacing:.02em}
.rating__row{display:flex;gap:8px;margin-top:8px}
.rating__row label{flex:1;display:block;position:relative;text-align:center;cursor:pointer}
/* Le bouton radio reste dans le document — il est seulement invisible. Un
   `display:none` le retirerait de l'ordre de tabulation, et la note
   deviendrait le seul champ du site qu'on ne peut pas donner au clavier. */
.rating__row input{position:absolute;opacity:0;width:1px;height:1px;margin:0}
.rating__row span{display:block;padding:11px 0;font-size:16px;font-weight:800;
                  border:1px solid color-mix(in srgb,var(--ink) 26%,var(--creme));
                  border-radius:10px;background:var(--paper);color:var(--ink)}
.rating__row input:checked + span{border-color:var(--prune);background:var(--prune);
                                  color:var(--creme)}
.rating__row input:focus-visible + span{outline:2px solid var(--sage);outline-offset:2px}
/* La case de consentement : l'un des deux seuls endroits du site ou une case
   commande autre chose que l'affichage. Elle ne se met pas en pleine largeur
   comme les champs — d'ou la remise a zero. */
.consent label{display:flex;gap:10px;align-items:flex-start;font-weight:600;font-size:14.5px;
               line-height:1.5;cursor:pointer}
.consent input{width:auto;flex:0 0 auto;margin:2px 0 0;padding:0;accent-color:var(--prune)}
/* les cinq pratiques : une liste, pas une phrase a rallonge separee par des
   points mediant. On les compte du regard. */
.practices{list-style:none;margin:16px 0 0;padding:0;display:grid;gap:7px;font-size:16px}
.practices li{position:relative;padding-left:24px}
.practices li::before{content:"";position:absolute;left:4px;top:.62em;width:8px;height:8px;
                      border-radius:50%;background:var(--sage)}

/* --- landing « 5 reasons why » : les blocs qui lui sont propres ---------- */
/* BANDEAU DE REASSURANCE (bloc 3). Les trois objections qui arrivent dans la
   seconde qui suit le titre. Les pictos sont des SVG EN LIGNE : trois fichiers
   d'icones seraient trois requetes de plus avant le premier mot lu, sur la page
   la plus mobile du site. */
.trust{list-style:none;margin:0;padding:0;display:grid;gap:18px 26px;
       grid-template-columns:repeat(auto-fit,minmax(248px,1fr))}
.trust li{display:flex;gap:13px;align-items:flex-start;font-size:15.5px;line-height:1.45}
.trust__i{width:26px;height:26px;flex:none;margin-top:1px;fill:none;
          stroke:var(--terracotta);stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.trust strong{font-size:16px}

/* LES LIGNES A COMPLETER, citees telles qu'elles sont imprimees. Une capture de
   page les rendrait a 9 px : ce sont trois lignes de huit mots, et les LIRE est
   la preuve — les voir photographiees n'en est pas une. */
.prompts{list-style:none;margin:14px 0 18px;padding:2px 0 2px 18px;display:grid;gap:10px;
         border-left:3px solid color-mix(in srgb,var(--terracotta) 42%,transparent)}
.prompts li{font-family:"Caveat",cursive;font-size:22px;line-height:1.3;
            color:var(--terracotta)}

/* LE CTA INTERSTITIEL (une ancre, pas un troisieme formulaire). Le
   rembourrage n'est pas decoratif : il porte la cible tactile a 48 px, comme
   tous les CTA de cette page. */
.skip{margin:0;font-family:var(--serif);font-size:clamp(18px,2.2vw,21px);font-weight:700}
.skip a{display:inline-block;padding:12px 6px;color:var(--plum);
        text-decoration-thickness:1.5px;text-underline-offset:5px}

/* LE RECAP DU BLOC 11 — une puce par raison, sur le prune. */
.recap{list-style:none;margin:18px auto 24px;padding:0;display:grid;gap:9px;max-width:520px;
       text-align:left;font-size:16px;color:var(--sur-prune)}
.recap li{position:relative;padding-left:26px}
.recap li::before{content:"";position:absolute;left:5px;top:.62em;width:8px;height:8px;
                  border-radius:50%;background:var(--gold-soft)}

/* La reassurance passe SOUS le bouton (structure bloc 2) : dans le bouton, elle
   allongeait la cible tactile sans etre lue ; dessous, elle repond aux trois
   questions qui restent une fois le doigt pose. */
.optin__note{margin:12px 0 0;font-size:13.5px;line-height:1.5;text-align:center;
             color:var(--ink-soft)}
.dark .optin__note{color:var(--sur-prune-soft)}
/* La barre collante recouvrirait la cible d'une ancre : on lui laisse sa place. */
.optin{scroll-margin-top:84px}

.fineprint{font-size:14px;line-height:1.6;color:var(--ink-soft);margin:0}

/* L'image passe devant sur un bureau, jamais sur un telephone (voir la media
   query). `:nth-child(even)` ne peut rien ici : chaque raison est seule dans sa
   section, donc toujours premiere-nee. */
.benefit--art-first .benefit__art{order:-1}

/* --- section d'avis ------------------------------------------------------ */
/* UNE TROISIEME SURFACE CLAIRE, et c'est la raison de son existence. Les pages
   alternent deja creme / creme chaud sans un seul raccord de meme couleur :
   inserer une section quelque part cree forcement un raccord. Plutot que de
   deplacer la section d'avis jusqu'a trouver le trou qui n'existe pas, on lui
   donne sa propre teinte — derivee de la sauge de tokens.json, comme les
   panneaux plats, et jamais une couleur inventee. */
.reviews-sec{background:color-mix(in srgb,var(--sage) 11%,var(--creme))}
.reviews-sec h2{margin-bottom:.3em}
.reviews__count{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
                gap:6px 12px;font-size:17px;color:var(--ink-soft);margin:0 0 26px;
                text-align:center}
.reviews__count strong{font-family:var(--serif);font-size:22px;color:var(--plum)}
.reviews__avg{font-family:var(--serif);font-size:21px;font-weight:700;color:var(--plum)}
.reviews__n{font-size:16px}
.reviews__note{text-align:center;font-size:13.5px;color:var(--ink-soft);margin:24px 0 0}
.review{background:var(--paper);border-radius:16px;padding:22px 20px;
        box-shadow:0 12px 30px rgba(30,20,40,.09);display:flex;flex-direction:column}
.review__top{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px}
.review__text{font-size:16px;margin:12px 0 14px}
.review__who{margin:auto 0 0;font-weight:800;font-size:14.5px;color:var(--plum);
             display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 10px}
/* La date n'est pas une decoration : un temoignage sans date est un temoignage
   dont on ne peut pas dire s'il parle du livre d'aujourd'hui. Elle est petite
   parce qu'elle se verifie, elle ne se vend pas. */
.review__date{font-weight:400;font-size:13px;color:var(--ink-soft);letter-spacing:.02em}
/* --- extraits du livre ----------------------------------------------------
   CE BLOC NE DOIT PAS RESSEMBLER A UNE CARTE D'AVIS, ET C'EST SA SEULE
   CONTRAINTE DE DESIGN.

   Un avis est la parole d'une lectrice ; un extrait est notre propre texte. A
   l'ecran, les deux sont un pave de prose au milieu d'une page de vente, et
   c'est exactement la que la confusion se produit — pas dans le balisage, que
   personne ne lit, mais dans le coup d'oeil de quelqu'un qui fait defiler.

   Ils se distinguent donc par TOUT ce qui se voit d'abord :
     · l'avis est une CARTE — fond papier, coins arrondis, ombre portee, sans
       serif, 16 px. Un objet pose sur la page.
     · l'extrait n'est PAS un objet : pas de fond, pas d'ombre, pas de bord. Du
       texte en serif, plus grand, centre, avec un trait fin au-dessus. Il se
       lit comme une page du livre qui affleure, pas comme un temoignage.
   Et surtout : l'extrait NOMME SA SOURCE. Un temoignage ne cite pas de page.
   C'est la ligne du dessous qui fait la difference pour un lecteur, plus que
   la typographie — d'ou son contraste, qui n'est pas celui d'une mention
   legale. */
.excerpt-sec{text-align:center}
.excerpt{margin:0;padding:0;max-width:44ch;margin-inline:auto;text-align:center}
/* Le trait, et non un guillemet ouvrant geant : un guillemet decoratif est
   precisement le signe typographique des blocs de temoignage. */
.excerpt::before{content:"";display:block;width:46px;height:2px;margin:0 auto 18px;
                 background:color-mix(in srgb,var(--plum) 38%,transparent)}
.excerpt__text{margin:0;font-family:var(--serif);font-size:clamp(19px,2.3vw,23px);
               line-height:1.42;color:var(--plum)}
.excerpt__text p{margin:0 0 .5em}
.excerpt__text p:last-child{margin-bottom:0}
/* LA SOURCE EN CAVEAT, comme les legendes de visuels : c'est l'annotation de la
   marque, la main qui montre du doigt. Elle est LISIBLE et non discrete — une
   source qu'on ne lit pas ne fait pas son travail, et son travail est
   d'empecher qu'on prenne cette phrase pour celle d'une lectrice. */
.excerpt__src{margin:16px 0 0;font-family:"Caveat",cursive;font-size:19px;line-height:1.3;
              color:var(--terracotta)}
.excerpt__src cite{font-style:normal}
.excerpt__page::before{content:" · "}
/* Dans une carte de lot, l'extrait est un ELEMENT de la carte et non un etage
   de la page : aligne a gauche comme le reste de la carte, un cran plus petit,
   et separe par un filet vertical plutot que par un trait centre — sans quoi il
   couperait la carte en deux. */
.card .excerpt,.duo .excerpt,.wrap.narrow>.excerpt{max-width:none}
.excerpt--inline,.duo .excerpt,.wrap.narrow .cta-row+.excerpt{text-align:left}
.duo .excerpt,.wrap.narrow>.excerpt:not(.excerpt-sec .excerpt){margin:18px 0 22px}
.duo .excerpt::before,.wrap.narrow>.excerpt::before{display:none}
.duo .excerpt,.wrap.narrow>.excerpt{border-left:2px solid
     color-mix(in srgb,var(--plum) 30%,transparent);padding-left:16px;text-align:left}
.duo .excerpt__text,.wrap.narrow>.excerpt__text{font-size:clamp(17px,1.9vw,19px)}
.duo .excerpt__src,.wrap.narrow>.excerpt__src{font-size:17px}

/* Les etoiles sont des DESSINS, pas des caracteres : la ligne rouge des faux
   avis interdit toute suite de trois « ★ » dans une page qui n'en montre
   aucun, et elle a raison de le faire. */
.stars{display:inline-flex;gap:3px}
.star{width:17px;height:17px;fill:var(--gold-brand)}
/* LA MOYENNE SE COUPE, ELLE NE S'ARRONDIT PAS. Arrondir 4,2 a l'entier
   superieur ferait un 5 sur une page de vente ; arrondir a l'inferieur volerait
   la note aux lectrices. Deux rangees superposees, celle du haut tronquee a la
   fraction juste : la cinquieme etoile est remplie a 20 % quand elle doit
   l'etre. */
.stars--avg{position:relative;display:inline-block;line-height:0}
.stars--avg .stars__off .star{fill:color-mix(in srgb,var(--ink) 18%,transparent)}
.stars--avg .stars__on{position:absolute;top:0;left:0;overflow:hidden;white-space:nowrap;
                       display:block}
.stars--avg .stars__off,.stars--avg .stars__on{display:inline-flex;gap:3px}
.stars--avg .stars__on .star{fill:var(--gold-brand)}

/* --- badge d'achat -------------------------------------------------------
   « Verified Buyer » n'est pas une decoration : c'est une affirmation qu'un
   lecteur peut nous opposer. Il ne sort que d'un `verified: true` ecrit a la
   main dans facts.json. Une lectrice beta a lu le livre sans l'acheter : elle
   porte « Early Reader », et le dire ne coute rien — c'est meme plus credible
   que l'inverse. Les deux badges se distinguent donc a l'oeil, sans que le
   second ait l'air d'un manque. */
.badge{font-size:11.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
       padding:4px 9px;border-radius:999px;white-space:nowrap}
.badge--ok{background:color-mix(in srgb,var(--sage) 26%,var(--creme));
           color:color-mix(in srgb,var(--sage) 52%,var(--ink));
           border:1px solid color-mix(in srgb,var(--sage) 55%,transparent)}
.badge--early{background:color-mix(in srgb,var(--ink) 7%,transparent);color:var(--ink-soft);
              border:1px solid color-mix(in srgb,var(--ink) 20%,transparent)}

/* LE BANDEAU DE MAQUETTE. Il est jaune, il est en capitales, il est en haut de
   la section, et il est laid exprès : c'est un objet de chantier. Le build
   depose en plus un fichier NOT-FOR-PROD dans dist/ tant qu'il est la — parce
   qu'un bandeau se voit sur la page, et qu'un dossier se televerse sans qu'on
   ouvre les pages. */
.sample-flag{background:var(--gold);color:var(--ink);font-weight:800;font-size:13px;
             letter-spacing:.11em;text-transform:uppercase;text-align:center;
             padding:11px 16px;border-radius:10px;margin:0 0 26px;
             border:2px dashed color-mix(in srgb,var(--ink) 45%,transparent)}
/* La version PASTILLE, pour les blocs disperses. Un bandeau pleine largeur
   au-dessus d'une carte isolee, repete cinq fois dans une page, finit par se
   lire comme un element de design — c'est-a-dire par ne plus se lire du tout.
   Elle porte exactement le meme texte : c'est ce texte que cherche la porte des
   echantillons, pas la taille de sa boite. */
.sample-flag--mini{display:block;width:fit-content;max-width:100%;margin:0 auto 14px;
                   font-size:11px;letter-spacing:.09em;padding:6px 12px;border-width:1px}

/* --- « Show more » : le reste des avis, sans une ligne de JavaScript --------
   Trois cartes visibles, le reste dans un `<details>`. Il s'ouvre au clic comme
   au clavier, il s'ouvre encore sans JS, et le contenu reste DANS la page pour
   qui la lit autrement — un moteur, un lecteur d'ecran, une impression. Un
   bouton qui masque des avis en les retirant du document masque aussi la seule
   preuve qu'ils existent. */
.reviews__more{margin-top:22px}
.reviews__more>summary{cursor:pointer;list-style:none;display:block;width:fit-content;
  margin:0 auto;font-weight:800;font-size:15px;letter-spacing:.04em;color:var(--plum);
  padding:11px 24px;border-radius:999px;background:var(--paper);
  border:1px solid color-mix(in srgb,var(--plum) 26%,transparent)}
.reviews__more>summary::-webkit-details-marker{display:none}
.reviews__more>summary::after{content:" ↓"}
.reviews__more[open]>summary::after{content:" ↑"}
.reviews__more>summary:hover{background:color-mix(in srgb,var(--plum) 7%,var(--paper))}
/* `auto-fill` et non `auto-fit` : le reste des avis est souvent UNE carte, et
   `auto-fit` fait disparaitre les pistes vides — la carte unique s'etirait alors
   sur toute la largeur, deux fois plus large que les trois du dessus. Les pistes
   vides restent, la carte garde le format de ses voisines. Sous 760 px la
   grille repasse a une piste comme les autres : la porte mobile les compte. */
.reviews__more .reviews{margin-top:22px;
  grid-template-columns:repeat(auto-fill,minmax(268px,1fr))}

/* --- LA CARTE ISOLEE, entre deux sections d'argumentaire -------------------
   Les avis ne vivent plus dans une seule section. Quatre d'entre eux sont poses
   le long de la page — apres le hero, apres le bloc rouge/vert, apres la
   garantie, avant le dernier CTA — parce qu'une objection se leve la ou elle
   arrive, pas dans un chapitre qui l'attend deux ecrans plus bas. Ils sortent
   de la MEME liste que la section groupee : la moyenne annoncee sous le hero
   est celle des cartes qu'on peut compter en bas. */
.solo-sec{background:color-mix(in srgb,var(--sage) 7%,var(--creme))}
.solo{max-width:620px;margin:0 auto}
.review--solo{padding:24px 24px 22px}
.review--solo .review__text{font-size:17px}

/* --- LA BARRE DE PREUVE, sous le hero --------------------------------------
   Le chiffre est le NOMBRE REEL d'avis de cette page, pas un total de commandes
   ni un « +1 000 lectrices » : la seule preuve qu'on peut opposer a quelqu'un
   est celle qu'il peut compter lui-meme, plus bas. En maquette, elle ne porte
   aucun chiffre du tout — des tirets. Un nombre pose « pour voir la mise en
   page » est un nombre qui part en ligne le jour ou on oublie de le retirer.
   FLEX ET NON GRID : une grille a deux pistes sous 760 px rend le build rouge,
   et cette barre doit pouvoir passer a la ligne sans media query dediee. */
.proofbar-sec{background:color-mix(in srgb,var(--sage) 9%,var(--creme))}
.proofbar{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
          gap:10px 22px;text-align:center}
/* Les avatars sont des MARQUES DE LA MARQUE, jamais des visages. Une rangee de
   portraits sous un compteur de lectrices dit « voici les gens qui ont lu » :
   la photo d'une personne reelle y serait un mensonge qu'aucune mention ne
   rattrape, et la seule illustration de personne que possede la marque est
   celle de son autrice — la repeter cinq fois ferait d'une rangee de lectrices
   une rangee de Hannah. */
.proofbar__faces{display:inline-flex;align-items:center}
.proofbar__mark{width:38px;height:38px;border-radius:50%;display:inline-flex;
  align-items:center;justify-content:center;background:var(--paper);
  border:1px solid color-mix(in srgb,var(--sage) 45%,transparent);
  box-shadow:0 3px 10px color-mix(in srgb,var(--ink) 12%,transparent)}
.proofbar__mark+.proofbar__mark{margin-left:-11px}
.proofbar__mark svg{width:21px;height:21px;fill:none;stroke:var(--plum);stroke-width:1.5;
                    stroke-linecap:round;stroke-linejoin:round}
.proofbar__score{display:inline-flex;flex-wrap:wrap;align-items:center;justify-content:center;
                 gap:5px 12px;font-size:17px;color:var(--ink-soft)}
.proofbar__score .reviews__avg{font-size:20px}
.proofbar__score .reviews__n{font-weight:800;color:var(--plum)}

/* --- LE BLOC ROUGE / VERT --------------------------------------------------
   Deux colonnes : la soiree telle qu'elle est, la soiree telle que le livre la
   propose. Le rouge est la TERRACOTTA de tokens.json — la marque n'a pas de
   rouge d'alerte, et en inventer un pour cette section ferait entrer une
   couleur qui n'existe dans aucun livre. Le vert est la sauge, celle des
   Sabbaths et des badges d'achat. Aucune des deux n'est un aplat sature : ce
   bloc oppose deux soirees, il ne signale pas une erreur de formulaire. */
.stuck{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr));
       gap:22px;align-items:start}
.stuck__col{border-radius:18px;padding:26px 24px 24px;background:var(--paper)}
.stuck__col--ko{background:color-mix(in srgb,var(--terracotta) 8%,var(--paper));
                border:1px solid color-mix(in srgb,var(--terracotta) 32%,transparent)}
.stuck__col--ok{background:color-mix(in srgb,var(--sage) 13%,var(--paper));
                border:1px solid color-mix(in srgb,var(--sage) 42%,transparent)}
.stuck__h{font-size:clamp(21px,2.5vw,26px);margin-bottom:.7em}
.stuck__col--ko .stuck__h{color:color-mix(in srgb,var(--terracotta) 68%,var(--ink))}
.stuck__col--ok .stuck__h{color:color-mix(in srgb,var(--sage) 52%,var(--ink))}
.stuck__list{list-style:none;margin:0;padding:0;display:grid;gap:14px}
.stuck__list li{display:flex;gap:12px;align-items:flex-start;font-size:16.5px;
                line-height:1.5}
.stuck__i{width:21px;height:21px;flex:none;margin-top:3px;fill:none;stroke-width:2.1;
          stroke-linecap:round;stroke-linejoin:round}
.stuck__col--ko .stuck__i{stroke:var(--terracotta)}
.stuck__col--ok .stuck__i{stroke:color-mix(in srgb,var(--sage) 78%,var(--ink))}
.stuck__list em{font-style:italic;color:var(--plum);font-weight:600}

/* --- LA GARANTIE, EN SECTION ----------------------------------------------
   Elle tenait en une phrase au bas de deux pages produit, entre un titre et un
   bouton. C'est pourtant la derniere objection avant de payer, et elle ne se
   leve pas en une ligne : combien de temps, a qui on ecrit, ce qu'il faut
   expliquer, si l'on rend le fichier, en combien de jours l'argent revient. */
.guarantee-sec{background:color-mix(in srgb,var(--gold-brand) 7%,var(--creme))}
.guarantee__seal{display:inline-flex;align-items:center;justify-content:center;
  width:62px;height:62px;border-radius:50%;margin-bottom:16px;background:var(--paper);
  border:1px solid color-mix(in srgb,var(--gold-brand) 55%,transparent);
  box-shadow:0 8px 22px color-mix(in srgb,var(--ink) 14%,transparent)}
.guarantee__seal svg{width:31px;height:31px;fill:none;stroke:var(--gold-brand);
                     stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.guarantee__h{margin-bottom:.55em}
.guarantee__close{font-weight:800;font-size:18px;color:var(--plum);margin:1.3em 0 .5em}
.guarantee__sign{font-family:"Caveat",cursive;font-size:26px;color:var(--terracotta);
                 margin:0}

/* --- L'AUTRICE EN TETE DE PAGE ---------------------------------------------
   Elle ne remplace pas la note signee du bas : les deux repondent a deux
   questions differentes. Celle du bas dit d'ou viennent les livres ; celle-ci
   dit QUI ECRIT, avant l'argumentaire — c'est la question qu'on se pose en
   arrivant sur une page qui va demander de l'argent, et elle n'avait de reponse
   qu'apres six ecrans de defilement.
   LE PORTRAIT EST ILLUSTRE. Un badge de verification a cote d'une fausse photo
   d'autrice serait la seule chose qu'on ne pourrait plus retirer d'une page de
   vente : elle ne se corrige pas, elle se retracte. */
.author-sec{background:var(--creme)}
.author{display:grid;grid-template-columns:auto 1fr;gap:26px;align-items:start;
        max-width:880px;margin:0 auto}
.author__face{width:112px;height:112px;border-radius:50%;overflow:hidden;flex:none;
  background:var(--paper);border:2px solid color-mix(in srgb,var(--sage) 45%,transparent)}
.author__face img{width:100%;height:100%;object-fit:cover}
.author__id{display:flex;align-items:center;gap:8px;margin:0 0 2px}
.author__name{font-family:var(--serif);font-size:24px;font-weight:700;color:var(--plum)}
/* LE BADGE DIT CE QU'IL COUVRE, ET RIEN DE PLUS. Il n'affirme pas qu'un tiers a
   verifie une identite : il dit que ce nom est bien celui qui signe les livres
   d'Anchored — meme nom sur la couverture, dans la note du bas et au pied de
   chaque email. Son intitule accessible l'ecrit en toutes lettres, et une porte
   du build refuse un badge qui perdrait cette mention. */
.author__check{display:inline-flex;width:20px;height:20px;flex:none}
.author__check svg{width:20px;height:20px;fill:color-mix(in srgb,var(--sage) 62%,var(--ink));
                   stroke:none}
.author__check .author__tick{fill:none;stroke:var(--creme);stroke-width:2.2;
                             stroke-linecap:round;stroke-linejoin:round}
.author__role{font-size:13px;font-weight:800;letter-spacing:.11em;text-transform:uppercase;
              color:var(--ink-soft);margin:0 0 14px}
.author__sign{font-family:"Caveat",cursive;font-size:25px;color:var(--terracotta);
              margin:.2em 0 0}
.author__body p{margin-bottom:.9em}

/* --- les chapitres nommes, les semaines nommees -------------------------- */
/* Ils etaient annonces par leur NOMBRE : « 6 chapters », « 13 weeks ». Une
   quantite ne se lit pas comme un sommaire — et c'est un sommaire qu'on cherche
   avant d'acheter un livre de 212 pages. */
.chapters{margin:0;padding:0 0 0 1.4em;display:grid;gap:11px;font-size:16px}
.chapters li::marker{color:var(--terracotta);font-weight:800}
.weeks{list-style:none;margin:26px auto 0;padding:0;max-width:820px;
       display:flex;flex-wrap:wrap;gap:9px;justify-content:center}
.weeks li{background:var(--paper);border:1px solid color-mix(in srgb,var(--prune) 20%,transparent);
          border-radius:999px;padding:8px 16px;font-size:15px;font-weight:700;
          color:var(--plum)}
/* L'intermede n'est pas une semaine : il ferme le premier mois et compte deux
   nuits. Le distinguer evite d'avoir a l'expliquer. */
.weeks--interlude{background:color-mix(in srgb,var(--gold) 22%,var(--creme));
                  border-color:color-mix(in srgb,var(--gold) 60%,transparent);
                  color:var(--ink);font-style:italic}

/* --- bloc de renversement de croyance ----------------------------------- */
.flip{display:grid;gap:16px;max-width:820px;margin:0 auto}
.flip__row{display:grid;grid-template-columns:1fr auto 1fr;gap:16px;align-items:center}
/* Le bloc a quitte le sombre (deux sections sombres par page, pas quatre) : il
   se compose donc sur le creme. La phrase rayee est en encre attenuee, la
   phrase juste sur un aplat d'or — le meme or que le surlignage des H2. */
.flip__old,.flip__new{border-radius:14px;padding:16px 18px;font-size:15.5px}
.flip__old{background:color-mix(in srgb,var(--ink) 6%,transparent);color:var(--ink-soft);
           text-decoration:line-through;
           text-decoration-color:color-mix(in srgb,var(--terracotta) 65%,transparent)}
.flip__new{background:color-mix(in srgb,var(--gold) 18%,transparent);color:var(--ink);
           border:1px solid color-mix(in srgb,var(--gold) 55%,transparent)}
.flip__ar{color:var(--terracotta);font-weight:800}

/* --- galerie produit ----------------------------------------------------- */
/* Trois vues au MEME ratio : une galerie ou chaque image a sa hauteur se lit
   comme un accident de mise en page, pas comme un choix. */
.gallery{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
         gap:22px;margin:0 0 30px}
.gallery figure{margin:0}
/* deux vues : sans plafond, elles s'etalent a 507 px chacune et la comparaison
   devient deux affiches. */
.gallery--duo{max-width:720px;margin-left:auto;margin-right:auto}
.gallery figcaption{margin-top:9px}
/* ---- LES VISUELS EN SITUATION -------------------------------------------
   Deux photos cote a cote sous la section qui parle de cet usage-la. Le gabarit
   de colonnes est copie de `.grid2` et non invente : `minmax(min(420px,100%),1fr)`
   retombe a UNE colonne des que la fenetre passe sous 420 px, ce qui est
   exactement ce que la porte mobile de shoot_site.py exige a 390 px — aucune
   grille multi-colonnes sur un telephone. Un `repeat(2,1fr)` aurait donne deux
   photos de 170 px de large, cote a cote, sur l'ecran qui recoit 90 % du trafic. */
.life-duo{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(420px,100%),1fr));
          gap:24px;margin-top:6px}
/* Le cas a UN seul visuel — /thirty, faute d'une seconde photo qui ne
   revendique pas une edition qu'elle n'a pas. Borne a la largeur d'une des deux
   colonnes ci-dessus, et centree : sans cela la photo prend 1136 px pour un
   fichier de 1000, soit un agrandissement de 14 %. */
.life-duo--solo{max-width:556px;margin-left:auto;margin-right:auto}
/* Le cas a TROIS — /thirty depuis le lot du 21/08. Le plancher de 420 px ne
   tient que deux colonnes ici : la troisieme photo tomberait seule sur une
   rangee et s'y etirerait sur 1136 px, le defaut meme que `--solo` corrige.
   A 300 px, trois colonnes tiennent (3x300 + 2x24 = 948 < 1136), et sous
   390 px il reste 346 px utiles pour un plancher de 300 : une seule colonne,
   ce que la porte mobile exige. */
.life-duo--trio{grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr))}
.life{margin:0}
.life figcaption{margin-top:10px;text-align:center}
.life-lead{margin:0 0 18px}

/* --- promesse de remboursement ------------------------------------------ */
/* Le bloc etait une bande sombre. Sur creme, il lui faut un contour pour rester
   une PROMESSE et non un paragraphe de plus : un filet prune, la couleur qui
   porte les versets dans les livres. */
.vow{border:1.5px solid color-mix(in srgb,var(--prune) 46%,transparent);
     border-radius:20px;padding:34px 30px 26px;
     background:color-mix(in srgb,var(--prune) 7%,var(--creme))}
.vow p:last-child{margin-bottom:0}

/* --- pont de remise ------------------------------------------------------ */
.bridge{border:2px dashed rgba(242,188,75,.6);border-radius:18px;padding:26px 24px;
        background:rgba(242,188,75,.07)}
.price{font-family:var(--serif);font-size:40px;font-weight:700;color:var(--plum)}
.dark .price{color:var(--creme)}
.price s{font-size:22px;opacity:.5;margin-right:12px;font-weight:400}

/* le champ-piege : hors ecran, jamais display:none — un robot qui lit le CSS
   saute ce qui est masque, et un lecteur d'ecran doit pouvoir l'annoncer. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* le bouton qui porte une page ne doit rien avoir d'un bouton */
button.page-shot{display:block;padding:0;border:1px solid rgba(46,42,48,.12);
                 background:none;font:inherit;width:100%}
.nav--focus{justify-content:center}

/* --- page merci : le contenu ne s'ouvre qu'avec le jeton ----------------- */
/* L'etat FERME est celui du HTML, exactement comme pour l'offre d'accueil
   ci-dessous : sans JavaScript, sans jeton, ou en arrivant par un lien colle,
   c'est « check your inbox » qui s'affiche — jamais le PDF, jamais le prix
   d'accueil. Le script n'a que le pouvoir d'OUVRIR. Un garde qui, en tombant en
   panne, montrerait ce qu'il garde ne garde rien. */
.gate__open{display:none}
.gate[data-state="open"] .gate__open{display:block}
.gate[data-state="open"] .gate__locked{display:none}

/* --- offre d'accueil (page merci) ---------------------------------------- */
/* L'etat FERME est celui du HTML : sans JavaScript, le visiteur voit le prix
   boutique et le rappel de l'email — jamais une fenetre ouverte qu'on ne
   pourrait pas tenir. Le script n'a que le pouvoir d'ouvrir. */
.welcome{border:2px solid color-mix(in srgb,var(--gold) 55%,transparent);
         border-radius:20px;padding:32px 28px;
         background:color-mix(in srgb,var(--gold) 8%,var(--creme))}
.welcome__open{display:none}
.welcome[data-state="open"] .welcome__open{display:block}
.welcome[data-state="open"] .welcome__closed{display:none}
.welcome h2{margin-bottom:.35em}
.welcome__clock{font-family:var(--serif);font-size:46px;font-weight:700;
                letter-spacing:.02em;color:var(--terracotta);margin:0 0 .1em;
                font-variant-numeric:tabular-nums}
.welcome .price{font-size:30px;margin-bottom:.6em}
.welcome .price s{font-size:19px}

/* --- note signee --------------------------------------------------------- */
/* Le portrait est ILLUSTRE, et il le restera : une fausse photo d'autrice est
   la seule chose qu'on ne pourra jamais retirer d'une page de vente. */
.note{display:grid;grid-template-columns:auto 1fr;gap:26px;align-items:start;
      max-width:760px;margin:0 auto}
.note__face{width:132px;height:132px;border-radius:50%;overflow:hidden;
            background:color-mix(in srgb,var(--sage) 14%,var(--creme))}
.note__face img{width:100%;height:100%;object-fit:cover}
.note p:last-child{margin-bottom:0}
.note__sign{font-family:"Caveat",cursive;font-size:26px;color:var(--terracotta);
            margin-top:.2em}

/* --- zoom des pages (sans librairie) ------------------------------------- */
.zoomable{cursor:zoom-in}
.lightbox{position:fixed;inset:0;z-index:50;display:grid;place-items:center;
          padding:24px;background:color-mix(in srgb,var(--ink) 88%,transparent);
          cursor:zoom-out}
.lightbox img{max-width:min(96vw,760px);max-height:92vh;width:auto;height:auto;
              border-radius:6px;box-shadow:0 30px 80px rgba(30,20,40,.5)}
.lightbox__hint{position:absolute;bottom:16px;left:0;right:0;text-align:center;
                color:var(--sur-prune);font-size:13px;letter-spacing:.06em}

/* --- l'ADVERTORIAL EDITORIAL (/journal/lying-awake) ------------------------
   Quatre regles, et pas une de plus. Cette page a longtemps eu sa PROPRE
   feuille de style — 13 Ko, une seconde palette en dur, une seconde famille
   serif, un second bouton — parce qu'elle etait recopiee dans dist/ sans passer
   par un gabarit. Elle rejoint site.css le 26/08 ; ce qui suit est le seul
   ecart qui restait justifie, c'est-a-dire ce qu'aucune autre page ne fait.

   Ce qui n'est PAS ici, et qui vient donc du site comme partout ailleurs : le
   H1 (serif, clamp), le corps (sans-serif 17 px), le bouton (`.cta`, l'or sur
   encre), l'extrait du livre (`.wrap.narrow>.excerpt`, filet vertical + source
   en Caveat), la largeur de lecture (`.wrap.narrow`, 730 px), la barre haute,
   la nav et le pied. Un advertorial qui ne ressemble pas au site sur lequel il
   vend demande a la lectrice de croire deux marques a la fois.

   LA SIGNATURE ET LA MENTION SONT DES `p` DE PLUS DE 60 CARACTERES POUR
   L'UNE — donc mesurees par la porte de prose de shoot_site.py, qui exige
   15 px minimum sur telephone. C'est pour ca que la mention est a 15 px et non
   a 13,5 comme un pied de page : c'est le dernier endroit ou economiser un
   demi-pixel, et la porte le dit maintenant a notre place. */
.ad__by{font-family:"Caveat",cursive;font-size:21px;line-height:1.3;
        color:var(--ink-soft);margin:-.2em 0 1.1em}
/* LE HERO EST NET, PLEIN CADRE — ET C'EST UN RENVERSEMENT ASSUME (28/08).
   Il a porte deux jours un double masque en degrade : un fondu sur les quatre
   cotes, au nom de la doctrine « illustration fondue, jamais encadree ». Cette
   doctrine vise les ILLUSTRATIONS aquarellees des livres, qui sont dessinees
   sur du creme et se posent sur du creme — leur fondre les bords evite le
   rectangle blanc qu'on verrait sinon. Une PHOTOGRAPHIE n'a pas ce probleme :
   elle a ses propres bords, et les estomper ne la fond pas dans la page, elle
   la fait paraitre mal imprimee. Sur un hero d'advertorial, le premier objet
   que voit la lectrice avait donc l'air d'un fichier abime.
   Le traitement est celui de /thirty et de /complete : rayon de 18 px, ombre
   portee, aucun degrade — `.media` sans son cadre a ratio, puisque le fichier
   sort deja au ratio ou il s'affiche. C'EST LA REGLE POUR TOUTE IMAGE DE CETTE
   PAGE : le hero, la planche, les vignettes. */
.ad__hero{width:100%;margin:0 auto 30px;border-radius:18px;
          box-shadow:0 22px 54px rgba(30,20,40,.17)}
/* La premiere phrase apres le hero est la CHUTE du titre, pas un paragraphe :
   elle se lit d'un souffle et donne le ton. Un cran plus grande, et c'est tout —
   pas de lettrine, qui ferait magazine sur une page qui se veut une lettre. */
.ad__drop{font-size:clamp(18.5px,2.1vw,20.5px);line-height:1.55}
/* LA PLANCHE AVANT/APRES, au milieu du recit. Elle RESPIRE plus qu'une image
   d'argumentaire — c'est un pattern interrupt, son travail est de casser le
   defilement, et une planche collee au paragraphe suivant ne le casse pas.
   Pas de `.media` autour : un cadre a ratio impose rognerait un des deux
   panneaux du diptyque, c'est-a-dire la moitie de l'argument. Pas de fondu non
   plus, contrairement au hero : la planche a son propre bord creme peint, et
   un masque par-dessus mangerait les deux bandeaux du bas.
   Le leger rayon suffit a la detacher du creme de la page sans lui dessiner le
   cadre net que la doctrine interdit. */
.ad__plate{margin:0}
.ad__plate img{border-radius:18px;box-shadow:0 22px 54px rgba(30,20,40,.17)}

/* --- LES TROIS PETITES REGLES (etage 4 de l'advertorial) ------------------
   Le recit les ENONCE en une phrase — « une regle, une regle, une regle » — et
   une phrase ne se scanne pas. Un advertorial se lit en diagonale avant d'etre
   lu : ce bloc est l'endroit ou la lectrice qui saute les paragraphes retrouve
   la methode entiere en trois coups d'oeil.
   TROIS COLONNES DECLAREES, ET NON UN `auto-fit`. La premiere version laissait
   la grille se replier toute seule sur un plancher de 268 px — et dans la
   colonne de lecture (`.wrap.narrow`, 686 px utiles) elle rendait DEUX regles
   cote a cote et la troisieme seule en dessous. Trois regles annoncees comme
   trois et affichees comme 2 + 1 ne se scannent pas : l'oeil compte deux
   choses, puis une autre. Le bloc vit donc dans le `.wrap` large et pose
   explicitement ses trois pistes. Sous 760 px, le media query les empile —
   c'est la porte mobile de shoot_site.py qui l'exige, et elle a raison : trois
   colonnes de 100 px ne sont pas trois colonnes. */
.rules{display:grid;grid-template-columns:repeat(3,1fr);
       gap:30px 26px;margin:30px 0 0;text-align:center}
.rules>li{list-style:none;margin:0}
/* UNE BOITE CARREE FIXE, ET LE DESSIN DEDANS. Elle valait `height:92px;
   width:auto` — donc trois largeurs differentes (84, 99 et 86 px), puisque les
   trois vignettes n'ont pas la meme hauteur native. La bulle de pensee etait
   18 % plus large que ses voisines et pesait plus lourd dans une rangee ou les
   trois doivent se valoir.
   Les assets sortent desormais CARRES de site_images.py, rognes sur leur encre
   et recentres sur leur centre de masse. La boite est donc carree elle aussi,
   et `contain` est la garantie : le jour ou une vignette reviendrait au mauvais
   format, elle serait contenue, jamais etiree.
   92 px reste decide par le fichier et non par le gout : au-dela d'environ
   94 px de cote, la quantification en palette se voit sur les aplats
   aquarelles. */
.rules__i{width:92px;height:92px;object-fit:contain;margin:0 auto 12px;display:block}
.rules__t{font-family:var(--serif);font-size:21px;font-weight:700;color:var(--plum);
          margin:0 0 .3em}
.rules__d{margin:0;font-size:16px;color:var(--ink-soft)}

/* --- L'ETAGE DE CONVICTION DE L'ACCUEIL ----------------------------------
   Trois idees, sur trois surfaces teintees. Elles reprennent `.panel` — la
   meme boite que les deux encarts du bas de l'accueil — et non `.card` : une
   carte porte une photo de produit et un prix, et trois cartes de plus sous
   les trois cartes produit se seraient lues comme six produits.
   MEME BOITE D'ICONE QUE `.rules`, 92 px, et c'est la meme raison qui la
   decide : au-dela d'environ 94 px de cote, la quantification en palette se
   voit sur les aplats aquarelles. Les deux etages se suivent sur l'accueil ;
   deux tailles de vignette a un ecran d'intervalle se liraient comme un defaut
   de gabarit, pas comme une intention.
   LE TITRE EST DANS LE MEME REGISTRE QUE `.rules__t` — serif, prune — parce
   que les deux blocs disent la meme categorie de chose : une idee courte sous
   une image. Ce qui les distingue est la SURFACE, pas la typographie.
   `align-items:stretch` sur la grille : les trois textes n'ont pas la meme
   longueur, et trois fonds teintes de hauteurs differentes se lisent comme un
   defaut d'alignement — la ou trois hauteurs de texte nu ne se voient pas. */
.think{align-items:stretch}
.think .panel{padding:30px 26px 34px;text-align:center}
.think__i{width:92px;height:92px;object-fit:contain;margin:0 auto 12px;display:block}
.think h3{font-family:var(--serif);font-size:21px;font-weight:700;color:var(--plum);
          margin:0 0 .35em}
.think p{margin:0;font-size:16px;color:var(--ink-soft)}

/* --- CE QU'IL Y A DEDANS (etage 7) ---------------------------------------
   Une liste, pas des paragraphes : ce sont des FAITS, et un fait se verifie
   d'un coup d'oeil. La puce est la meme sauge que `.practices` de la landing —
   le site n'invente pas une seconde puce pour une seconde liste. */
.facts-list{list-style:none;margin:24px 0 0;padding:0;display:grid;gap:12px;
            font-size:16.5px;text-align:left;max-width:560px;
            margin-inline:auto}
.facts-list li{position:relative;padding-left:26px}
.facts-list li::before{content:"";position:absolute;left:4px;top:.62em;width:8px;height:8px;
                       border-radius:50%;background:var(--sage)}
.facts-list b{font-weight:800;color:var(--ink)}
/* La rangee de pastilles du livre, posee comme un filet : elle annonce la
   liste, elle ne la decore pas. 150 px est son natif — on ne l'agrandit pas. */
.facts-list__rule{width:150px;height:auto;margin:4px auto 0;display:block;opacity:.9}
.ad__cta{margin:34px 0 8px}
.ad__cta-note{margin:14px 0 0;font-style:italic;color:var(--ink-soft);font-size:16px}
/* SUR LE PRUNE, LES DEUX LIGNES DE CLOTURE CHANGENT D'ENCRE. Elles sont nees
   sur du creme et y ont leur couleur ; posees telles quelles sur la bande
   sombre de l'etage 9, elles seraient restees en encre sur du prune —
   c'est-a-dire invisibles. Aucune porte ne l'aurait vu : shoot_site.py mesure
   les couleurs de FOND, jamais le contraste d'un texte sur celui qui le porte.
   `--sur-prune` pour la ligne de rythme, `--sur-prune-soft` pour la mention :
   la seconde est un rappel legal, pas une phrase de vente, et 72 % de creme
   est le seuil au-dessous duquel le pied de page tombait sous AA. */
.dark .ad__cta-note{color:var(--sur-prune)}
.dark .ad__note{color:var(--sur-prune-soft);
                border-top-color:color-mix(in srgb,var(--creme) 22%,transparent)}
/* La mention de transparence : encadree par le haut, comme la note legale des
   avis. Elle n'est pas une signature, c'est une DIVULGATION — qui publie, et
   que le recit est celui d'une personne. Le filet dit qu'on change de registre. */
.ad__note{margin:30px 0 0;padding-top:18px;
          border-top:1px solid color-mix(in srgb,var(--ink) 14%,transparent);
          color:var(--ink-soft);font-style:italic;font-size:15px;line-height:1.6}

/* --- pied --------------------------------------------------------------- */
.foot{background:var(--prune);color:var(--sur-prune-soft);padding:44px 22px;font-size:13.5px}
.foot__in{max-width:var(--wrap);margin:0 auto;text-align:center}
/* En bas de page, l'ancre SEULE au-dessus du mot : on signe, on ne se
   represente pas une deuxieme fois. `margin:auto` parce que le pied est
   centre et qu'une image est un bloc — sans lui elle se collerait a gauche. */
.foot__mark{width:auto;height:30px;display:block;margin:0 auto 10px}
.foot__brand{font-family:var(--serif);font-size:22px;color:var(--creme);margin:0 0 12px}
.foot__legal{line-height:1.7;margin:0 0 16px}
.foot__links{display:flex;gap:18px;justify-content:center;flex-wrap:wrap}
.foot__links a{color:var(--sur-prune)}

/* --- tableau de bord interne (/admin) ------------------------------------ */
/* Aux couleurs du site, parce qu'une page d'outil laide finit par ne plus etre
   ouverte — et celle-ci porte la seule liste de ce qui reste a faire hors du
   depot. Elle n'est liee de nulle part et ne s'indexe pas : c'est build.mjs qui
   le verifie, pas une consigne. */
/* `overflow-wrap:anywhere` n'est pas cosmetique : un chemin de fichier est un
   mot de quarante caracteres sans espace, et sa largeur minimale devient celle
   de la grille qui le contient. Un seul <code> a suffi a pousser la page a
   453 px dans une fenetre de 390 — c'est-a-dire a du defilement horizontal sur
   toute la page, pour un nom de fichier. */
code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.92em;
     background:color-mix(in srgb,var(--prune) 9%,transparent);padding:1px 5px;
     border-radius:5px;overflow-wrap:anywhere}
.steps>*,.faq>*{min-width:0}
.facts__h{font-family:var(--sans);font-size:13px;font-weight:800;letter-spacing:.13em;
          text-transform:uppercase;color:var(--terracotta);margin:26px 0 8px}
.facts{width:100%;border-collapse:collapse;font-size:15px;table-layout:fixed}
.facts th,.facts td{text-align:left;vertical-align:top;padding:9px 12px 9px 0;
                    border-bottom:1px solid color-mix(in srgb,var(--ink) 12%,transparent);
                    overflow-wrap:anywhere}
.facts th{width:38%;font-weight:700;color:var(--plum)}
.facts__why td{font-size:13.5px;font-style:italic;color:var(--ink-soft);line-height:1.55;
               padding-top:2px;border-bottom:0}
/* Le tableau « que fait chaque cle » : trois colonnes sur un bureau, et une
   liste empilee sous 760 px — trois colonnes de texte a 110 px ne sont pas un
   tableau, ce sont trois colonnes vides. Les cellules reprennent alors leur
   etiquette, sinon la valeur ne dit plus de quoi elle est la valeur. */
.keys{width:100%;border-collapse:collapse;font-size:15px;margin-top:20px}
.keys th,.keys td{text-align:left;vertical-align:top;padding:12px 14px 12px 0;
                  border-bottom:1px solid color-mix(in srgb,var(--ink) 12%,transparent);
                  overflow-wrap:anywhere}
.keys thead th{font-size:12px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
               color:var(--terracotta);border-bottom-width:2px}
.keys tbody th{width:23%;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
               font-size:13.5px;font-weight:700;color:var(--plum)}
.keys tbody td:last-child{width:20%;font-weight:700;color:var(--ink)}
@media(max-width:760px){
  .keys,.keys tbody,.keys tr,.keys th,.keys td{display:block;width:auto}
  .keys thead{display:none}
  .keys tr{padding:14px 0;border-bottom:1px solid color-mix(in srgb,var(--ink) 14%,transparent)}
  .keys th,.keys td{border:0;padding:0 0 6px}
  .keys tbody th{font-size:14px}
  .keys tbody td{font-size:15px}
  .keys tbody td:last-child::before{content:"now: ";font-weight:800;color:var(--terracotta)}
}

/* --- le tableau des lots (/bundles) -------------------------------------- */
/* UN TABLEAU, ET PAS UNE GRILLE — la contrainte est mesuree, pas esthetique :
   sous 760 px, shoot_site.py rend le build rouge des qu'une grille garde plus
   d'une piste, et trois colonnes de prix a 110 px sur un telephone ne sont pas
   un comparatif, ce sont trois colonnes vides. `display:table` echappe a cette
   mesure parce qu'il n'est pas une grille — mais il deborderait, ce que la
   meme porte refuse. D'ou le repli en blocs empiles plus bas, calque sur
   `.keys` : c'est le meme probleme, resolu de la meme facon, et deux solutions
   differentes pour deux tableaux du meme site auraient diverge au premier
   changement.
   `table-layout:auto` et non `fixed` : la premiere colonne porte un nom de
   produit sur deux lignes, les trois autres un prix ou un mot. A largeurs
   egales, le nom se casse en quatre lignes a cote de trois cellules vides. */
.compare{width:100%;border-collapse:collapse;font-size:15.5px;margin:26px 0 0}
.compare th,.compare td{text-align:left;vertical-align:top;padding:14px 16px 14px 0;
                        border-bottom:1px solid color-mix(in srgb,var(--ink) 12%,transparent)}
.compare thead th{font-size:12px;font-weight:800;letter-spacing:.11em;text-transform:uppercase;
                  color:var(--terracotta);border-bottom-width:2px;line-height:1.4}
.compare tbody th{font-weight:700;color:var(--ink);width:34%}
.compare tbody th small{display:block;font-weight:400;font-size:13.5px;color:var(--ink-soft);
                        margin-top:3px}
.compare__yes{font-weight:700;color:var(--sage)}
/* « not included » se lit AUSSI vite que « included », et c'est le point : une
   ligne absente d'un lot doit se voir sans relire. Elle est en gris et non en
   rouge — ce n'est pas un defaut du produit, c'est ce qu'on n'a pas mis
   dedans. */
.compare__no{color:var(--ink-soft);opacity:.75}
.compare__total th,.compare__total td{font-weight:700;color:var(--ink-soft);
                                      border-bottom-width:2px}
.compare__price th,.compare__price td{font-family:var(--serif);font-size:22px;font-weight:700;
                                      color:var(--plum);padding-top:16px}
.compare__price small{display:block;font-family:var(--sans);font-size:13.5px;font-weight:700;
                      color:var(--sage);margin-top:4px;letter-spacing:.02em}
.compare__go td a{font-weight:700;color:var(--plum);text-underline-offset:4px}
.compare__go th,.compare__go td{border-bottom:0}
/* Le libelle d'une colonne, repete dans la cellule une fois le tableau replie.
   Il n'est PAS decoratif : sans lui, « $19 » sous « The Quiet Collection »
   pourrait etre le prix de n'importe laquelle des trois colonnes. */
.compare td::before{content:attr(data-col) " ";display:none;font-size:12px;font-weight:800;
                    letter-spacing:.1em;text-transform:uppercase;color:var(--terracotta)}
/* --- les deux cartes de lot, qui REMPLACENT le tableau sur telephone -------
   Le tableau replie en blocs empiles a ete essaye et abandonne : il donnait
   « The 30-Day Edition / on its own $19 / Nightstand Kit: not included / Quiet
   Collection: included », c'est-a-dire un inventaire d'attributs. Un inventaire
   informe, il ne fait pas choisir — et a 390 px la question n'est pas « que
   contient chaque colonne » mais « laquelle des deux je prends ». Les deux
   rendus sont GENERES par blocLots() depuis les memes cles de facts.json : ils
   ne peuvent pas diverger, c'est la condition pour s'autoriser deux ecritures
   du meme comparatif dans le DOM. */
.lotcards{display:none}
.solo{list-style:none;margin:22px 0 26px;padding:0}
.solo li{display:flex;justify-content:space-between;gap:14px;align-items:baseline;
         padding:9px 0;font-size:15.5px;color:var(--ink-soft);
         border-bottom:1px solid color-mix(in srgb,var(--ink) 10%,transparent)}
.solo b{font-weight:800;color:var(--ink);white-space:nowrap}
.lotcard{background:var(--paper);border-radius:18px;padding:22px 20px 24px;margin:0 0 18px;
         box-shadow:0 14px 34px rgba(30,20,40,.1)}
.lotcard__h{font-family:var(--serif);font-size:23px;font-weight:700;color:var(--plum);
            margin:0 0 14px;line-height:1.2}
.lotcard__has{list-style:none;margin:0 0 16px;padding:0}
.lotcard__has li{position:relative;padding-left:27px;margin:0 0 8px;font-size:16px;
                 line-height:1.4}
.lotcard__has li::before{position:absolute;left:0;top:0;font-weight:800}
.lotcard__has .is-in::before{content:"✓";color:var(--sage)}
/* La piece ABSENTE reste ecrite, et grisee. Elle porte le MOT « not included »
   et non plus un tiret : le tableau du desktop l'ecrivait deja en toutes
   lettres pendant que la carte laissait deviner un signe, et un signe se
   devine quand un mot se lit. Les deux rendus tirent ce mot de la meme
   constante dans blocLots().
   Pas de croix rouge : ce n'est pas un defaut du Kit, c'est ce qu'on n'a pas
   mis dedans — et l'autre carte, juste dessous, le contient. */
.lotcard__has .is-out{color:var(--ink-soft);opacity:.72}
.lotcard__has .is-out::before{content:"–";color:var(--ink-soft)}
.lotcard__not{display:block;font-weight:700;color:var(--ink-soft);
              letter-spacing:.01em;margin-top:1px}
.lotcard__was{margin:0 0 2px;font-size:15px;color:var(--ink-soft)}
.lotcard__was s{opacity:.7}
.lotcard__pay{font-family:var(--serif);font-size:34px;font-weight:700;color:var(--plum);
              margin:0 0 16px;line-height:1.1}
.lotcard__pay small{display:block;font-family:var(--sans);font-size:14px;font-weight:700;
                    color:var(--sage);margin-top:4px;letter-spacing:.02em}
/* Un BOUTON plein, pas un lien texte : c'est la seule action de la carte, et un
   lien souligne au bas d'un prix se lit comme une note de bas de page.
   `display:block` et non `flex` : le `.cta` de base pose sa mention de garantie
   en `<small>` bloc SOUS le libelle. Passe en flex, l'ancre devenait une rangee
   et la mention se collait a DROITE du libelle, qui se cassait alors en trois
   lignes dans ce qui restait. Un bouton pleine largeur n'a pas besoin de flex,
   il a besoin de `width`. */
.lotcard .cta{display:block;width:100%;padding-left:18px;padding-right:18px}

@media(max-width:760px){
  .compare{display:none}
  .lotcards{display:block}
}

/* La seule chose qu'un lecteur d'ecran doit entendre et qu'aucun oeil ne voit :
   la legende d'un tableau, et l'intitule d'une colonne de boutons. `clip-path`
   plutot que `display:none`, qui la retirerait aussi de l'arbre accessible —
   c'est-a-dire qui la supprimerait pour tout le monde. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
         clip-path:inset(50%);white-space:nowrap;border:0}

/* Le rappel legal des avis. Il est encadre parce qu'il n'est pas une
   recommandation : c'est la seule ligne de cette page qu'on ne peut pas
   corriger apres coup une fois publiee. */
.legal-note{border-left:4px solid var(--terracotta);
            background:color-mix(in srgb,var(--terracotta) 9%,transparent);
            border-radius:0 12px 12px 0;padding:14px 18px;margin:0 0 20px;font-size:16px}
/* Un extrait a copier : il doit defiler DANS sa boite, jamais pousser la page —
   un fragment de JSON est fait de lignes qu'on ne coupe pas. */
.snippet{background:color-mix(in srgb,var(--prune) 8%,var(--paper));
         border:1px solid color-mix(in srgb,var(--prune) 22%,transparent);
         border-radius:12px;padding:16px 18px;overflow-x:auto;margin:0 0 14px}
.snippet code{background:none;padding:0;font-size:13.5px;line-height:1.65;
              white-space:pre;overflow-wrap:normal}

.todo{list-style:none;margin:22px 0 0;padding:0;display:grid;gap:14px;max-width:840px}
.todo li{position:relative;padding-left:34px;font-size:16px}
.todo li::before{content:"";position:absolute;left:0;top:.18em;width:19px;height:19px;
                 border-radius:5px;border:2px solid color-mix(in srgb,var(--prune) 50%,transparent);
                 background:var(--paper)}

/* --- pages legales ------------------------------------------------------- */
.doc{max-width:760px;margin:0 auto;padding:46px 22px 70px}
.doc h1{font-size:34px}
.doc h2{font-size:22px;margin-top:1.6em}
.doc p,.doc li{font-size:16px;color:var(--ink-soft)}

/* Sous 760 px, AUCUNE grille ne reste a deux colonnes. `.practice` manquait a
   l'appel : les cinq pratiques de la landing — la page ou arrive tout le
   trafic, majoritairement mobile — s'y ecrasaient en deux colonnes de 160 px.
   Le garde-fou de shoot_site.py mesure desormais les grilles a 390 px : une
   grille a plus d'une colonne y rend le build rouge, et cette regle ne peut
   donc plus etre oubliee par la suivante. */
/* --- telephone ----------------------------------------------------------- */
/* Une colonne veut dire PLEINE LARGEUR. Le premier correctif mobile avait bien
   ramene `.practice` a une colonne, mais la vignette restait posee a cote du
   texte dans la meme rangee : le resultat, sur un vrai iPhone, etait une
   colonne de prose a 55 % de la largeur avec un grand vide a cote — deux
   colonnes deguisees. Les zones nommees rendent l'ordre explicite :
   titre, verset, vignette, texte. Aucune alternance en mobile : elle ne dit
   plus rien quand tout est empile, et elle deplace le regard pour rien. */
@media(max-width:760px){
  .duo,.benefit{grid-template-columns:1fr}
  /* Aucune alternance en mobile : elle ne dit plus rien quand tout est empile,
     et elle mettrait l'image AVANT le titre de la raison qu'elle illustre. */
  .benefit:nth-child(even) .benefit__art,
  .benefit--art-first .benefit__art{order:0}
  .trust{grid-template-columns:1fr;gap:14px}
  /* `.rules` se replie deja seule (auto-fit, plancher 268 px). On l'ecrit
     quand meme : c'est la seule page ou arrive du trafic paye, et une regle
     qui depend d'un plancher se casse le jour ou l'on baisse le plancher. */
  .rules{grid-template-columns:1fr;gap:26px}
  .practice,.practice:nth-child(odd){grid-template-columns:1fr;
    grid-template-areas:"head" "art" "body";gap:14px}
  .practice__head,.practice__body{align-self:auto}
  .vignette{max-width:240px}
  .flip__row{grid-template-columns:1fr}
  .flip__ar{display:none}
  .note{grid-template-columns:1fr;justify-items:center;text-align:center}
  /* Le bloc d'autrice suit la note signee : portrait au-dessus, texte dessous,
     et le texte reste a gauche. Le centrer ferait de trois paragraphes une
     citation — la note du bas en fait un, celui-ci en fait trois. */
  .author{grid-template-columns:1fr;gap:16px}
  .author__id{justify-content:flex-start}
  /* Une colonne veut dire PLEINE LARGEUR : sous 760 px, deux colonnes de
     comparaison deviennent deux blocs empiles, jamais deux colonnes etroites. */
  .stuck{grid-template-columns:1fr;gap:16px}
  .stuck__col{padding:22px 18px 20px}
  /* La rangee d'avatars passe au-dessus du chiffre plutot qu'a cote : a 390 px,
     les trois elements de la barre sur une seule ligne donnent trois colonnes
     de 100 px, et la phrase se coupe en trois. */
  .proofbar{flex-direction:column;gap:12px}
  .proofbar__score{font-size:16px}
  .reviews__more>summary{font-size:15px;padding:12px 20px}
  .welcome{padding:26px 20px}
  .welcome__clock{font-size:38px}
  /* Plancher typographique : sur un telephone, une mention a 13 px se saute.
     Le corps est deja a 17 px ; ce sont les petites lignes qu'on releve. */
  .pay,.foot__legal,.foot,.optin__note,.fineprint,.trust li,
  .reviews__note,.peek__hint{font-size:15px}
  /* `:not()` parce que le titre d'une etape EST un `<p>` : sans lui, le
     plancher de 16 px devient un plafond pour lui — il gagne en specificite sur
     `.steps__t` (0,1,1 contre 0,1,0) et ramene le titre a la taille du corps.
     Une regle dont le commentaire dit « on releve les petites lignes » ne doit
     pas, au passage, ecraser les grandes. */
  .card__price,.practices,.faq p:not(.faq__q),.steps p:not(.steps__t),
  .card__note,.welcome-note{font-size:16px}
  /* La barre collante garde le logo et le bouton ; la phrase de promesse sort.
     A 390 px, les trois ensemble ne tiennent pas — et c'est le hero, juste
     dessous, qui porte la meme promesse en H1. */
  .lpbar__say{display:none}
  .lpbar__in{padding:6px 14px;gap:12px}
  .lpbar__cta{padding:0 16px;font-size:14px}
  .launch-note{font-size:15px}
}
