/* ═══════════════════════════════════════════════════════════════════════════
   Cabestian — pages de lecture suivie (/communaute/ et /communaute/field-notes/)
   ───────────────────────────────────────────────────────────────────────────
   Ces cinq pages viennent de la V2 (fond blanc, accent orange, polices Google).
   Elles sont référencées par les moteurs : on reprend l'habillage, jamais le texte
   ni les adresses. Cette feuille remplace les <style> embarqués de la V2 par le
   vocabulaire V4 (navy, crème, cashmere, bordeaux, General Sans / JetBrains Mono),
   et elle est partagée par les cinq pages : une seule source de vérité, un seul
   fichier en cache pour le lecteur qui enchaîne deux articles.

   Elle NE contient pas la nav : celle-ci vient de _shared/nav.css + nav.js
   (CabNav.init), comme sur mentions-legales.html.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
  --navy:#06121A; --navy2:#0C1825; --azurite:#1B2B41; --stalactite:#F7F6F4;
  --soft-titanium:#CFD0D4; --cashmere:#A5B8D0; --ruby:#63001F; --ruby-lite:#C0455E;
  /* --ruby-texte : le bordeaux clair ÉCLAIRCI pour le PETIT TEXTE sur fond sombre (audit du
     23/09, M16). #C0455E en 11 px mesurait 2,96 à 3,8:1 selon le fond, pour 4,5 requis.
     Même teinte (350°) et même saturation, luminosité HLS relevée de 13 points, le minimum
     qui passe partout : 4,57:1 sur l'azurite #1B2B41, 4,68 sur le fond le plus clair
     relevé sous un surtitre (#1B2A38), 6,05 sur le navy. #C0455E reste la couleur des
     aplats, filets, survols et contours de focus (3:1 suffisent hors texte).
     TRANCHÉ (audit du 24/09, lot 2) : les étiquettes des cartes translucides de droite
     (« Transcription locale », « Utilisez ») passaient sur la partie claire du fond animé,
     jusqu'à #364653, et y tombaient à 3,5:1. Décision de Maxime : panneau plus opaque,
     couleur de texte inchangée. --panel passe de .42 à .75 d'opacité et ses deux teintes
     glissent vers --navy2/--navy (au lieu de --azurite/--navy2) : mesuré sur pixels réels,
     4,78:1 dans le pire cas (contre 3,40 avant), le verre reste translucide (25 % du fond
     y percent toujours). */
  --ruby-texte:#D17789;
  --grad:linear-gradient(90deg,#9B1B3A 0%,#C0455E 42%,#A5B8D0 100%);
  /* --alu-ruby et --alu-inset sont exigés par _shared/nav.css (bouton Contact de la
     pill) : sans eux, le CTA perd son fond bordeaux et ne ressemble plus à un bouton. */
  --alu-ruby:linear-gradient(180deg,#8A0F35 0%,#63001F 52%,#4A0014 100%);
  --alu-inset:inset 0 1px 0 rgba(255,255,255,.22),inset 0 -1px 0 rgba(0,0,0,.4);
  --hair:rgba(165,184,208,.16);
  --panel:linear-gradient(180deg,rgba(12,24,37,.75),rgba(6,18,26,.75));
  --fd:'Archivo',system-ui,sans-serif; --fm:'JetBrains Mono',ui-monospace,monospace;
  /* gouttière unifiée avec le reste du site */
  --gut:clamp(22px,7vw,132px);
  /* Mesure de ligne, cible 65-75 caractères. Exprimée en rem et non en « ch » : le « ch »
     se résout avec la police de l'élément qui l'utilise, et l'article (1rem) n'a pas la
     même taille que son corps de texte (1,075rem) — la même déclaration donnait donc deux
     largeurs différentes. En rem, la mesure suit la taille de police choisie par le
     lecteur dans son navigateur, ce qui est le comportement souhaité.
     35,5rem = 568 px : 70 caractères par ligne, mesurés au navigateur. */
  --mesure:35.5rem;
  /* ─── Échelle typographique : neuf paliers, chacun à plus de 18 % du suivant ───
     Arbitrage du 03/08 (57 tailles rendues, 48 des 56 écarts sous 6 %, donc invisibles).
     Les paliers restent fluides entre parenthèses : la borne haute est le palier.
     Arbitrage laissé ouvert par la note, tranché ici PAR FAMILLE et non en bloc :
     la bande 17 à 18,6 px contenait à la fois des corps de texte et des TITRES de
     cartes dont le corps voisin est à 15-16. Tout écraser sur « base » aurait fait
     disparaître la hiérarchie de ces cartes. Les titres montent donc à « large »,
     les corps descendent à « base ». */
  --t-micro:11px;                        /* étiquettes mono capitales, fil d'Ariane */
  --t-petit:13px;                        /* notes, légendes, cellules denses */
  --t-base:16px;                         /* corps de texte */
  --t-large:clamp(17px,1.4vw,20px);      /* chapô, titre de carte */
  --t-lead:clamp(20px,2vw,25px);         /* phrase de tête */
  --t-t3:clamp(24px,2.6vw,32px);         /* titre de bloc */
  --t-t2:clamp(29px,3.2vw,40px);         /* titre de section */
  --t-t1:clamp(34px,4.4vw,52px);         /* titre de page */
  --t-hero:clamp(40px,5.6vw,68px);       /* titre d'accueil */

}

*{margin:0;padding:0;box-sizing:border-box}
html{background:var(--navy);-webkit-text-size-adjust:100%}
body{background:radial-gradient(120% 90% at 62% 0%, #16283A 0%, #0C1825 46%, #06121A 100%);
  color:var(--stalactite);font-family:var(--fd);-webkit-font-smoothing:antialiased;min-height:100vh;
  /* garde-fou : aucune de ces pages ne doit défiler horizontalement, quelle que soit
     la largeur. Les blocs larges (tableaux) scrollent dans leur propre conteneur. */
  overflow-x:hidden}
a{color:inherit;text-decoration:none}
img,svg{max-width:100%}

/* le calque réfracté du verre reste offscreen : ici le DOM EST le visuel, le canvas
   ne sert qu'à donner au shader une copie du fond à réfracter sous la pill. */
#glbg{position:fixed;inset:0;width:100%;height:100%;display:none}

/* grain : même texture que l'accueil, sinon les aplats paraissent morts à côté */
/* Fond peint en shader (_shared/fond.js), sous tout le reste.
   ─────────────────────────────────────────────────────────────────────────────
   Il reste MASQUE par defaut : le script ne l'affiche qu'une fois WebGL obtenu et
   la premiere image peinte. Sans WebGL il ne s'affiche donc jamais, et le degrade
   du body reste visible : aucun risque d'ecran noir.
   Le contenu de ces pages est deja en z-index 2, le grain en 9000 : ce fond se
   glisse dessous sans rien deranger. */
#cab-fond{position:fixed;inset:0;width:100%;height:100%;z-index:0;display:none;pointer-events:none}

.grain{position:fixed;inset:-60%;width:220%;height:220%;z-index:9000;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:180px 180px;animation:grain 1.2s steps(4) infinite}
@keyframes grain{0%{transform:translate(0,0)}25%{transform:translate(-3%,2%)}50%{transform:translate(2%,-3%)}
  75%{transform:translate(-2%,-2%)}100%{transform:translate(3%,3%)}}
@media (prefers-reduced-motion:reduce){.grain{animation:none}}

/* Indicateur de focus (repris de nav.css) : #C0455E = 3,84:1 sur le navy. */
:focus-visible{outline:2px solid var(--ruby-lite);outline-offset:3px;border-radius:3px}

/* Lien d'évitement : sur un article long, sauter la nav au clavier fait gagner
   une demi-douzaine de tabulations. Visible seulement au focus. */
.skip{position:absolute;left:-9999px;top:0;z-index:9999;font-family:var(--fm);font-size:var(--t-micro);
  padding:12px 18px;background:var(--navy2);border:1px solid var(--hair);border-radius:0 0 10px 0}
.skip:focus{left:0}

/* ═══════════ Fil d'Ariane ═══════════════════════════════════════════════════
   Il porte la hiérarchie des adresses (accueil › communauté › field notes › article),
   qui ne change pas : ces URL sont référencées.

   Contrastes relevés le 03/08 : les libellés à 62 % d'opacité donnaient 4,1:1 pour un corps
   de 11 px, sous le seuil de 4,5:1, et le séparateur à 30 % tombait à 1,9:1, soit invisible.
   Les opacités sont calculées contre #16283A, le point le PLUS CLAIR du dégradé de fond
   (son origine, en haut de page, exactement là où se trouve le fil d'Ariane) : c'est le pire
   cas. 78 % donne 4,95:1 pour les libellés, 58 % donne 3,38:1 pour le séparateur, seuil des
   éléments non textuels. Plus bas dans la page, le fond fonce et le rapport ne fait que
   monter. La teinte ne change pas. */
.breadcrumb{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.18em;text-transform:uppercase;
  color:rgba(165,184,208,.78)}
.breadcrumb ol{list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:.6rem}
.breadcrumb li{display:inline-flex;align-items:center;gap:.6rem}
.breadcrumb a{color:rgba(165,184,208,.78);transition:color .22s}
.breadcrumb a:hover{color:var(--stalactite)}
.breadcrumb [aria-current="page"]{color:var(--stalactite)}
.breadcrumb .sep{color:rgba(165,184,208,.58)}

/* ═══════════ ARTICLE : lecture suivie ═══════════════════════════════════════
   Colonne unique, centrée, bornée à --mesure. Le padding haut dégage la pill fixe. */
.article{max-width:calc(var(--mesure) + 2*var(--gut));margin:0 auto;
  padding:120px var(--gut) 0;position:relative;z-index:2}
.article > *{max-width:var(--mesure)}
.article .breadcrumb{margin-bottom:2.4rem}

.article__meta{display:flex;flex-wrap:wrap;gap:.5rem 1.4rem;align-items:center;font-family:var(--fm);
  font-size:var(--t-micro);letter-spacing:.16em;text-transform:uppercase;color:rgba(165,184,208,.62);margin-bottom:1.5rem}
.article__meta .accent{color:var(--ruby-texte)}
.article__meta .lien-auteur{text-decoration:underline;text-underline-offset:2px;text-decoration-color:rgba(165,184,208,.4)}
.article__meta .lien-auteur:hover{text-decoration-color:var(--ruby-texte)}
.article__title{font-weight:600;font-size:var(--t-t2);line-height:1.04;
  letter-spacing:-.028em;color:var(--stalactite)}
/* Chapô : plus grand que le corps, encre pleine, mesure raccourcie pour l'ancrer
   comme une accroche et non comme le début du texte. */
.article__lead{margin-top:1.7rem;font-size:var(--t-large);line-height:1.5;
  font-weight:500;letter-spacing:-.012em;color:var(--stalactite);max-width:44ch}
.article__divider{width:48px;height:2px;background:var(--grad);margin:2.8rem 0;border-radius:2px}

/* Corps. 1.075rem / 1.72 : l'interlignage long est ce qui fait tenir un article
   de 1 500 mots, davantage que la taille de police. */
.article__body{font-size:var(--t-base);line-height:1.72;color:var(--soft-titanium)}
.article__body p{margin-bottom:1.35rem}
.article__body p strong,.article__body li strong{font-weight:600;color:var(--stalactite)}
.article__body em{font-style:italic;color:var(--stalactite)}

/* Hiérarchie de titres nette : h2 séparé par un filet (on change de partie),
   h3 sans filet (on reste dans la même). L'œil doit distinguer les deux sans lire. */
.article__body h2{margin:3.2rem 0 1.1rem;padding-top:2rem;border-top:1px solid var(--hair);
  font-weight:600;font-size:var(--t-t3);line-height:1.16;letter-spacing:-.02em;
  color:var(--stalactite)}
.article__body h3{margin:2.2rem 0 .7rem;font-weight:600;font-size:var(--t-large);line-height:1.25;
  letter-spacing:-.012em;color:var(--stalactite)}
/* le premier h2 suit le filet du chapô : pas besoin d'un second trait */
.article__body > h2:first-child{margin-top:0;padding-top:0;border-top:none}

.article__body ul,.article__body ol{padding-left:1.35rem;margin-bottom:1.35rem}
.article__body li{margin-bottom:.62rem;line-height:1.65}
.article__body li::marker{color:var(--ruby-lite)}

/* Citation : filet bordeaux à gauche, comme le bloc « limites » des pages produit.
   Pas d'italique — nos polices n'ont pas de fonte italique auto-hébergée, un long
   passage en oblique synthétique se lit mal. */
.article__body blockquote{margin:2.4rem 0;padding:.2rem 0 .2rem 1.5rem;
  border-left:2px solid var(--ruby-lite);font-size:var(--t-large);line-height:1.5;font-weight:500;
  letter-spacing:-.012em;color:var(--stalactite);max-width:46ch}

.article__body code{font-family:var(--fm);font-size:.88em;padding:.12em .38em;
  background:rgba(192,69,94,.12);color:#E4A0AF;border-radius:4px;
  /* les identifiants techniques ne doivent pas casser la ligne n'importe où */
  word-break:break-word}

.article__body a{color:var(--stalactite);text-decoration:underline;text-underline-offset:3px;
  text-decoration-thickness:1px;text-decoration-color:rgba(192,69,94,.7);transition:text-decoration-color .22s}
.article__body a:hover{text-decoration-color:var(--ruby-lite)}

/* Tableau : il déborde forcément sur mobile, donc il défile DANS son conteneur —
   jamais la page. Le wrapper est ajouté au balisage, le texte reste intact. */
.article__body .tbl-wrap{overflow-x:auto;border:1px solid var(--hair);border-radius:14px;
  margin:1.8rem 0;-webkit-overflow-scrolling:touch}
.article__body table{width:100%;border-collapse:collapse;min-width:560px;font-size:var(--t-petit)}
.article__body th{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.16em;text-transform:uppercase;
  text-align:left;padding:14px 18px;border-bottom:1px solid var(--hair);white-space:nowrap;
  color:var(--cashmere);background:rgba(6,18,26,.42)}
.article__body td{padding:14px 18px;border-bottom:1px solid var(--hair);vertical-align:top;
  line-height:1.5;color:var(--soft-titanium)}
.article__body tr:last-child td{border-bottom:none}
.article__body td strong{color:var(--stalactite);font-weight:600}
/* Sous 760 px, le tableau de 560 px défilait (dans 333 px à 390 de large), sans indice : la
   colonne « Outil open source », celle qui porte le message, restait hors champ (audit du
   24/09, lot 2 — même défaut, même traitement que les pages produits, commit b836211). La
   couche passe au-dessus de sa ligne, sur toute la largeur, et les deux colonnes de contenu
   se lisent côte à côte sous leurs en-têtes, qui restent en tête du tableau. Plus de
   défilement horizontal caché. Tableau générique (pas de classes .crit/.now/.ours comme
   table.cmp) : on cible par position, 1re colonne = étiquette de ligne. */
@media (max-width:759px){
  .article__body .tbl-wrap{overflow-x:visible}
  .article__body table{min-width:0;display:block}
  .article__body table thead,.article__body table tbody{display:block}
  .article__body table tr{display:grid;grid-template-columns:1fr 1fr}
  .article__body table thead th:first-child{display:none}
  .article__body table th{white-space:normal;padding:13px 14px;letter-spacing:.12em}
  .article__body table td{padding:6px 14px 14px}
  .article__body table tbody td:first-child{grid-column:1/-1;white-space:normal;
    padding:14px 14px 2px;border-bottom:none}
  .article__body table th:nth-child(2),.article__body table td:nth-child(2){border-left:1px solid var(--hair)}
}

.article__footer{margin-top:4rem;padding:2.2rem 0 0;border-top:1px solid var(--hair);
  display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;
  font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.16em;text-transform:uppercase;
  color:rgba(165,184,208,.62)}
.article__back{color:var(--cashmere);transition:color .22s}
.article__back:hover{color:var(--stalactite)}

@media (max-width:640px){.article{padding-top:100px}}

/* ═══════════ EN-TÊTE DES PAGES D'INDEX ══════════════════════════════════════ */
/* La gouttière s'AJOUTE à la largeur utile (calc(1180px + 2*--gut)) : posée sur le même
   élément qu'un max-width de 1180px, elle se serait retranchée du contenu, qui n'aurait
   plus fait que 978 px sur grand écran — les grilles tombaient alors à deux colonnes. */
.page-hero{max-width:calc(1180px + 2*var(--gut));margin:0 auto;padding:120px var(--gut) 3.2rem;
  position:relative;z-index:2}
.page-hero .breadcrumb{margin-bottom:2.4rem}
.page-hero__eyebrow{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.22em;text-transform:uppercase;
  color:var(--cashmere);margin-bottom:1.4rem;display:flex;align-items:center;gap:14px}
.page-hero__eyebrow::before{content:'';width:34px;height:2px;background:var(--grad);flex:none}
.page-hero__title{font-weight:600;font-size:var(--t-t1);line-height:1.02;
  letter-spacing:-.028em;max-width:17ch}
.page-hero__sub{margin-top:1.5rem;max-width:52ch;font-size:var(--t-large);
  line-height:1.55;color:var(--soft-titanium)}
@media (max-width:640px){.page-hero{padding-top:100px}}

/* ═══════════ INDEX FIELD NOTES : la liste d'articles ════════════════════════ */
.fn-list{max-width:calc(1180px + 2*var(--gut));margin:0 auto;padding:0 var(--gut) 9vh;
  position:relative;z-index:2}
/* Grille date | corps | flèche. La date en colonne fixe donne un rythme de sommaire ;
   sous 760 px elle repasse au-dessus du titre plutôt que d'écraser le texte. */
.fn-item{display:grid;grid-template-columns:132px minmax(0,1fr) auto;gap:1.6rem;align-items:baseline;
  padding:2rem 0;border-top:1px solid var(--hair);transition:padding-left .35s cubic-bezier(.16,1,.3,1)}
.fn-item:last-of-type{border-bottom:1px solid var(--hair)}
.fn-item:hover{padding-left:.8rem}
.fn-item:hover .fn-item__title{color:var(--stalactite)}
.fn-item__date{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.16em;text-transform:uppercase;
  color:rgba(165,184,208,.62)}
.fn-item__body{display:flex;flex-direction:column;gap:.55rem;min-width:0}
.fn-item__title{font-weight:600;font-size:var(--t-large);letter-spacing:-.018em;line-height:1.2;
  color:var(--stalactite);transition:color .22s}
/* 56ch ≈ 68 caractères rendus : même confort de lecture que le corps des articles.
   À 62ch la ligne montait à 76 caractères sur grand écran (mesuré). */
.fn-item__excerpt{font-size:var(--t-base);color:var(--soft-titanium);line-height:1.6;max-width:56ch}
.fn-item__tags{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:.3rem}
.fn-item__tag{font-family:var(--fm);font-size:var(--t-micro);
  color:var(--cashmere);padding:.28rem .6rem;border:1px solid var(--hair);border-radius:999px}
.fn-item__arrow{color:rgba(165,184,208,.5);transition:color .22s,transform .35s cubic-bezier(.16,1,.3,1)}
.fn-item:hover .fn-item__arrow{color:var(--ruby-lite);transform:translateX(4px)}
.fn-item__arrow svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round}
.fn-empty{padding:3rem 0;text-align:center;color:rgba(165,184,208,.5);font-family:var(--fm);
  font-size:var(--t-petit);letter-spacing:.16em;text-transform:uppercase}
@media (max-width:760px){
  .fn-item{grid-template-columns:1fr auto;gap:.5rem 1rem;padding:1.6rem 0}
  .fn-item__date{grid-column:1/-1}
  .fn-item__arrow{align-self:center}
}

/* ═══════════ PAGE COMMUNAUTÉ : sections ═════════════════════════════════════
   Structure « étiquette à gauche, contenu à droite » : c'est le motif d'un dossier
   technique, pas d'une plaquette. Sous 900 px l'étiquette repasse au-dessus. */
.page-body{max-width:calc(1180px + 2*var(--gut));margin:0 auto;padding:0 var(--gut) 4vh;
  position:relative;z-index:2}
.csec{display:grid;grid-template-columns:170px minmax(0,1fr);gap:clamp(24px,4vw,54px);
  padding:clamp(46px,7vh,84px) 0;border-top:1px solid var(--hair)}
.csec:first-child{border-top:none;padding-top:0}
.csec-label{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.22em;text-transform:uppercase;
  color:var(--ruby-texte);padding-top:.4rem}
.csec-title{font-weight:600;font-size:var(--t-t3);line-height:1.1;
  letter-spacing:-.024em;margin-bottom:1.2rem}
.csec-title .accent{color:var(--cashmere)}
.csec-lead{font-size:var(--t-base);line-height:1.6;color:var(--soft-titanium);max-width:54ch}
.csec-lead + .csec-lead{margin-top:.9rem}
@media (max-width:900px){
  .csec{grid-template-columns:1fr;gap:1.4rem}
  .csec-label{padding-top:0}
}
/* une section peut contenir deux blocs (texte + grille) : ils s'empilent dans la
   colonne de droite au lieu de créer une troisième colonne */
.csec > * + *{min-width:0}
.csec > div + div,.csec > .cos-grid,.csec > .cos-vs-grid,.csec > .cos-tool-grid{grid-column:2}
@media (max-width:900px){
  .csec > div + div,.csec > .cos-grid,.csec > .cos-vs-grid,.csec > .cos-tool-grid{grid-column:1}
}

/* — programmes — */
/* 230 px : le seuil qui donne 4 colonnes sur grand écran (une seule rangée, pas de
   quatrième carte orpheline) et 2×2 sur tablette. */
.cprog{display:grid;gap:2px;border:1px solid var(--hair);border-radius:16px;overflow:hidden;
  background:var(--hair);grid-template-columns:repeat(auto-fit,minmax(min(100%,230px),1fr))}
.cprog-card{background:var(--panel);padding:28px 26px;min-width:0;display:flex;flex-direction:column}
.cprog-card__eyebrow{font-family:var(--fm);font-size:var(--t-micro);
  color:rgba(165,184,208,.55);margin-bottom:14px}
.cprog-card__title{font-weight:600;font-size:var(--t-large);letter-spacing:-.012em;line-height:1.22}
.cprog-card__body{margin-top:11px;font-size:var(--t-base);line-height:1.55;color:var(--soft-titanium)}
.cprog-card__meta{margin-top:auto;padding-top:16px;font-family:var(--fm);font-size:var(--t-micro);
  letter-spacing:.16em;text-transform:uppercase;color:rgba(165,184,208,.5)}
/* la carte « Cercle » porte un disclosure au lieu d'un bouton de modale : il se colle
   en bas comme la mention des autres cartes, pour que les quatre s'alignent */
.cprog-card__more{margin-top:auto}

/* — briques opensource : le détail est un <details> natif, pas une modale.
     Une modale n'existe qu'avec JavaScript ; ici tout le texte est dans la page,
     lisible et navigable au clavier même script désactivé. — */
/* pas de margin-top : ces grilles sont des lignes de la grille .csec, l'écart vient
   déjà du `gap` de la section — le cumul des deux creusait un trou. */
.cos-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr))}
.cos-card{border:1px solid var(--hair);border-radius:16px;background:var(--panel);
  padding:26px 24px;min-width:0;transition:border-color .25s,transform .35s cubic-bezier(.16,1,.3,1)}
.cos-card:hover{border-color:rgba(165,184,208,.34);transform:translateY(-2px)}
.cos-card__icon{width:38px;height:38px;color:var(--cashmere);margin-bottom:18px}
.cos-card__icon svg{width:100%;height:100%;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
.cos-card__tag{font-family:var(--fm);font-size:var(--t-micro);
  color:var(--ruby-texte);display:block;margin-bottom:9px}
.cos-card__name{font-weight:600;font-size:var(--t-large);letter-spacing:-.012em;line-height:1.25}
.cos-card__why{margin-top:10px;font-size:var(--t-base);line-height:1.55;color:var(--soft-titanium)}

/* disclosure natif : le triangle par défaut est remplacé par un « + » qui pivote */
/* Le pied se colle en bas de carte. Sans flex-direction, il suivait le corps : dès qu'un
   titre passait à deux lignes (« Obsidian (Community plugins) », « Site document
   management » en anglais), le lien du bas tombait 25px plus bas que celui de ses deux
   voisines, à hauteur de carte pourtant identique. */
.cos-card,.cos-tool-card{display:flex;flex-direction:column}
.cos-card .cos-more,.cos-tool-card .cos-more{margin-top:auto}
/* margin-top:16px écrasait le margin-top:auto de .cprog-card__more (même spécificité, plus
   bas dans la feuille), ce que le commentaire de cette règle-là voulait précisément éviter. */
.cprog-card .cos-more{margin-top:auto}
.cos-more{margin-top:16px;border-top:1px solid var(--hair);padding-top:14px}
.cos-more > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:10px;
  font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.18em;text-transform:uppercase;
  color:var(--cashmere);transition:color .22s}
.cos-more > summary::-webkit-details-marker{display:none}
.cos-more > summary:hover{color:var(--stalactite)}
.cos-more > summary::after{content:'+';font-size:var(--t-petit);line-height:1;color:var(--ruby-lite);
  margin-left:auto;transition:transform .25s cubic-bezier(.16,1,.3,1)}
.cos-more[open] > summary::after{transform:rotate(45deg)}
.cos-more__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.cos-more__meta span{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.1em;padding:6px 11px;
  border:1px solid var(--hair);border-radius:7px;color:rgba(165,184,208,.72)}
.cos-more__detail p{margin-top:13px;font-size:var(--t-base);line-height:1.6;color:var(--soft-titanium)}
.cos-more__links{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
.cos-more__links a{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.14em;text-transform:uppercase;
  padding:9px 14px;border-radius:8px;border:1px solid var(--hair);color:var(--cashmere);
  display:inline-flex;align-items:center;gap:8px;transition:border-color .22s,color .22s}
.cos-more__links a:hover{border-color:rgba(165,184,208,.4);color:var(--stalactite)}
.cos-more__links svg{width:13px;height:13px;fill:currentColor}

/* — « au lieu de X, utilisez Y » — */
/* 400 px : ces cartes portent DEUX colonnes de texte (le SaaS, l'alternative). En dessous,
   les noms de produits se cassaient sur trois lignes et la comparaison devenait illisible. */
.cos-vs-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(100%,400px),1fr))}
.cos-vs-card{display:grid;grid-template-columns:minmax(0,1fr) 30px minmax(0,1fr);align-items:center;
  gap:10px;border:1px solid var(--hair);border-radius:16px;background:var(--panel);padding:22px 20px}
.cos-vs-card__side{min-width:0;display:flex;flex-direction:column;gap:7px}
.cos-vs-card__label{font-family:var(--fm);font-size:var(--t-micro);
  color:rgba(165,184,208,.5)}
.cos-vs-card__side--alt .cos-vs-card__label{color:var(--ruby-texte)}
.cos-vs-card__name{font-weight:600;font-size:var(--t-base);line-height:1.25;letter-spacing:-.01em}
/* le SaaS remplacé est atténué : la lecture doit tomber sur l'alternative */
.cos-vs-card__side--saas .cos-vs-card__name{color:rgba(207,208,212,.72)}
.cos-vs-card__note{font-size:var(--t-petit);line-height:1.45;color:rgba(165,184,208,.62)}
.cos-vs-card__arrow{color:var(--ruby-lite)}
.cos-vs-card__arrow svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
@media (max-width:420px){
  .cos-vs-card{grid-template-columns:1fr;gap:14px}
  .cos-vs-card__arrow{transform:rotate(90deg)}
}

/* — boîte à outils par usage — */
.cos-tool-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(100%,270px),1fr))}
.cos-tool-card{border:1px solid var(--hair);border-radius:16px;background:var(--panel);
  padding:26px 24px;min-width:0}
.cos-tool-card__icon{width:34px;height:34px;color:var(--cashmere);margin-bottom:16px}
.cos-tool-card__icon svg{width:100%;height:100%;fill:none;stroke:currentColor;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round}
.cos-tool-card__cat{font-family:var(--fm);font-size:var(--t-micro);
  color:rgba(165,184,208,.55);margin-bottom:8px}
.cos-tool-card__title{font-weight:600;font-size:var(--t-large);letter-spacing:-.012em;line-height:1.25}
.cos-tool-card__list{list-style:none;margin-top:14px;display:grid;gap:9px}
.cos-tool-card__list li{font-size:var(--t-base);line-height:1.5;color:var(--soft-titanium);
  padding-left:14px;position:relative}
.cos-tool-card__list li::before{content:'';position:absolute;left:0;top:.62em;width:5px;height:1px;
  background:var(--ruby-lite)}
.cos-tool-card__list strong{color:var(--stalactite);font-weight:600}

/* — projets ouverts — */
.cproj{margin-top:1.8rem;border-top:1px solid var(--hair)}
.cproj-row{display:grid;grid-template-columns:170px minmax(0,1fr) auto;gap:1.4rem;align-items:baseline;
  padding:20px 0;border-bottom:1px solid var(--hair)}
.cproj-row__num{font-family:var(--fm);font-size:var(--t-micro);
  color:rgba(165,184,208,.55)}
.cproj-row__name{font-weight:600;font-size:var(--t-large);letter-spacing:-.012em;display:block}
.cproj-row__sub{margin-top:7px;font-size:var(--t-base);line-height:1.55;color:var(--soft-titanium);max-width:56ch}
.cproj-row__status{font-family:var(--fm);font-size:var(--t-micro);
  color:var(--cashmere);border:1px solid var(--hair);border-radius:999px;padding:.3rem .7rem;white-space:nowrap}
.cproj-row__status--soon{color:rgba(165,184,208,.5)}
.cproj-note{margin-top:1.5rem;font-size:var(--t-base);line-height:1.6;color:rgba(165,184,208,.72);max-width:56ch}
@media (max-width:760px){
  .cproj-row{grid-template-columns:1fr auto;gap:.5rem 1rem}
  .cproj-row__num{grid-column:1/-1}
}

/* — comment participer — */
.cstep{display:grid;gap:2px;margin-top:1.8rem;border:1px solid var(--hair);border-radius:16px;
  overflow:hidden;background:var(--hair);grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}
.cstep-item{background:var(--panel);padding:28px 26px;min-width:0}
.cstep-item__num{font-family:var(--fm);font-size:var(--t-micro);
  color:rgba(165,184,208,.55);margin-bottom:14px}
.cstep-item__title{font-weight:600;font-size:var(--t-large);letter-spacing:-.012em;line-height:1.22}
.cstep-item__body{margin-top:10px;font-size:var(--t-base);line-height:1.55;color:var(--soft-titanium)}

/* — appel final — */
.ccta{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:28px;
  padding:clamp(34px,5vh,52px) clamp(26px,4vw,44px);margin:clamp(46px,7vh,84px) 0 9vh;
  border:1px solid var(--hair);border-radius:20px;background:var(--panel)}
.ccta__title{font-weight:600;font-size:var(--t-t3);letter-spacing:-.024em;line-height:1.1}
.ccta__title .accent{color:var(--cashmere)}
.ccta__sub{margin-top:11px;font-size:var(--t-base);line-height:1.55;color:var(--soft-titanium);max-width:46ch}
.ccta__actions{display:flex;flex-wrap:wrap;align-items:center;gap:18px}
.ccta__btn{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.12em;text-transform:uppercase;
  padding:15px 26px;border-radius:10px;background:var(--alu-ruby);color:var(--stalactite);
  box-shadow:var(--alu-inset);transition:transform .16s cubic-bezier(.16,1,.3,1)}
.ccta__btn:active{transform:scale(.97)}
.ccta__link{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.1em;color:var(--cashmere);
  transition:color .22s}
.ccta__link:hover{color:var(--stalactite)}

/* ═══════════ Pied de page commun ═══════════════════════════════════════════ */
.foot{max-width:calc(1180px + 2*var(--gut));margin:0 auto;padding:5vh var(--gut) 7vh;
  border-top:1px solid var(--hair);
  display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:18px;
  position:relative;z-index:2}
.foot a{font-family:var(--fm);font-size:var(--t-micro);letter-spacing:.1em;color:var(--cashmere);transition:color .22s}
.foot a:hover{color:var(--stalactite)}

/* ═══════════ Révélation au scroll ══════════════════════════════════════════
   Le masquage est porté par .armed, que SEUL le script pose. Sans JavaScript,
   .rv reste donc pleinement visible. Écrit dans l'autre sens (masquer en CSS,
   révéler en JS), une page entière devenait invisible sans script — le défaut
   exact corrigé sur les pages champ le 30/07. */
.rv.armed{opacity:0;transform:translateY(16px)}
.rv.armed.in{opacity:1;transform:none;
  transition:opacity .7s cubic-bezier(.16,1,.3,1),transform .7s cubic-bezier(.16,1,.3,1)}
@media (prefers-reduced-motion:reduce){
  .rv,.rv.armed,.rv.armed.in{opacity:1!important;transform:none!important;transition:none}
  .fn-item,.cos-card{transition:none}
}

/* Équilibre des titres et des paragraphes.
   ─────────────────────────────────────────────────────────────────────────────
   Même règle que _shared/cards.css et _shared/champ.css, où elle avait été posée le
   03/08 contre les titres dont le dernier mot tombe seul sur une ligne. Cette
   feuille-ci ne l'avait jamais reçue : le titre de la note 001 laissait « US. »
   seul, et rien ne le corrigeait. */
h1,h2,h3,h4,.article__title,.page-hero__title,.csec-title,.ccta__title,
.fn-item__title,.cprog-card__title,.cos-card__name,.cos-tool-card__title,
.cproj-row__name,.cstep-item__title{text-wrap:balance}
p,li,.article__lead,.page-hero__sub,.csec-lead,.fn-item__excerpt,
.cos-card__why,.cprog-card__body,.cproj-row__sub,.cstep-item__body{text-wrap:pretty}
