/* ==========================================================================
   PipeLinker Hub - site vitrine · palette LOOT-US
   Thème clair unique, assumé. Aucune dépendance externe.

   Les blocs de code gardent un fond sombre : c'est ce qu'un terminal est, et
   c'est aussi ce qui donne au texte coloré le contraste qu'un fond blanc lui
   retire. Ils redéfinissent les jetons localement plutôt que de porter leurs
   propres couleurs, pour rester une seule liste à tenir.
   ========================================================================== */

:root {
  /* Palette
     #E8701A orange (primaire) · #003B56 bleu profond (secondaire)
     #E2E0E0 et #CDCCCC gris (secondaire) · #C42726 rouge (erreur seule)

     L'orange et le bleu sont complémentaires : le bleu tire vers 199 degrés de
     teinte, l'orange vers 25. C'est ce qui les fait tenir ensemble sans qu'aucun
     des deux ne soit délavé pour laisser passer l'autre. */
  --orange:      #E8701A;
  --bleu:        #003B56;
  --gris:        #E2E0E0;
  --gris-fonce:  #CDCCCC;
  --rouge:       #C42726;

  --bg:          #FFFFFF;
  --bg-alt:      #F7F6F5;
  --surface:     #FFFFFF;
  --surface-2:   #F2F1F0;
  --border:      var(--gris-fonce);
  --border-soft: var(--gris);

  /* Le texte est bleu profond plutôt que noir : sur un fond blanc il porte la
     marque à chaque ligne, sans rien coûter en lisibilité - il tient douze
     contre un. */
  --text:        var(--bleu);
  --text-muted:  #4A6472;
  --text-dim:    #7A8D97;

  /* **L'orange de la marque est assombri pour tout ce qui porte du texte.**
     #E8701A sur blanc tient trois contre un, ce qui ne suffit ni à un lien ni à
     un bouton ; #BC5510 tient quatre virgule sept, mesuré et non estimé. La
     teinte est la même, seule la luminosité change.

     L'orange vif ne sert donc qu'aux lueurs et au dégradé du titre, où rien ne
     s'écrit dessus. Deux autres pistes ont été essayées et écartées : un orange
     clair puis un saumon, tous deux avec du bleu nuit écrit dessus - la seule
     façon de garder une teinte claire sans passer sous le seuil, et un rendu qui
     n'a pas convenu. */
  --accent:      #BC5510;
  --accent-lit:  #9C4409;
  --accent-2:    var(--bleu);
  --accent-3:    var(--orange);
  --on-accent:   #FFFFFF;

  /* Conservé pour ce qui ne peut être qu'une erreur : un champ refusé, un
     message qui n'est pas parti. Une couleur qui ne sert qu'à cela reste lue
     comme telle. */
  --loot-red:    var(--rouge);

  --radius:      14px;
  --radius-sm:   9px;
  /* La largeur du contenu.
     Elle a valu 1140 puis 1320 px, ce qui laissait encore de la place inutilisée
     sur un écran large. Les grilles - fonctions, protocoles, calculateur - y gagnent
     une respiration ; le texte suivi, lui, garde sa propre largeur plus bas,
     une ligne trop longue se relisant mal. */
  --wrap:        1440px;

  /* Sur un 1920, 1440 laissait deux cent quarante pixels morts de chaque côté.
     La largeur utile monte donc avec l'écran, mais par paliers et non en
     pourcentage : un en-tête qui suit le bord fatigue, et les colonnes de
     texte, elles, ne s'élargissent pas pour autant. */
  --rail:        0px;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* `clip` et non `hidden` : `hidden` fait du corps un conteneur de
     défilement, et un élément collant à l'intérieur cesse de coller - il n'a
     plus d'ancêtre qui défile vraiment. Le sommaire d'article glissait avec la
     page au lieu de rester en vue. Les deux coupent le débordement latéral de
     la même façon. */
  overflow-x: clip;
}

img, svg { max-width: 100%; }
a { color: inherit; }

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: 24px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--accent); color: var(--on-accent);
  padding: 10px 16px; border-radius: var(--radius-sm);
  font-weight: 650; text-decoration: none;
  transition: top .18s ease;
}
.skip-link:focus { top: 12px; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ── Header ──────────────────────────────────────────────────────────── */

.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .25s ease, background .25s ease;
}
.site-header.is-stuck { border-bottom-color: var(--border-soft); }

.header-inner {
  display: flex; align-items: center; gap: 24px;
  min-height: 68px;
}

.brand {
  display: inline-flex; align-items: center; gap: 10px;
  color: var(--accent);
  text-decoration: none;
  font-weight: 700;
  letter-spacing: -.01em;
}
/* **La marque, et non plus un « P » dessiné à la main.** Le symbole n'est pas
   carré : il est plus haut que large, et lui imposer 30 par 30 l'aurait écrasé.
   La largeur est posée, la hauteur suit. */
.brand-mark { width: 30px; height: auto; flex: none; }
.brand-text { color: var(--text); font-size: 1.06rem; }

.nav {
  margin-left: auto;
  display: flex; align-items: center; gap: 28px;
}
.nav a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: .95rem;
  transition: color .18s ease;
}
.nav a:hover { color: var(--text); }
.nav a.btn { color: var(--on-accent); }
/* Le bouton de langue : deux lettres dans un cadre, à part du menu. Il mène
   à la même page dans l'autre langue, ou à l'accueil de l'autre langue. */
.nav a.nav-langue {
  font-family: var(--mono); font-size: .74rem; font-weight: 700; letter-spacing: .08em;
  padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px;
  color: var(--text-muted);
}
.nav a.nav-langue:hover { border-color: var(--accent); color: var(--text); }
.nav a.nav-langue::after { display: none; }

/* Le trait du menu, au survol et sur la page courante.

   **Le même pseudo-élément pour les deux**, et deux intensités : un trait qui
   se déploie sous l'entrée survolée, plein sous celle où l'on est. Deux
   mécanismes différents auraient fini par se décaler d'un pixel.

   Il vit sur un pseudo-élément plutôt que sur une bordure : une bordure
   décalerait le libellé au moment où elle paraît, et toute la barre bougerait
   au survol. Et il se déploie par `scaleX` depuis la gauche - une largeur
   animée déclencherait une mise en page à chaque image. */
.nav a:not(.btn) { position: relative; }
.nav a:not(.btn)::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -7px;
  height: 2px; border-radius: 2px;
  background: color-mix(in srgb, var(--accent) 55%, transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .18s ease;
}
.nav a:not(.btn):hover::after,
.nav a:not(.btn):focus-visible::after { transform: scaleX(1); }

/* La page courante garde le trait plein : survoler une autre entrée ne doit
   jamais faire croire qu'on a changé de page. */
.nav a.is-current:not(.btn) { color: var(--text); }
.nav a.is-current:not(.btn)::after {
  background: var(--accent);
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .nav a:not(.btn)::after { transition: none; }
}

.nav-toggle {
  display: none;
  margin-left: auto;
  width: 42px; height: 42px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block; width: 17px; height: 1.8px;
  background: var(--text); border-radius: 2px;
  margin-inline: auto;
  transition: transform .22s ease, opacity .22s ease;
}
.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before, .nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after  { top:  6px; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after  { transform: translateY(-6px) rotate(-45deg); }

/* ── Boutons ─────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 13px 24px;
  border-radius: 999px;
  font-weight: 620; font-size: .97rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform .16s ease, background .18s ease, border-color .18s ease;
  white-space: nowrap;
}
.btn-sm { padding: 9px 18px; font-size: .9rem; }
.btn-primary {
  background: var(--accent); color: var(--on-accent);
}
.btn-primary:hover { background: var(--accent-lit); transform: translateY(-1px); }
.btn-ghost {
  border-color: var(--border);
  color: var(--text);
  background: transparent;
}
.btn-ghost:hover { border-color: #4C4C46; background: var(--surface); transform: translateY(-1px); }

@media (prefers-reduced-motion: reduce) {
  .btn:hover { transform: none; }
}

/* ── Hero ────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  padding: clamp(72px, 12vw, 140px) 0 clamp(64px, 9vw, 108px);
  overflow: hidden;
  border-bottom: 1px solid var(--border-soft);
  background:
    linear-gradient(180deg, rgba(232,112,26,.07), transparent 55%),
    radial-gradient(1px 1px at 20% 30%, rgba(0,59,86,.18), transparent),
    radial-gradient(1px 1px at 70% 15%, rgba(0,59,86,.13), transparent),
    var(--bg);
}
.hero::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(var(--border-soft) 1px, transparent 1px),
    linear-gradient(90deg, var(--border-soft) 1px, transparent 1px);
  background-size: 68px 68px;
  mask-image: radial-gradient(ellipse 90% 62% at 50% 0%, #000 20%, transparent 78%);
  opacity: .5;
  pointer-events: none;
}
.hero-glow {
  position: absolute; top: -320px; left: 50%; translate: -50% 0;
  width: 900px; height: 620px;
  background: radial-gradient(circle, rgba(232,112,26,.20), transparent 62%);
  filter: blur(30px);
  pointer-events: none;
}
.hero-inner { position: relative; text-align: center; }

.eyebrow {
  margin: 0 0 14px;
  font-family: var(--mono);
  font-size: .78rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
}

h1 {
  margin: 0 0 22px;
  font-size: clamp(2.3rem, 6vw, 4rem);
  line-height: 1.08;
  letter-spacing: -.035em;
  font-weight: 720;
}
.grad {
  background: linear-gradient(100deg, var(--accent) 10%, var(--accent-2) 90%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

.lead {
  margin: 0 auto 34px;
  max-width: 660px;
  font-size: clamp(1.02rem, 1.6vw, 1.18rem);
  color: var(--text-muted);
}
.lead-2 {
  margin-top: -18px;
  font-size: 1rem;
  color: var(--text-dim);
  max-width: 620px;
}
.lead em, .split-text em, .card em, figcaption em { color: var(--text); font-style: italic; }

.hero-actions {
  display: flex; flex-wrap: wrap; gap: 14px; justify-content: center;
}

.hero-chips {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  list-style: none; margin: 42px 0 0; padding: 0;
}
.hero-chips li {
  font-family: var(--mono); font-size: .8rem;
  color: var(--text-dim);
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 7px 14px; border-radius: 999px;
}

/* ── Sections ────────────────────────────────────────────────────────── */

.section { padding: clamp(64px, 9vw, 108px) 0; }
.section-alt { background: var(--bg-alt); border-block: 1px solid var(--border-soft); }

.section-head { max-width: 680px; margin: 0 0 52px; }
.section-head .eyebrow { margin-bottom: 12px; }

.h2 {
  margin: 0 0 16px;
  font-size: clamp(1.65rem, 3.4vw, 2.4rem);
  line-height: 1.16;
  letter-spacing: -.028em;
  font-weight: 700;
}
.section-sub { margin: 0; color: var(--text-muted); }

/* ── Split (texte + visuel) ──────────────────────────────────────────── */

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 68px);
  align-items: center;
}
.split-reverse .split-text { order: 2; }
.split-text p { color: var(--text-muted); }
.split-text strong { color: var(--text); font-weight: 640; }
.split-text > :first-child { margin-top: 0; }

.ticks { list-style: none; padding: 0; margin: 26px 0 0; }
.ticks li {
  position: relative;
  padding-left: 30px;
  margin-bottom: 11px;
  color: var(--text-muted);
}
.ticks li::before {
  content: "";
  position: absolute; left: 4px; top: .62em;
  width: 9px; height: 5px;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}

.link-arrow {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  padding-bottom: 1px;
}
.link-arrow::after { content: " →"; }
.link-arrow:hover { border-bottom-color: var(--accent); }

/* ── Flow (agent → serveur) ──────────────────────────────────────────── */

.flowcard {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 34px 28px;
  text-align: center;
}
.flow-node {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 16px;
  background: var(--surface-2);
}
.flow-server { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.flow-label { display: block; font-weight: 640; }
.flow-sub {
  display: block;
  font-family: var(--mono); font-size: .76rem; color: var(--text-dim);
  margin-top: 3px;
}
.flow-arrow {
  position: relative;
  height: 78px;
  display: grid; place-items: center;
}
.flow-arrow-line {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 2px; translate: -50% 0;
  background: linear-gradient(180deg, var(--border), var(--accent));
}
.flow-arrow-line::after {
  content: "";
  position: absolute; bottom: -1px; left: 50%; translate: -50% 0;
  border: 6px solid transparent;
  border-top-color: var(--accent);
}
.flow-arrow-tag {
  position: relative;
  background: var(--surface);
  padding: 4px 12px;
  font-family: var(--mono); font-size: .74rem;
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px;
}

/* ── Cartes ──────────────────────────────────────────────────────────── */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 30px 26px;
  transition: border-color .22s ease, transform .22s ease;
}
.card:hover { border-color: #4C4C46; transform: translateY(-2px); }
.card h3 {
  margin: 0 0 10px;
  font-size: 1.12rem;
  letter-spacing: -.015em;
}
.card p { margin: 0; color: var(--text-muted); font-size: .965rem; }

.card-icon {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 11px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 24%, transparent);
  margin-bottom: 18px;
}
.card-icon svg {
  width: 21px; height: 21px;
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.card-icon svg .fill { fill: var(--accent); stroke: none; }

@media (prefers-reduced-motion: reduce) {
  .card:hover { transform: none; }
}

@media (min-width: 1800px) { :root { --wrap: 1560px; } }

/* ── Page article ────────────────────────────────────────────────────── */

.article { padding: clamp(52px, 8vw, 92px) 0 clamp(64px, 9vw, 108px); }
/* La colonne de texte suivi.
   Elle reste étroite : une ligne trop longue se relit mal, et l'oeil perd le
   début de la suivante. 820 px à 17 px font environ quatre-vingt-cinq signes,
   la limite haute de ce qui se lit sans effort. */
.article-wrap { max-width: 820px; }

/* Ce qui n'est pas du texte suivi déborde la colonne.
   Un schéma large comprimé dans une colonne étroite pendant que mille pixels
   restent vides de chaque côté, c'est de la place perdue deux fois : il devient
   illisible, et l'écran ne sert à rien. La marge négative le recentre sur la
   largeur utile sans sortir de la page.

   **Les maquettes en sont exclues, et c'est la distinction qui compte.** Un
   schéma dessiné sur neuf cents unités gagne à être large ; une fenêtre imitée
   n'y gagne rien - étirée à onze cents pixels pour montrer une barre d'adresse
   et quatre lignes, elle a l'air gonflée, et ne ressemble plus à un navigateur. */
/* Le tableau d'exemples partageait cette règle ; il est parti avec le
   calculateur, et les cartes des offres ont pris sa place - quatre cartes dans
   une colonne de texte tiennent deux par deux et se lisent mal. */
/* Sur les tarifs, seules les cartes débordent : l'abonnement, les
   prestations et les notes revenaient à 1 120 px sous des paragraphes à 880,
   et la page se lisait à deux largeurs. */
.article .diagram,
.article .offers {
  --large: min(1120px, calc(100vw - 48px));
  width: var(--large);
  /* `max-width: 100%` est posé plus haut pour empêcher un débordement ; il
     écraserait cette largeur, d'où sa levée ici et ici seulement. */
  max-width: none;
  margin-left: calc(50% - var(--large) / 2);
}
/* ── Le sommaire, et la largeur qu'il libère ──────────────────────────────
   À 820 px sur un écran de 1920, la page occupait quarante-trois pour cent de
   ce qu'elle avait. Élargir la colonne aurait été le mauvais remède : à cette
   largeur, une ligne fait cent quarante signes et l'oeil perd le début de la
   suivante.

   La largeur se remplit donc par la structure. Le sommaire prend la marge
   gauche, la colonne de texte garde sa mesure, et ce qui n'est pas du texte
   suivi - schémas, exemples, appel à l'action - déborde vers la droite au lieu
   de déborder des deux côtés.

   `:has` est ce qui tient l'ensemble : sans JavaScript le sommaire n'est pas
   inséré, la règle ne s'applique pas, et la page reprend sa colonne centrée
   plutôt que de se décaler à droite d'une gouttière vide. */
.article-toc { display: none; }

/* L'en-tête est collant : sans cette marge, un titre rejoint par le sommaire
   se rangeait dessous, et l'on atterrissait sur la ligne suivante. La règle
   vaut pour toute cible d'ancre - une carte de la gamme visée depuis le menu
   arrivait coupée sous l'en-tête, et l'on ne voyait pas où l'on était. */
[id] { scroll-margin-top: 96px; }
.article-wrap > h2 { scroll-margin-top: 104px; }

@media (min-width: 1400px) {
  .article-wrap:has(.article-toc) {
    /* La grille prend la largeur utile, mais pas au-delà : à 1560 px la
       réserve de droite devenait plus large que le sommaire de gauche, et la
       colonne de texte cessait d'être au centre de l'écran. */
    max-width: min(var(--wrap), 1440px);
    margin-inline: auto;
    display: grid;
    /* La troisième colonne n'a pas de contenu propre : c'est la réserve dans
       laquelle les schémas s'étendent. */
    grid-template-columns: 236px minmax(0, 820px) minmax(0, 1fr);
    column-gap: 64px;
    align-content: start;
  }
  .article-wrap:has(.article-toc) > * { grid-column: 2; }

  .article-wrap:has(.article-toc) > .article-toc {
    display: block;
    grid-column: 1;
    /* Il couvre toute la hauteur de l'article, sans quoi le collant n'aurait
       que sa propre rangée pour glisser.

       **`span` et non `-1`.** Dans une grille dont les rangées sont toutes
       implicites, `-1` désigne la fin de la grille *explicite*, c'est-à-dire la
       première ligne : le sommaire tenait alors dans la seule rangée 1, qu'il
       gonflait à ses cinq cents pixels, et le titre de l'article était repoussé
       d'autant sous son surtitre. Les rangées ainsi créées en trop sont vides,
       donc hautes de zéro, et l'écart entre rangées est nul. */
    grid-row: 1 / span 200;
    align-self: start;
    position: sticky;
    top: 96px;
    max-height: calc(100vh - 128px);
    overflow-y: auto;
  }

  /* Déborder vers la droite, et non de part et d'autre : à gauche il n'y a
     plus de vide, il y a le sommaire. */
  .article-wrap:has(.article-toc) > .diagram,
  .article-wrap:has(.article-toc) > .offers {
    grid-column: 2 / -1;
    width: auto;
    max-width: none;
    margin-left: 0;
  }
}

.article-toc-tete {
  margin: 0 0 14px;
  font-size: .72rem;
  font-weight: 640;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.article-toc ol {
  margin: 0;
  padding: 0;
  list-style: none;
  border-left: 1px solid var(--border-soft);
}
.article-toc li { margin: 0; }
.article-toc a {
  display: block;
  padding: 7px 0 7px 16px;
  margin-left: -1px;
  border-left: 2px solid transparent;
  font-size: .855rem;
  line-height: 1.35;
  color: var(--text-muted);
  text-decoration: none;
}
.article-toc a:hover { color: var(--text); }
/* Le titre courant. Sur une page de douze sections, c'est la seule chose qui
   dise où l'on en est. */
.article-toc a.is-courant {
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: 560;
}


.article-title {
  margin: 0 0 20px;
  font-size: clamp(1.9rem, 4.4vw, 2.9rem);
  line-height: 1.14;
  letter-spacing: -.03em;
  font-weight: 700;
}
.article-chapo {
  margin: 0 0 44px;
  padding-bottom: 32px;
  border-bottom: 1px solid var(--border-soft);
  font-size: clamp(1.02rem, 1.6vw, 1.16rem);
  color: var(--text-muted);
}
.article h2 {
  margin: 46px 0 14px;
  font-size: clamp(1.35rem, 2.6vw, 1.7rem);
  letter-spacing: -.022em;
  line-height: 1.22;
}
.article h3 {
  margin: 32px 0 8px;
  font-size: 1.06rem;
  letter-spacing: -.012em;
}
.article h3::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px; border-radius: 4px;
  background: var(--accent);
  margin-right: 10px; vertical-align: middle;
  transition: width .18s ease;
}
/* Le point du sous-titre s'allonge en survolant. Il est déjà là : le faire
   grandir dit « c'est ici » sans rien ajouter à l'écran. */
.article h3:hover::before { width: 18px; }

/* ── Le survol des titres ─────────────────────────────────────────────────
   Un trait d'accent glisse dans la marge, et le titre ne bouge pas d'un
   pixel : le repère est posé en absolu, hors du flux.

   **Il ne prend pas la couleur d'un lien, et c'est le point.** Un titre qui
   vire à l'orange au survol apprend à cliquer dessus, et il ne mène nulle
   part : le signe se retourne alors contre les vrais liens de la page, qu'on
   finit par ne plus croire. Un trait dans la marge accompagne la lecture sans
   rien promettre. */
.h2, .article h2, .article-title, .hero-title { position: relative; }
.h2::before, .article h2::before, .article-title::before, .hero-title::before {
  content: "";
  position: absolute;
  left: -20px;
  top: .1em;
  bottom: .1em;
  width: 5px;
  border-radius: 3px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform .22s ease;
}
.h2:hover::before, .article h2:hover::before,
.article-title:hover::before, .hero-title:hover::before { transform: scaleY(1); }

/* Un aplat sous le titre, en plus du trait.
   Le trait seul se voyait mal sur les titres longs, où l'oeil est déjà loin
   quand il paraît. L'aplat, lui, se lit d'un coup - et il **surligne** plutôt
   qu'il ne colore : un titre teinté de la couleur d'un lien apprend à cliquer
   dessus, un titre surligné dit seulement où l'on est.

   Posé derrière le texte, avec des marges négatives, il ne déplace rien. */
.h2::after, .article h2::after, .article-title::after, .hero-title::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -8px -16px -8px -16px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  opacity: 0;
  transition: opacity .22s ease;
}
.h2:hover::after, .article h2:hover::after,
.article-title:hover::after, .hero-title:hover::after { opacity: 1; }

/* Les sous-titres reçoivent le même aplat, leur point tenant lieu de trait. */
.article h3 { position: relative; }
.article h3::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -5px -12px -5px -12px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  opacity: 0;
  transition: opacity .18s ease;
}
.article h3:hover::after { opacity: 1; }

/* Ce que quelqu'un a demandé de ne pas voir bouger ne bouge pas. Le repère
   paraît tout de même, il n'a simplement plus de trajet. */
@media (prefers-reduced-motion: reduce) {
  .h2::before, .article h2::before, .article h3::before,
  .article-title::before, .hero-title::before,
  .h2::after, .article h2::after, .article h3::after,
  .article-title::after, .hero-title::after { transition: none; }
}
.article p { color: var(--text-muted); }
.article strong { color: var(--text); font-weight: 640; }

.article-cta {
  display: flex; flex-wrap: wrap; gap: 14px;
  margin-top: 52px;
  padding-top: 36px;
  border-top: 1px solid var(--border-soft);
}

/* ── Encart d'explication ────────────────────────────────────────────── */

.note {
  margin-top: 32px;
  padding: 26px 28px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent-3);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.note h3 {
  margin: 0 0 12px;
  font-size: 1.02rem;
  letter-spacing: -.012em;
}
.note p {
  margin: 0 0 12px;
  color: var(--text-muted);
  font-size: .93rem;
}
.note p:last-child { margin-bottom: 0; }

/* ── Offres ──────────────────────────────────────────────────────────── */

/* Quatre cartes, et des ruptures écrites plutôt qu'un `auto-fit`.

   **`auto-fit` laissait la quatrième seule sur sa ligne.** Entre 1 000 et
   1 240 pixels il en tenait trois, et le sur mesure se retrouvait tout seul
   avec deux tiers de vide à sa droite - ce qui le fait lire comme une
   remarque en bas de page plutôt que comme la quatrième offre. Deux par deux,
   ou quatre de front : jamais trois plus une. */
.offers {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
  align-items: stretch;
}
@media (min-width: 760px) {
  .offers { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1240px) {
  .offers { grid-template-columns: repeat(4, 1fr); }
  /* À quatre de front, la carte perd une partie de ses marges plutôt que son
     contenu : trente pixels de chaque côté sur deux cent quatre-vingts, c'est
     un cinquième de la carte donné à du vide. */
  .offers > .offer { padding: 30px 24px; }
}
.offer {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 34px 30px;
}
.offer-featured {
  border-color: color-mix(in srgb, var(--accent) 42%, var(--border));
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--accent) 7%, transparent), transparent 240px),
    var(--surface);
}
.offer-name {
  margin: 0 0 6px;
  font-size: 1.22rem;
  letter-spacing: -.02em;
}
.offer-line { margin: 0 0 20px; color: var(--text-muted); }
.offer .ticks { margin-top: 0; }
.offer .ticks li { font-size: .95rem; }
.offer code,
.split-text code {
  font-family: var(--mono); font-size: .87em;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 6px;
  white-space: nowrap;
}
/* Les quatre cartes à la même hauteur, le bouton au bas de chacune. Elles
   ont été laissées à la hauteur de leur contenu quand le sur mesure faisait
   trois lignes par option et tirait les trois autres vers le bas ; les lignes
   sont courtes maintenant, et l'alignement redevient ce qu'on attend. */
.offer-cta { margin-top: auto; width: 100%; }
.offer .ticks { margin-bottom: 22px; }
.offers { align-items: stretch; }
/* Le prix d'entrée, sous les boutons du premier écran. Discret : c'est une
   information, pas un argument crié - l'argument est qu'il soit là. */
.hero-prix {
  margin: 16px 0 0;
  color: var(--text-dim);
  font-size: .92rem;
}
.hero-prix b {
  color: var(--text);
  font-family: var(--mono);
  font-weight: 700;
}

/* Le renvoi vers la page des tarifs, sur l'accueil.

   Un seul nombre et un bouton : l'ordre de grandeur se lit d'un coup d'oeil, le
   reste est à une page de là. Répéter les trois cartes ici en aurait fait un
   second exemplaire à tenir à jour, et c'est ce qui a déjà fait afficher deux
   prix différents pour la même configuration. */
.offres-renvoi {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin: 34px auto 0;
  max-width: 760px;
  padding: 34px 32px;
  text-align: center;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--border));
  border-radius: var(--radius);
}
.offres-renvoi-prix { margin: 0; color: var(--text-muted); font-size: .95rem; }
.offres-renvoi-prix b {
  display: block;
  color: var(--text);
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.2;
}
.offres-renvoi-dit { margin: 0; color: var(--text-muted); max-width: 62ch; }

/* Pourquoi un abonnement, et ce qui continue quand il s'arrête.

   **Deux colonnes qui se regardent**, et non deux paragraphes qui se suivent :
   ce qu'on vient y chercher est la comparaison - ce que je garde, ce que je
   perds -, et une liste sous l'autre la fait faire de mémoire. */
.abonnement {
  margin: 34px 0 0;
  padding: 30px 32px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}
.abonnement > .h3 { margin: 0 0 14px; }
.abonnement-tete { margin: 0 0 8px; color: var(--text-muted); max-width: 78ch; }
.abonnement-deux {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 34px;
  margin: 18px 0 6px;
}
.abonnement-titre {
  margin: 0;
  font-size: .82rem;
  font-weight: 640;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.abonnement-deux .ticks { margin-top: 12px; }
.abonnement-pied { margin: 14px 0 0; color: var(--text-muted); max-width: 78ch; }

/* La colonne de ce qui s'arrête porte une barre et non une coche. Une croix
   rouge en ferait une alerte ; ce n'est pas une panne, c'est une limite. */
.ticks-non li::before {
  width: 11px; height: 0;
  border-left: 0;
  border-bottom: 2px solid var(--text-dim);
  transform: none;
  top: .72em;
}

@media (max-width: 720px) {
  .abonnement { padding: 24px 22px; }
  .abonnement-deux { grid-template-columns: 1fr; gap: 4px; }
}

.offers-note {
  margin: 30px auto 0;
  max-width: 720px;
  text-align: center;
  color: var(--text-dim);
  font-size: .93rem;
}

/* ── Diagramme ───────────────────────────────────────────────────────── */

.diagram {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px;
}
.diagram-scroll { overflow-x: auto; }
.diagram svg { display: block; min-width: 720px; width: 100%; height: auto; }
.diagram figcaption {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--border-soft);
  color: var(--text-dim);
  font-size: .9rem;
}
/* Le texte qui lit le schéma, sous la figure. Le dessin dit le chemin à qui
   connaît déjà le produit, et à personne d'autre ; un moteur génératif, lui,
   ne lit ni les boîtes ni les flèches. Dans le bandeau, la légende de la
   figure est masquée : ce paragraphe y est le seul texte visible. */
.diagram-lit {
  margin: 14px 0 0;
  color: var(--text-dim);
  font-size: .9rem;
  line-height: 1.6;
}
.diagram-lit strong { color: var(--text-muted); }
.article-wrap .diagram-bloc { margin-bottom: 30px; }
/* Le schéma et son texte forment une seule pièce : dans le bandeau, qui
   est une grille à deux colonnes, deux enfants en feraient deux cases. */
.diagram-bloc { min-width: 0; }

.d-box rect { fill: var(--surface-2); stroke: var(--border); stroke-width: 1; }
.d-box-hub rect {
  fill: none;
  stroke: color-mix(in srgb, var(--accent) 26%, var(--border));
  stroke-dasharray: 6 5;
}
.d-t-hub { fill: var(--accent); text-anchor: start; }
.d-box-main rect { fill: color-mix(in srgb, var(--accent) 6%, var(--surface-2)); stroke: color-mix(in srgb, var(--accent) 38%, var(--border)); }
.d-box-agent rect { stroke: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.d-box-leaf rect { fill: var(--bg-alt); stroke: var(--border-soft); }

.d-t {
  fill: var(--text); font-family: var(--sans); font-size: 13.5px; font-weight: 620;
  text-anchor: middle;
}
.d-t-lg { font-size: 15px; text-anchor: start; }
.d-t-sm { font-size: 12.5px; }
.d-s {
  fill: var(--text-dim); font-family: var(--mono); font-size: 10.5px;
  text-anchor: middle;
}

.d-pill rect { fill: var(--surface); stroke: var(--border); }
.d-pill text {
  fill: var(--text-muted); font-family: var(--mono); font-size: 12px;
  text-anchor: middle;
}


.d-link { stroke: var(--border); stroke-width: 1.6; fill: none; }
.d-link-accent { stroke: var(--accent); stroke-width: 2; }
.d-link-thin { stroke: var(--text-dim); stroke-width: 1.4; }
.d-arrowhead { fill: var(--border); }
.d-arrowhead-a { fill: var(--accent); }
.d-dash { stroke: var(--border); stroke-width: 1; stroke-dasharray: 5 6; }
.d-band-bg { fill: var(--surface); }
.d-band {
  fill: var(--accent); font-family: var(--mono); font-size: 11px;
  text-anchor: middle; letter-spacing: .02em;
}

/* ── Sécurité ────────────────────────────────────────────────────────── */

.grid-sec {
  display: grid;
  /* Trois colonnes au plus, et non « autant que la largeur permet ».
     Les neuf questions y tiennent en trois rangées pleines ; à quatre colonnes,
     la dernière n'en portait qu'une, seule et étirée. */
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  /* Trois colonnes toujours, mais des cellules qui respirent sur un grand
     écran : à 1000 px de large, neuf questions tenaient au centre d'un vide. */
  max-width: min(1320px, 100%);
  margin-inline: auto;
  gap: 2px;
  background: var(--border-soft);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  overflow: hidden;
}/* Trois au plus, et dit explicitement.
   `auto-fit` en donnait quatre dès que la grille a eu 1320 px, et la dernière
   rangée ne portait plus qu'une question, seule et étirée - ce que le cap à
   1000 px empêchait jusqu'ici par accident. */
@media (min-width: 1000px) {
  .grid-sec { grid-template-columns: repeat(3, 1fr); }
}

.sec {
  background: var(--bg-alt);
  padding: 30px 28px;
}
.sec h3 {
  margin: 0 0 9px;
  font-size: 1.02rem;
  letter-spacing: -.012em;
}
.sec h3::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  margin-right: 10px; vertical-align: middle;
}
.sec p { margin: 0; color: var(--text-muted); font-size: .94rem; }

/* Les maquettes dessinées - le faux terminal, la fausse fenêtre de navigateur -
   ont vécu ici. Elles ne prouvaient rien, et une image d'illustration sous
   un cadre qui attend une vraie prise se lisait comme la prise. Retirées ;
   les cadres `.prise` disent ce qu'on attend, et rien d'autre. */

.footnote {
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid var(--border-soft);
  color: var(--text-dim);
  font-size: .88rem;
}
/* Qui tient la page, et de quand elle date. Sur une page de sécurité, c'est
   ce qu'un lecteur cherche avant de croire le reste ; la date vient de git,
   `scripts/controles/dates_visibles.py` la recopie. Dans le bloc des sources
   du CRA, elle est déjà encadrée : le trait de `.footnote` y serait un
   deuxième trait à vingt pixels du premier. */
.page-maj { margin-bottom: 34px; }
.page-maj span { color: var(--text-muted); }
.note .page-maj { margin-bottom: 0; }

/* ── Plateformes ─────────────────────────────────────────────────────── */

.platforms {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
  margin-top: clamp(40px, 6vw, 68px);
}
.platform {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  background: var(--surface);
}
.platform h4 {
  margin: 0 0 8px;
  font-size: 1rem;
  font-family: var(--mono);
  color: var(--accent);
  font-weight: 600;
}
.platform p { margin: 0; color: var(--text-muted); font-size: .93rem; }

/* ── CTA ─────────────────────────────────────────────────────────────── */

.section-cta {
  border-top: 1px solid var(--border-soft);
  background:
    radial-gradient(ellipse 70% 100% at 50% 100%, rgba(232,112,26,.13), transparent 70%),
    var(--bg);
}
.cta-inner { max-width: 660px; margin-inline: auto; text-align: center; }
.cta-inner .section-sub { margin-bottom: 32px; }

/* ── Footer ──────────────────────────────────────────────────────────── */

.site-footer {
  border-top: 1px solid var(--border-soft);
  padding: 56px 0 36px;
  background: var(--bg-alt);
}
/* Trois zones : la marque à gauche, les trois colonnes de liens à droite, la
   ligne du bas sur toute la largeur. */
.footer-inner {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 2fr);
  gap: 40px 64px;
  align-items: start;
}
.footer-marque { max-width: 46ch; }
.footer-tag {
  margin: 14px 0 0;
  color: var(--text-muted);
  font-size: .95rem;
  line-height: 1.5;
}
/* L'éditeur : une ligne discrète, qui répond à une question qu'on se pose
   parfois sans prendre la place de ce qu'on est venu lire. */
.footer-editeur {
  margin: 14px 0 0;
  font-size: .86rem;
  line-height: 1.5;
  color: var(--text-dim);
}
.footer-editeur a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.footer-nav {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}
.footer-nav > div { display: flex; flex-direction: column; gap: 10px; }
.footer-titre {
  margin: 0 0 4px;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.footer-nav a {
  color: var(--text-muted); text-decoration: none; font-size: .92rem;
}
.footer-nav a:hover { color: var(--text); }
.footer-bas {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px 24px;
  margin: 16px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--border-soft);
  font-family: var(--mono);
  font-size: .74rem;
  letter-spacing: .03em;
  color: var(--text-dim);
}
.footer-bas a { color: var(--text-dim); text-decoration: none; }
.footer-bas a:hover { color: var(--text); }
@media (max-width: 900px) {
  .footer-inner { grid-template-columns: 1fr; gap: 32px; }
}
@media (max-width: 560px) {
  .footer-nav { grid-template-columns: 1fr 1fr; }
}

/* ── Révélation au scroll ────────────────────────────────────────────── */

/* L'état masqué n'est appliqué que si le JS a pu s'exécuter : sans lui,
   le contenu reste visible plutôt que d'être définitivement caché. */
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s ease, transform .55s ease;
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* Le décalage entre éléments voisins, qui donne l'impression qu'une grille
   apparaît par vagues plutôt que d'un bloc.
   **En CSS et non par le script** : un `el.style.transitionDelay` est un style
   en ligne, et la politique de sécurité les retire - le décalage ne s'appliquait
   pas, et la console rendait cinquante refus par page. */
.js .reveal:nth-child(3n+2) { transition-delay: 70ms; }
.js .reveal:nth-child(3n+3) { transition-delay: 140ms; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* ── Responsive ──────────────────────────────────────────────────────── */

@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
  .split-reverse .split-text { order: 0; }
}

@media (max-width: 900px) {
  .nav-toggle { display: grid; place-items: center; }

  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 4px;
    padding: 14px 24px 22px;
    background: var(--bg-alt);
    border-bottom: 1px solid var(--border);
    display: none;
  }
  /* Le tiroir dépasse un écran de téléphone depuis que « Produit » y déplie
     ses huit entrées : il défile, sans quoi le bouton du bas est hors de
     portée. */
  .nav.is-open { display: flex; max-height: calc(100vh - 68px); overflow-y: auto; }
  .nav a { padding: 11px 0; font-size: 1rem; }
  .nav a.btn { margin-top: 10px; justify-content: center; }
}

@media (max-width: 760px) {
  body { font-size: 16px; }

  .hero-actions { flex-direction: column; align-items: stretch; }
  .hero-actions .btn { width: 100%; }
}

/* ── Listes dans un article ──────────────────────────────────────────── */

.article ul { margin: 14px 0 0; padding-left: 22px; color: var(--text-muted); }
.article li { margin-bottom: 9px; }
.article li::marker { color: var(--accent); }

/* ── Échéances ───────────────────────────────────────────────────────── */

.dates {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  border-left: 2px solid var(--border);
}
.dates li {
  position: relative;
  margin: 0;
  padding: 0 0 24px 26px;
}
.dates li:last-child { padding-bottom: 0; }
.dates li::before {
  content: "";
  position: absolute; left: -7px; top: 8px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--accent);
  border: 3px solid var(--bg);
}
.dates b {
  display: block;
  color: var(--text);
  font-weight: 660;
  letter-spacing: -.01em;
}
.dates span { color: var(--text-muted); font-size: .95rem; }

/* Le cadre de ce que le client héberge, autour du hub et de sa base. */
.d-box-host rect {
  fill: none;
  stroke: var(--border);
  stroke-dasharray: 3 6;
}
.d-s-start { text-anchor: start; }
.d-s-end   { text-anchor: end; }

/* ── Formulaire de contact ───────────────────────────────────────────── */

.form { margin: 34px auto 0; max-width: 720px; text-align: left; }
/* « facultatif », dit à côté de l'intitulé plutôt que dans le vide sous le
   champ : c'est en lisant le nom du champ qu'on décide de le remplir. */
.facultatif {
  margin-left: 6px;
  font-size: .74rem;
  font-weight: 400;
  color: var(--text-dim);
  text-transform: none;
  letter-spacing: 0;
}
/* Un bouton éteint le dit, et cesse d'inviter au clic. Sans cela il gardait sa
   couleur pleine pendant l'envoi, et le second clic partait. */
.form button[disabled] {
  opacity: .55;
  cursor: default;
  pointer-events: none;
}
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
}
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

.field { margin: 0 0 18px; display: flex; flex-direction: column; gap: 7px; }
.form-grid .field { margin: 0; }
.field label {
  font-size: .88rem;
  font-weight: 620;
  color: var(--text);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 11px 13px;
  font: inherit;
  font-size: .95rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color .18s ease, box-shadow .18s ease;
}
/* **Le champ du besoin est haut**, et pas seulement redimensionnable. Le
   calculateur y dépose déjà six lignes de configuration : à cent vingt pixels,
   le visiteur ouvrait un champ qui semblait plein avant d'avoir écrit un mot. */
.field textarea { resize: vertical; min-height: 220px; }
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.field input:user-invalid,
.field textarea:user-invalid { border-color: var(--loot-red); }

/* Le piège à robots.
   Retiré du flux plutôt que masqué par `display: none` : un robot un peu
   sérieux lit le style et saute ce qui est explicitement caché. */
.leurre {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.form-actions {
  display: flex; align-items: center; flex-wrap: wrap; gap: 16px;
  margin-top: 8px;
}
.form-note { margin: 0; font-size: .9rem; color: var(--text-muted); }
.form-note.is-error { color: var(--loot-red); }
.form-note.is-ok { color: var(--accent); }
.form.is-sending button { opacity: .6; pointer-events: none; }

/* Le prix d'appel d'un palier.
   Posé sous la ligne d'accroche et au-dessus de la liste : c'est ce qu'on
   cherche en deuxième, après avoir lu le nom. */
.offer-price {
  margin: 0 0 18px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--border-soft);
  color: var(--text-muted);
  font-size: .95rem;
}
/* Le prix réglé d'avance, sur deux ou trois ans : deux lignes discrètes
   sous le prix à l'année, qui disent la remise avec sa durée. */
.offer:has(.offer-duree) .offer-price { border-bottom: 0; padding-bottom: 0; margin-bottom: 8px; }
.offer-duree { list-style: none; margin: 0 0 18px; padding: 0 0 14px; border-bottom: 1px solid var(--border-soft); font-size: .84rem; color: var(--text-dim); display: grid; gap: 4px; }
.offer-duree b { color: var(--text-muted); font-weight: 600; }
/* Le prix ramené à l'équipement, au plafond de l'offre. Il ferme le bloc du
   prix, donc c'est lui qui porte le trait quand il est là : deux traits à
   quatre pixels l'un de l'autre se lisent comme une erreur de mise en page. */
.offer:has(.offer-unit) .offer-duree { border-bottom: 0; padding-bottom: 0; margin-bottom: 6px; }
.offer-unit { margin: 0 0 18px; padding-bottom: 14px; border-bottom: 1px solid var(--border-soft); font-size: .8rem; color: var(--text-dim); }
.offer-price b {
  color: var(--text);
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: -.02em;
}

/* ── Calculateur de tarif ────────────────────────────────────────────── */

@media (max-width: 720px) {
}

/* Qui demande moins d'animation garde le repli, sans la transition. */
@media (prefers-reduced-motion: reduce) {
}

/* Le curseur, dessiné à la main : l'apparence native diffère d'un système à
   l'autre au point qu'on ne reconnaît pas le même composant. */
/* La piste dit ce qui est compris et ce qui se paie.
   *
   * Trois zones, dans cet ordre : **orange pâle** jusqu'au seuil d'inclusion -
   * ce qu'on a déjà -, **orange plein** du seuil au curseur - ce qu'on ajoute -,
   * puis neutre. Une piste d'une seule couleur aurait dit « voilà où vous
   * êtes », celle-ci dit « voilà ce que vous payez », ce qui est la question.
   *
   * **Le remplissage part de la gauche**, et c'est ce qui a changé : la zone
   * comprise était grise, si bien que l'orange semblait commencer au milieu de
   * la piste et qu'on lisait un curseur cassé plutôt qu'un seuil. Deux tons du
   * même orange disent la même chose sans ce faux départ.
   *
   * **Les deux arrêts viennent de classes, pas d'un attribut `style`.** La
   * politique de sécurité retire les styles en ligne sans un mot, et ce dépôt
   * s'y est déjà pris deux fois. Deux familles de classes suffisent :
   * la position du pouce, par cran exact, et le seuil de l'inclusion, au
   * pourcent - lui ne tombe pas sur un cran. */

/* ── Les systèmes, par leur signe ─────────────────────────────────────── */

/* Trois glyphes en SVG dans la feuille, et non en fichiers : un `data:` est
   autorisé par `img-src`, et rien ne part chercher trois images pour trois
   icônes d'un centimètre. Les trois sont dessinés ici - un manchot, quatre
   carreaux, un téléphone : le robot d'Android a été employé un temps, sous
   CC BY 3.0, et sa ligne d'attribution en pied de page ne se comprenait pas ;
   un téléphone dessiné par nous n'a besoin de rien. La couleur est celle du
   texte atténué, écrite en dur parce qu'une image de fond ne lit pas les
   variables. */
.ico {
  display: inline-block;
  width: 1.1em; height: 1.1em;
  margin-right: .4em;
  vertical-align: -.18em;
  background: no-repeat center / contain;
}
.ico-linux { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234A6472' d='M12 1.5c-2.6 0-4.3 2-4.3 4.8 0 1.2.2 2.1-.4 3.2-1.4 2.4-3.3 4.6-3.3 7.3 0 1 .3 1.8.8 2.5-.4.4-.8 1-.8 1.7 0 .9.7 1.5 1.9 1.5 1.1 0 2.3-.3 3.1-.9.9.4 2 .6 3 .6s2.1-.2 3-.6c.8.6 2 .9 3.1.9 1.2 0 1.9-.6 1.9-1.5 0-.7-.4-1.3-.8-1.7.5-.7.8-1.5.8-2.5 0-2.7-1.9-4.9-3.3-7.3-.6-1.1-.4-2-.4-3.2C16.3 3.5 14.6 1.5 12 1.5zm-1.6 3.6a.8.8 0 1 1 0 1.6.8.8 0 0 1 0-1.6zm3.2 0a.8.8 0 1 1 0 1.6.8.8 0 0 1 0-1.6zM12 7l1.4 1-1.4 1-1.4-1z'/%3E%3Cpath fill='%23fff' d='M12 10.5c-2 0-3.5 2.4-3.5 5.2 0 2.1 1.5 3.5 3.5 3.5s3.5-1.4 3.5-3.5c0-2.8-1.5-5.2-3.5-5.2z'/%3E%3C/svg%3E"); }
.ico-windows { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234A6472' d='M3 4.5 11 3.4v7.9H3zm0 15 8 1.1v-7.9H3zm9-16.2L21 2v9.3h-9zm0 9.4h9V22l-9-1.3z'/%3E%3C/svg%3E"); }
.ico-android { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234A6472' d='M7 2.5h10a2 2 0 0 1 2 2v15a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2zm0 2v13h10v-13H7zm3.8 15.2h2.4a.7.7 0 1 1 0 1.4h-2.4a.7.7 0 1 1 0-1.4z'/%3E%3C/svg%3E"); }

/* La ligne « sur mobile » des cartes porte le signe après le texte : c'est le
   texte qui dit le geste, le signe ne fait que répondre « lequel ? ». */
.ticks li.ligne-android::after {
  content: "";
  display: inline-block;
  width: 1em; height: 1em;
  margin-left: .35em;
  vertical-align: -.15em;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234A6472' d='M7 2.5h10a2 2 0 0 1 2 2v15a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2zm0 2v13h10v-13H7zm3.8 15.2h2.4a.7.7 0 1 1 0 1.4h-2.4a.7.7 0 1 1 0-1.4z'/%3E%3C/svg%3E") no-repeat center / contain;
}

.plateformes {
  list-style: none;
  margin: 0 0 20px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px 22px;
  font-size: .85rem; color: var(--text-dim);
}
.plateformes b { color: var(--text-muted); font-weight: 600; }

.matrice th .ico { margin-right: .3em; }


.calc-note { margin: 0 0 20px; font-size: .85rem; color: var(--text-dim); }
@media (max-width: 1080px) {
  .calc { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
  .calc { grid-template-columns: 1fr; }
  /* Après la règle du dessus, et non avant : les deux s'appliquent ici, et
     c'est la dernière qui gagne. Trois boutons côte à côte sur un téléphone
     coupent leurs intitulés en deux. */
}

/* ── Les protocoles ──────────────────────────────────────────────────── */

.protos-tete { margin-top: 58px; }
.protos-tete .h3 {
  margin: 0 0 10px;
  font-size: clamp(1.25rem, 2.3vw, 1.55rem);
  letter-spacing: -.022em;
}
.protos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(268px, 1fr));
  gap: 18px;
  margin-top: 30px;
}
/* Les huit tiennent en deux rangées de quatre. Sans ce plafond, une largeur
   suffisante en donne cinq puis trois, et la seconde rangée pend. */
/* Quatre, parce qu'il y a huit cartes.
   Le compte gouverne, et non la largeur disponible : sept accès plus celle des
   protocoles à venir font deux rangées pleines à quatre colonnes. À trois, la
   dernière rangée n'en portait plus que deux. */
@media (min-width: 1200px) {
  .protos { grid-template-columns: repeat(4, 1fr); }
}
.proto {
  display: flex;
  flex-direction: column;
  padding: 20px 22px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.proto-nom {
  margin: 0 0 9px;
  font-size: 1rem;
  font-weight: 660;
  letter-spacing: -.012em;
}
/* Le sigle à côté du nom : c'est par lui qu'on cherche, mais c'est le nom qui
   dit ce que ça fait. */
.proto-nom span {
  margin-left: 8px;
  font-family: var(--mono);
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  border-radius: 5px;
  padding: 3px 7px;
  white-space: nowrap;
}
.proto-quoi { margin: 0; font-size: .91rem; color: var(--text-muted); }
.proto-quoi em { color: var(--text); font-style: italic; }

/* Ce que la session laisse derrière elle.
   Deux mots distincts et non un booléen : un transfert de fichiers ne produit
   pas de rejeu, mais il tient un journal d'opérations - l'afficher comme « non
   enregistré » effacerait ce qu'il garde vraiment. */
/* La ligne de trace tombe au bas de la carte.
   Sans `margin-top: auto` elle suivait son paragraphe, et une rangée de cartes
   rendait quatre traits d'horizon à quatre hauteurs différentes - ce que l'oeil
   lit comme un désalignement avant même de lire les mots. */
.proto-trace {
  margin: auto 0 0;
  padding-top: 13px;
  border-top: 1px solid var(--border-soft);
  font-family: var(--mono);
  font-size: .76rem;
  letter-spacing: .02em;
}
.proto-trace::before { content: "◆"; margin-right: 7px; }
.proto-rejeu { color: var(--accent); }
.proto-journal { color: var(--text-dim); }

.proto-suite {
  background: var(--surface-2);
  border-style: dashed;
  justify-content: center;
}
.proto-suite .proto-nom { color: var(--text-muted); }

/* La note sur les plafonds, sous le détail.
   Quatre lignes disant « au plus » établissent la borne ; celle-ci dit ce
   qu'elle implique - qu'on peut en déclarer moins sans rien perdre. */
.calc-plafond {
  margin: 14px 0 0;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--text-dim);
}

/* Sous le bouton de demande : dire que le réglage n'est pas perdu.
   Sans cette ligne, on clique en croyant devoir tout ressaisir. */
/* Ce qui est compris se lit sur le curseur lui-même.
   Deux crans sous le seuil rendent le même prix - c'est une inclusion, pas une
   panne - et sans ce gris on déplace le curseur en croyant qu'il ne répond
   pas. La borne est dite en toutes lettres juste dessous, parce qu'un gris se
   constate mais ne s'explique pas. */
.calc-usage {
  margin: 14px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
  font-size: .8rem;
  color: var(--text-dim);
}

/* Ce qui s'affiche à la place du détail quand le barème ne chiffre plus.
   Une phrase, et non une ligne de tableau : une explication rangée dans la
   colonne d'un montant se lit comme un tableau cassé. */

/* Les groupes de la FAQ : un titre qui se voit, avec sa phrase.
   Il était une étiquette de 13 px en capitales grises au-dessus de la grille,
   et on lisait vingt cartes sans savoir de quoi chacune relevait. */
.faq-tete {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 22px;
  margin: 56px 0 18px;
  padding-top: 22px;
  border-top: 3px solid var(--accent);
  max-width: min(1320px, 100%); margin-inline: auto;
}
.faq-tete:first-of-type { margin-top: 0; border-top: 0; padding-top: 0; }
.faq-groupe {
  margin: 0;
  font-size: 1.6rem;
  font-weight: 720;
  letter-spacing: -.02em;
  color: var(--text);
}
.faq-dit { margin: 0; color: var(--text-muted); }

/* La matrice de compatibilité des agents. Un tableau et non trois paragraphes :
   ce qu'on vient y chercher est la case qui dit non. */
.matrice { margin: 22px 0 8px; overflow-x: auto; }
.matrice table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.matrice th, .matrice td {
  padding: 9px 12px;
  text-align: left;
  border-bottom: 1px solid var(--border-soft);
}
.matrice thead th { font-size: .78rem; letter-spacing: .04em; text-transform: uppercase; color: var(--text-dim); }
.matrice tbody th { font-weight: 500; color: var(--text); }
.matrice td.oui { color: var(--text-muted); }
.matrice td.non { color: var(--accent); font-weight: 640; }
.matrice-note { margin: 10px 0 0; font-size: .85rem; color: var(--text-dim); }

/* ── L'accueil en deux rôles ─────────────────────────────────────────── */

/* **Le haut prend l'écran, la suite garde sa largeur de lecture.** Le héros
   se lisait « tassé » à 1 920 : une colonne de 660 px centrée, trois
   paragraphes. Il est en deux colonnes - le texte à gauche, les deux prises à
   droite - sur toute la largeur du cadre, et la base passe à 18 px au-delà
   de 1 400 px. Les cartes et les paragraphes restent à 1 440. */
@media (min-width: 1400px) { body { font-size: 18px; } }

.hero-duo { padding-top: clamp(56px, 7vw, 96px); padding-bottom: clamp(56px, 7vw, 88px); }
.hero-duo-inner { text-align: left; }
.hero-texte { max-width: 60ch; }
.hero-duo h1 { font-size: clamp(2.2rem, 4.6vw, 3.9rem); }
.hero-duo .lead { margin-left: 0; max-width: 58ch; font-size: clamp(1.02rem, 1.4vw, 1.3rem); line-height: 1.55; }
.hero-duo .hero-actions { justify-content: flex-start; }
.hero-duo .hero-prix { max-width: 60ch; }
.hero-prises { display: grid; gap: 16px; margin-top: 36px; }
@media (min-width: 1000px) {
  .hero-duo-inner { display: grid; grid-template-columns: 1.25fr 1fr; gap: clamp(40px, 5vw, 72px); align-items: center; }
  .hero-prises { margin-top: 0; }
}

/* Le cadre d'une prise, en attendant la vidéo.
   Il dit ce qu'il attend - numéro du cahier, sujet, durée - pour qu'on sache
   quoi capturer ; le jour où la vidéo existe, elle prend sa place dans le
   même cadre. Les hachures disent « provisoire » sans le crier. */
.prise {
  position: relative;
  margin: 0;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 30px 60px -34px rgba(0,59,86,.35);
  overflow: hidden;
}
.prise-num {
  position: absolute; left: 14px; top: 14px; z-index: 1;
  font-family: var(--mono); font-size: .72rem; font-weight: 700; letter-spacing: .06em;
  color: var(--on-accent); background: var(--bleu);
  padding: 5px 9px; border-radius: 6px;
}
.prise-cadre {
  min-height: 236px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  padding: 44px 24px 24px;
  text-align: center;
  background: repeating-linear-gradient(135deg, var(--bg-alt) 0 14px, var(--surface-2) 14px 28px);
}
.prise-cadre b { font-size: 1.1rem; color: var(--text); }
.prise-cadre span { color: var(--text-muted); font-size: .95rem; }
.prise figcaption {
  position: absolute; right: 14px; bottom: 14px;
  font-family: var(--mono); font-size: .7rem;
  color: var(--on-accent); background: rgba(0,59,86,.85);
  padding: 5px 9px; border-radius: 6px;
}
.prise-sm .prise-cadre { min-height: 190px; }
/* L'écran d'un téléphone est en portrait, et le reste : étiré sur la largeur
   d'une prise de console, il n'aurait plus rien d'un téléphone. */
.prise-portrait { max-width: 330px; margin-inline: auto; }
.prise-portrait .prise-cadre { min-height: 420px; }

/* ── La prise dans sa carte ────────────────────────────────────────────
   **La démonstration appartient à la carte du produit qu'elle montre.** Les
   deux ont été un bloc à part, entre le chapeau et les cartes : elles ne se
   rattachaient à rien, prenaient trois cent quarante pixels de haut, et les
   deux colonnes n'apparaissaient plus qu'au-dessous. Sous le titre de sa
   carte, chacune illustre ce qui est écrit à côté, et ce sont les deux
   colonnes qui font la structure.

   **Bornées par la hauteur**, un paysage et un portrait s'alignent : une
   console en 16/9 et un téléphone en portrait n'ont pas la même largeur et
   n'ont pas à l'avoir. Ce qu'on y lit reste un aperçu ; un clic les ouvre en
   grand, et c'est à ça que sert la loupe. */
.gamme article > .prise { margin: 4px 0 16px; align-self: flex-start; max-width: 100%; }
.gamme article > .prise.prise-portrait { margin-inline: 0; }
.gamme article > .prise .prise-affiche {
  max-height: 300px; max-width: 100%; width: auto; height: auto;
}
@media (max-width: 700px) {
  .gamme article > .prise .prise-affiche { max-height: 240px; }
}
/* Une prise faite : la vidéo (ou l'image) prend la place du cadre, qui reste
   dans la page - c'est lui qui revient quand on retire la prise. */
.prise-affiche { display: block; width: 100%; height: auto; }
.prise-media { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity .35s; }
.prise-media.is-lue { opacity: 1; }
.prise:has(.prise-affiche) .prise-cadre,
.prise:has(.prise-affiche) .prise-num,
.prise:has(.prise-affiche) figcaption { display: none; }
/* Un clic ouvre la prise en grand : à 700 px de large, une console faite pour
   1920 se devine, elle ne se lit pas. */
.prise:has(.prise-affiche) { cursor: zoom-in; }
.prise:has(.prise-affiche):focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.prise-loupe {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(0, 20, 30, .88);
  cursor: zoom-out;
}
.prise-loupe video, .prise-loupe img {
  display: block;
  max-width: min(96vw, 1920px); max-height: 92vh;
  width: auto; height: auto;
  border-radius: 10px;
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.8);
  background: #000;
}
.prise-loupe-fermer {
  position: fixed; top: 18px; right: 22px;
  width: 44px; height: 44px; border-radius: 50%;
  border: 0; background: rgba(255,255,255,.14); color: #fff;
  font-size: 26px; line-height: 44px; cursor: pointer;
}
.prise-loupe-fermer:hover { background: rgba(255,255,255,.28); }
body.a-la-loupe { overflow: hidden; }

/* Les deux rôles, côte à côte, reliés par une flèche. */
.roles { display: grid; gap: 22px; }
@media (min-width: 900px) { .roles { grid-template-columns: 1fr 1fr; } }
.role {
  position: relative;
  padding: 32px 32px 28px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
}
.role-num {
  margin: 0 0 10px;
  font-family: var(--mono); font-size: .74rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent);
}
.role h3 { margin: 0 0 12px; font-size: 1.55rem; letter-spacing: -.02em; }
.role > p { margin: 0 0 16px; color: var(--text-muted); }
.role .ticks { margin: 0; padding: 0; list-style: none; }
.role .ticks li { margin-bottom: 8px; }
.puces { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 14px 0 0; padding: 0; }
.puces li {
  font-family: var(--mono); font-size: .76rem;
  color: var(--text-muted); background: var(--surface);
  border: 1px solid var(--border); border-radius: 999px; padding: 5px 12px;
}
.role-fleche {
  display: none;
  position: absolute; top: 50%; left: 100%; transform: translate(-50%, -50%);
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--bleu); color: var(--on-accent);
  font-weight: 800; z-index: 1;
  align-items: center; justify-content: center;
}
@media (min-width: 900px) { .role-fleche { display: flex; } }
.section-suite { display: flex; flex-wrap: wrap; gap: 12px 32px; margin: 26px 0 0; }

/* Les trois étapes, numérotées par le CSS, une prise en tête. */
.etapes { display: grid; gap: 22px; list-style: none; margin: 0; padding: 0; counter-reset: etape; }
@media (min-width: 900px) { .etapes { grid-template-columns: repeat(3, 1fr); } }
.etapes li {
  position: relative;
  padding: 28px 28px 26px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
}
.etapes li::before {
  counter-increment: etape; content: counter(etape);
  position: absolute; top: -18px; left: 24px; z-index: 1;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--accent); color: var(--on-accent);
  font-weight: 800; display: flex; align-items: center; justify-content: center;
}
.etapes .prise { margin: 8px 0 18px; box-shadow: none; }
.etapes h3 { margin: 0 0 8px; font-size: 1.2rem; }
.etapes p { margin: 0; color: var(--text-muted); }

/* Pour qui : trois cas. */
.cas { display: grid; gap: 22px; }
@media (min-width: 900px) { .cas { grid-template-columns: repeat(3, 1fr); } }
/* Le lien descend au bas de la carte, et les six « Ce que le hub fait pour
   vous » s'alignent d'une carte à l'autre. Sans cela il suivait son
   paragraphe, et six cartes de longueurs différentes donnaient six hauteurs
   différentes - ce que l'oeil lit comme un défaut avant de lire le texte. */
.cas article { padding: 30px; border: 1px solid var(--border); border-radius: 16px; background: var(--surface); display: flex; flex-direction: column; }
.cas h3 { margin: 0 0 10px; font-size: 1.25rem; }
.cas p { margin: 0 0 14px; color: var(--text-muted); }
.cas article > .link-arrow { margin-top: auto; align-self: flex-start; }

/* Les quatre chiffres. */
.chiffres { display: grid; gap: 22px; list-style: none; margin: 0; padding: 0; }
@media (min-width: 700px) { .chiffres { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .chiffres { grid-template-columns: repeat(4, 1fr); } }
/* Centrés, le nombre en grand et en orange plein, un trait fin au-dessus :
   quatre nombres alignés à gauche en petit se lisaient comme des cases de
   formulaire. Le dégradé du titre a été essayé ici et retiré : sur trois
   caractères il ne se voit pas, et le trait bicolore faisait tache. */
.chiffres li {
  position: relative;
  padding: 34px 26px 30px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  text-align: center;
  overflow: hidden;
}
.chiffres li::before {
  content: "";
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  width: 56px; height: 4px; border-radius: 0 0 4px 4px;
  background: var(--accent);
}
.chiffres b {
  display: block;
  font-size: clamp(2.6rem, 3.4vw, 3.4rem);
  font-weight: 800;
  letter-spacing: -.04em; line-height: 1;
  margin-bottom: 12px;
  color: var(--accent);
}
.chiffres span { display: block; color: var(--text-muted); font-size: .95rem; max-width: 26ch; margin: 0 auto; }

/* Les quatre questions, en deux colonnes, sans script. */
.questions { display: grid; gap: 10px 40px; }
@media (min-width: 900px) { .questions { grid-template-columns: 1fr 1fr; } }
.questions > div { border-bottom: 1px solid var(--border); padding: 14px 0; }
.questions h3 { margin: 0; font-weight: 700; font-size: 1.05rem; }
.questions p { color: var(--text-muted); margin: 10px 0 0; }

/* ── Le menu, en deux listes ───────────────────────────────────────────
   Deux groupes qui s'ouvrent au survol et au focus, sans script - au premier
   toucher avec, par main.js. Le titre est étiré à la hauteur de l'en-tête
   pour qu'aucun vide ne sépare le titre de sa liste. Il y a eu un panneau
   large qui décrivait toute la gamme avec une lettre par produit ; la gamme
   se présente sur l'accueil, dans une bande faite pour ça. */
.nav-groupe { position: relative; }
/* Le titre est un `span` focalisable, pas un lien : il porte les mêmes
   règles que les entrées - couleur, trait de survol, marque de la page
   courante - sans mener nulle part. */
.nav-groupe > span {
  position: relative;
  display: inline-flex; align-items: center; padding: 22px 0;
  color: var(--text-muted); font-size: .95rem; cursor: default;
  transition: color .18s ease;
}
.nav-groupe > span:hover, .nav-groupe > span:focus-visible, .nav-groupe:focus-within > .nav-groupe > span { color: var(--text); }
.nav-groupe > span::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 15px;
  height: 2px; border-radius: 2px;
  background: color-mix(in srgb, var(--accent) 55%, transparent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .18s ease;
}
.nav-groupe > span:hover::after, .nav-groupe:focus-within > .nav-groupe > span::after { transform: scaleX(1); }
.nav-groupe > span.is-current { color: var(--text); }
.nav-groupe > span.is-current::after { background: var(--accent); transform: scaleX(1); }
.nav-groupe > span > .chevron { font-size: .7em; margin-left: 4px; }
.nav-sous {
  display: none;
  position: absolute; top: 100%; left: -14px;
  min-width: 260px;
  flex-direction: column; gap: 2px;
  padding: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 20px 40px -24px rgba(0,59,86,.4);
}
.nav-groupe:hover .nav-sous, .nav-groupe:focus-within .nav-sous, .nav-groupe.is-open .nav-sous { display: flex; }
.nav-sous { min-width: 360px; padding: 12px; gap: 4px; }
/* Une entrée : un signe, un titre, une ligne. Les signes sont dessinés en
   SVG dans la feuille - un terminal, une puce, un écran et un téléphone, une
   grille ; un serveur, une clé, un bouclier - parce qu'une lettre ne se
   comprend pas et qu'une liste nue est triste. */
.nav-sous a { display: grid; grid-template-columns: 38px 1fr; gap: 12px; align-items: start; padding: 10px 12px; border-radius: 10px; font-size: .92rem; color: var(--text); }
.nav-sous a:hover { background: var(--bg-alt); color: var(--text); }
.nav-sous a:not(.btn)::after { display: none; }
.nav-sous a > span { display: block; color: var(--text-muted); font-size: .84rem; line-height: 1.4; }
.nav-sous a > span > b { display: block; color: var(--text); font-size: .95rem; margin-bottom: 2px; }
.nav-ico { display: block; width: 38px; height: 38px; border-radius: 10px; background: #FFF0E3 no-repeat center / 22px 22px; }
.nav-ico-terminal { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='2'/%3E%3Cpath d='M7 9l3 3-3 3M12 15h5'/%3E%3C/svg%3E"); }
.nav-ico-agent { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round'%3E%3Crect x='6' y='6' width='12' height='12' rx='2'/%3E%3Crect x='9.5' y='9.5' width='5' height='5' rx='1'/%3E%3Cpath d='M9 3v3M15 3v3M9 18v3M15 18v3M3 9h3M3 15h3M18 9h3M18 15h3'/%3E%3C/svg%3E"); }
.nav-ico-appareils { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round'%3E%3Crect x='2' y='5' width='14' height='10' rx='1.5'/%3E%3Cpath d='M6 19h6M9 15v4'/%3E%3Crect x='17' y='9' width='5' height='10' rx='1.2'/%3E%3Cpath d='M19.5 17h.01'/%3E%3C/svg%3E"); }
.nav-ico-gamme { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8'%3E%3Crect x='4' y='4' width='7' height='7' rx='1.5'/%3E%3Crect x='13' y='4' width='7' height='7' rx='1.5'/%3E%3Crect x='4' y='13' width='7' height='7' rx='1.5'/%3E%3Crect x='13' y='13' width='7' height='7' rx='1.5'/%3E%3C/svg%3E"); }
.nav-ico-serveur { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round'%3E%3Crect x='3' y='4' width='18' height='7' rx='1.5'/%3E%3Crect x='3' y='13' width='18' height='7' rx='1.5'/%3E%3Cpath d='M7 7.5h.01M7 16.5h.01'/%3E%3C/svg%3E"); }
.nav-ico-cle { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='12' r='4'/%3E%3Cpath d='M12 12h9M18 12v3M15 12v2'/%3E%3C/svg%3E"); }
.nav-ico-bouclier { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23BC5510' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l8 3v6c0 4.5-3.2 7.8-8 9-4.8-1.2-8-4.5-8-9V6z'/%3E%3Cpath d='M9 12l2 2 4-4'/%3E%3C/svg%3E"); }

@media (max-width: 900px) {
  .nav-groupe > span { padding: 11px 0; font-size: 1rem; }
  .nav-groupe > span::after { display: none; }
  .nav-sous { display: flex; position: static; min-width: 0; padding: 0 0 6px 14px; border: 0; box-shadow: none; background: transparent; }
  .nav-sous a { grid-template-columns: 1fr; padding: 8px 0; }
  .nav-ico { display: none; }
}

/* ── Le bandeau des pages intérieures ─────────────────────────────────
   Une page intérieure commençait par un titre et 5 000 px de texte, sans
   une image ni un bouton avant le pied. Elle commence maintenant par
   montrer : un bandeau en deux colonnes - sur-titre, titre, chapeau, deux
   boutons, trois faits - et à droite la prise qui prouve ce que le titre
   promet. Le texte suit, dans sa colonne, avec une prise par section, un
   appel à mi-page, et trois portes de sortie à la fin. */
.page-bandeau {
  position: relative;
  padding: clamp(44px, 6vw, 72px) 0 clamp(40px, 5vw, 56px);
  border-bottom: 1px solid var(--border-soft);
  background: linear-gradient(180deg, rgba(232,112,26,.07), transparent 80%), var(--bg);
}
/* Le bandeau ouvre l'article, donc l'article ne garde pas sa marge du haut ;
   et le bandeau laisse un vrai espace sous lui, sans quoi le sommaire
   collait aux boutons. */
.article:has(> .page-bandeau) { padding-top: 0; }
.page-bandeau { margin: 0 0 clamp(40px, 5vw, 64px); }
.page-bandeau-inner { display: grid; gap: 36px; align-items: center; }
@media (min-width: 1000px) { .page-bandeau-inner { grid-template-columns: 1.1fr 1fr; gap: clamp(40px, 5vw, 64px); } }
.page-bandeau .article-title { margin-bottom: 18px; }
.page-bandeau .article-chapo { max-width: 56ch; margin-bottom: 26px; }
.page-bandeau .hero-actions { justify-content: flex-start; }
.page-bandeau .prise-cadre { min-height: 300px; }
.article .page-bandeau .diagram { width: auto; max-width: none; margin: 0; }
.page-bandeau .diagram figcaption { display: none; }
.page-bandeau .matrice { margin: 0; }

/* La colonne de lecture, un peu plus large : 76 signes à 18 px. */
.article-wrap { max-width: 880px; }
@media (min-width: 1400px) {
  .article-wrap:has(.article-toc) { grid-template-columns: 236px minmax(0, 880px) minmax(0, 1fr); }
}

/* Une prise dans le texte suivi. */
.article-wrap > .prise { margin: 8px 0 30px; }
.article-wrap > .prise .prise-cadre { min-height: 280px; }

/* L'appel à mi-page. */
.cta-mi {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px 28px;
  margin: 40px 0;
  padding: 26px 30px;
  border-radius: 14px;
  background: var(--bleu); color: var(--on-accent);
}
.cta-mi p { margin: 0; color: #BFD3DD; }
.cta-mi b { display: block; color: var(--on-accent); font-size: 1.15rem; margin-bottom: 4px; }

/* Les trois portes de sortie. */
.suite { display: grid; gap: 18px; margin: 52px 0 0; padding: 36px 0 0; list-style: none; border-top: 1px solid var(--border-soft); }
@media (min-width: 760px) { .suite { grid-template-columns: repeat(3, 1fr); } }
.suite li { display: flex; }
.suite a {
  display: block; width: 100%; padding: 18px 20px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface);
  text-decoration: none; color: var(--text);
}
.suite a:hover { border-color: var(--accent); }
.suite b { display: block; margin-bottom: 4px; }
.suite span { color: var(--text-muted); font-size: .92rem; }

/* Le bouton du sommaire, posé par le script avec le reste. */

/* ── La gamme, sur l'accueil ────────────────────────────────────────────
   Six logiciels, une carte chacun : ce que c'est, où ça tourne, chez qui.
   C'est là que l'écosystème se présente, pas dans un menu. */
/* Deux groupes : le socle sur quatre colonnes, les deux applications sur
   deux - plus larges, parce qu'elles sont deux et qu'on les cherche. */
.gamme { display: grid; gap: 18px; }
@media (min-width: 700px) { .gamme { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) {
  .gamme-socle { grid-template-columns: repeat(4, 1fr); }
  .gamme-applications { grid-template-columns: repeat(2, 1fr); }
}
/* Le tiret est un marqueur à part, pas un morceau de la première ligne :
   sur un téléphone, « Deux applications, pour aller plus vite » passe à la
   ligne, et la suite revenait se ranger sous le tiret plutôt que sous le
   premier mot. */
.gamme-titre { display: flex; align-items: flex-start; gap: 12px; margin: 30px 0 14px; font-size: 1.15rem; letter-spacing: -.01em; color: var(--text); }
.gamme-titre::before { content: ""; flex: none; width: 22px; height: 3px; border-radius: 2px; background: var(--accent); margin-top: .62em; }
.gamme-titre:first-of-type { margin-top: 0; }
.gamme article { padding: 26px 26px 22px; border: 1px solid var(--border); border-radius: 16px; background: var(--surface); display: flex; flex-direction: column; }
.gamme article.chez-nous { background: var(--bg-alt); }
/* ── La vignette d'une carte ──────────────────────────────────────────
   Un dessin par logiciel, et ce qu'il dessine est ce que le logiciel fait,
   jamais son écran : une capture inventée se lirait comme une capture, et
   le site n'en porte aucune. Le trait est celui des signes du menu, et la
   couleur d'accent ne porte que le mouvement - ce qui va vers le hub, ce
   qui en sort, ce qui est coupé par défaut.

   **Une taille fixe, pas une largeur.** Les cartes des applications font
   le double des autres ; un dessin en pourcentage y aurait doublé, et les
   six n'auraient plus eu l'air d'une famille. */
.vignette { display: block; width: 200px; max-width: 100%; height: 80px; margin: 0 0 16px; }
.vignette .trait,
.vignette .flux { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.vignette .trait { stroke: var(--text-dim); stroke-width: 1.6; }
.vignette .plein { fill: var(--text-dim); }
.vignette .flux { stroke: var(--accent); stroke-width: 1.8; }
.vignette .flux-plein { fill: var(--accent); }
.vignette .pointille { stroke-dasharray: 3 4; }
/* Le fond de la carte « chez nous » est déjà gris : le dessin y reprend un
   ton plus soutenu, sans quoi il s'efface. */
.gamme article.chez-nous .vignette .trait { stroke: var(--text-muted); }
.gamme article.chez-nous .vignette .plein { fill: var(--text-muted); }
.gamme .ou { margin: 0 0 8px; font-family: var(--mono); font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }
.gamme h3 { margin: 0 0 8px; font-size: 1.2rem; }
/* Seule la description s'étire : le sur-titre est aussi un `p`, et il
   poussait le titre de la carte la moins remplie vers le bas. */
.gamme p { margin: 0 0 12px; color: var(--text-muted); }
/* Les paragraphes se suivent ; ce sont les puces qui descendent au bas de la
   carte. Le premier paragraphe a été étiré à la place, et sur une carte à
   trois paragraphes le vide s'ouvrait au milieu du texte. */
.gamme .ou { flex: none; }
.gamme .puces { margin: auto 0 14px; padding-top: 6px; }

/* ── La page des tarifs, en bandes ─────────────────────────────────────
   Tout dans le cadre : le titre, les quatre cartes de front, l'abonnement et
   les prestations côte à côte, puis le détail en deux colonnes - chaque
   section dans sa case, à une largeur de lecture de soixante-quinze signes.
   Elle a été un article à colonne étroite dont les cartes débordaient. */
.tarifs { padding: clamp(44px, 6vw, 72px) 0 clamp(64px, 9vw, 108px); }
.tarifs .article-title { max-width: 24ch; }
.tarifs .article-chapo { max-width: 70ch; }
.tarifs .offers { margin-top: 34px; }
.tarifs-duo { display: grid; gap: 22px; margin-top: 22px; align-items: start; }
@media (min-width: 1100px) { .tarifs-duo { grid-template-columns: 1.15fr 1fr; } }
.tarifs-duo .abonnement, .tarifs-duo .prestations { margin: 0; }
.tarifs .offres-dit { margin: 22px 0 0; }
.tarifs-detail { display: grid; gap: 22px; margin-top: 48px; align-items: start; }
@media (min-width: 1000px) { .tarifs-detail { grid-template-columns: 1fr 1fr; } }
.tarifs-detail .detail {
  padding: 30px 32px 26px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  max-width: 78ch;
}
.tarifs-detail .detail > h2 { margin: 0 0 14px; font-size: 1.45rem; letter-spacing: -.02em; }
.tarifs-detail .detail > h2:first-child { margin-top: 0; }
.tarifs-detail .detail p { color: var(--text-muted); }
.tarifs-detail .detail p:last-child { margin-bottom: 0; }
.tarifs-detail .detail .note { margin: 18px 0 0; }
.tarifs-detail .detail h3 { font-size: 1.05rem; margin: 20px 0 8px; }

/* La page de la gamme : un bandeau court, puis des bandes comme l'accueil. */
.gamme-page { padding-bottom: 0; }
.gamme-page .article-title { max-width: 30ch; }
.gamme-page .article-chapo { max-width: 70ch; }
.gamme-page .hero-actions { justify-content: flex-start; margin-bottom: clamp(36px, 5vw, 56px); }

/* ── La page des tarifs, le parcours ──────────────────────────────────
   Les cartes, puis « composez la vôtre », puis cinq questions dans l'ordre
   où l'on se les pose, puis tout le détail en dépliants. Douze sections en
   deux colonnes, dans l'ordre où elles avaient été écrites, se lisaient
   comme un bazar : les sujets se répétaient, et rien ne disait qu'entre
   deux cartes il y a une licence. */
.tarifs { padding-bottom: clamp(44px, 6vw, 64px); }
.composer {
  margin: 22px 0 0;
  padding: 24px 28px;
  border: 1.5px dashed var(--accent);
  border-radius: 16px;
  background: #FFF9F4;
}
.composer-dit { color: var(--text-muted); margin-bottom: 16px; }
.composer-dit b { display: block; color: var(--text); font-size: 1.1rem; margin-bottom: 4px; }
.composer-champs { display: grid; gap: 14px; align-items: end; }
@media (min-width: 900px) { .composer-champs { grid-template-columns: repeat(4, 1fr) auto; } }
.composer .field { margin: 0; }
.composer .field label { font-size: .8rem; color: var(--text-dim); }
.composer .btn { white-space: nowrap; }

.tarifs-deux, .tarifs-trois, .tarifs-quatre { display: grid; gap: 22px; }
@media (min-width: 760px) { .tarifs-deux { grid-template-columns: 1fr 1fr; } .tarifs-trois, .tarifs-quatre { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .tarifs-trois { grid-template-columns: repeat(3, 1fr); } .tarifs-quatre { grid-template-columns: repeat(4, 1fr); } }
.carte { padding: 28px; border: 1px solid var(--border); border-radius: 16px; background: var(--surface); }
.carte h3 { margin: 0 0 10px; font-size: 1.2rem; }
.carte p { margin: 0 0 10px; color: var(--text-muted); }
.carte p:last-child { margin-bottom: 0; }
.carte .ticks { margin: 0; padding: 0; list-style: none; }
.carte .ticks li { margin-bottom: 8px; }
.carte.sombre { background: var(--bleu); border-color: var(--bleu); color: var(--on-accent); }
.carte.sombre h3 { color: var(--on-accent); }
.carte.sombre p { color: #BFD3DD; }
.moins { margin: 0; padding: 0; list-style: none; color: var(--text-muted); }
.moins li { position: relative; padding-left: 26px; margin-bottom: 8px; }
.moins li::before { content: ""; position: absolute; left: 4px; top: .72em; width: 11px; height: 2px; background: var(--text-dim); }
.tarifs .calc-note { margin: 22px 0 0; max-width: 100ch; }

.deplis { display: grid; gap: 10px; }
.depli { border: 1px solid var(--border); border-radius: 14px; background: var(--surface); padding: 0 26px; }
.depli summary { cursor: pointer; list-style: none; padding: 18px 0; font-weight: 700; font-size: 1.08rem; }
.depli summary::-webkit-details-marker { display: none; }
.depli summary::after { content: "+"; float: right; color: var(--accent); font-weight: 700; }
.depli[open] summary::after { content: "−"; }
.depli-corps { padding: 0 0 22px; max-width: 78ch; }
.depli-corps p { color: var(--text-muted); }
.depli-corps h3 { font-size: 1.05rem; margin: 18px 0 8px; }
.depli-corps .abonnement { margin: 0; padding: 0; border: 0; background: transparent; }
.depli-corps .note { margin: 16px 0 0; }
.tarifs-final .section-head { max-width: 62ch; }
