/* ============================================================================
   ROBUR — le SITE VITRINE
   Dépend de `tokens.css`, `components.css` et `hierarchie.css`, qui sont des
   COPIES VERBATIM de `design/`. On ne les édite pas ici : `outils/synchroniser.sh`
   les recopie depuis la source. Ce fichier ne contient que ce qui n'existe que
   sur la vitrine — une vitrine n'est pas un écran d'application, elle a une
   ouverture, des emplacements de téléchargement et un pied de page.

   AUCUNE VALEUR EN DUR. Deux exceptions, et les deux sont commentées sur place :
   les points de rupture (une largeur d'écran n'est pas un jeton de conception)
   et les épaisseurs de trait en unités du repère SVG (elles s'échelonnent avec
   le dessin, ce ne sont pas des pixels).

   LA PAGE EST AUTONOME : pas de CDN, pas de fonte distante, pas de script
   tiers, pas de mesure d'audience. Une page qui promet que les données de santé
   ne quittent pas le téléphone et qui appelle Google Fonts au chargement se
   contredit à sa première ligne.
   ============================================================================ */

/* ── Coquille ───────────────────────────────────────────────────────────────
   `.contenu` de `components.css` réserve la place de la barre d'onglets de
   l'application ; ici il n'y en a pas. La vitrine a donc sa propre coquille. */
.page {
  min-height: 100dvh;
  display: grid;
  grid-template-rows: auto 1fr auto;   /* tête · corps · pied */
}

/* La mesure du corps. `--largeur-app` (78rem) est la mesure d'un SaaS à rails ;
   une page qui se lit en continu a besoin de moins, sinon les titres partent à
   un demi-écran de leur texte. 64rem tient trois colonnes de dessins ou deux
   colonnes de texte, et pas davantage. Locale : cette mesure ne sert qu'ici. */
.bande {
  --mesure-site: 64rem;
  width: 100%;
  max-width: var(--mesure-site);
  margin-inline: auto;
  padding-inline: var(--gouttiere);
}

/* Lien d'évitement. Il n'est visible qu'au clavier — mais alors il l'est
   vraiment : posé sur le fond de page, à l'encre, avec l'anneau de focus. */
.saut {
  position: absolute;
  left: var(--space-2);
  top: calc(var(--inset-haut) + var(--space-2));
  z-index: calc(var(--z-barre) + 1);
  padding: var(--space-2) var(--space-3);
  background: var(--c-surface);
  border: var(--trait-fort);
  border-radius: var(--radius-sm);
  color: var(--c-text);
  font-size: var(--text-sm);
  font-weight: var(--poids-demi);
  transform: translateY(-200%);
}
.saut:focus { transform: none; }

/* ── En-tête ────────────────────────────────────────────────────────────────
   Même grammaire que `.entete` de l'application (marque à gauche, filet en bas,
   fond translucide), mais la vitrine n'a pas de pastille de profil : elle ne
   sait pas à qui elle parle, et elle n'a rien à afficher à cette place. */
.tete {
  position: sticky; top: 0; z-index: var(--z-barre);
  background: color-mix(in oklab, var(--c-bg) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: var(--trait);
}
.tete__rang {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: var(--cible-min);
  padding-block: calc(var(--inset-haut) + var(--space-3)) var(--space-3);
}
.tete__marque {
  display: inline-flex; align-items: center; gap: var(--space-2);
  color: var(--c-accent); text-decoration: none;
}
.tete__marque svg { width: 26px; height: 26px; display: block; }
.tete__mot {
  font-family: var(--font-titre); font-variation-settings: var(--fv-titre);
  font-optical-sizing: none; font-weight: var(--poids-gras);
  font-size: var(--text-lg); letter-spacing: var(--tracking-marque);
  color: var(--c-text);
}

/* La navigation d'ancres n'apparaît qu'à partir de 40rem. En dessous, elle
   volerait deux lignes à l'ouverture pour proposer de sauter dans une page
   qu'on n'a pas encore commencé à lire — et le seul lien qui compte (obtenir
   l'application) reste, lui, présent à toutes les largeurs. */
.tete__nav { display: none; margin-left: auto; gap: var(--space-5); }
.tete__nav a {
  display: inline-flex; align-items: center; min-height: var(--cible-min);
  color: var(--c-text-muted); font-size: var(--text-sm); font-weight: var(--poids-moyen);
  text-decoration: none;
}
.tete__nav a:hover { color: var(--c-text); }
.tete__action { margin-left: auto; }

/* Point de rupture : ce n'est pas un jeton, c'est la largeur à laquelle le
   contenu cesse d'être à l'étroit. Mesurée sur le contenu, pas sur un appareil. */
@media (min-width: 40rem) {
  .tete__nav { display: flex; }
  .tete__action { margin-left: 0; }
}

/* ── L'ouverture ────────────────────────────────────────────────────────────
   Une seule idée, et elle est écrite en toutes lettres. Pas d'image de salle
   de sport, pas de dégradé, pas de « transformez votre corps » : le produit
   dit qu'il ne devine pas, la page ne peut pas ouvrir sur une promesse. */
.ouverture { padding-block: var(--space-8) var(--space-6); }

/* La bande d'état. Elle est en TÊTE, avant le titre, et c'est délibéré : une
   vitrine qui annoncerait la disponibilité en bas de page mentirait par ordre
   de lecture. Règle reprise du rapport : ce qui manque est annoncé AVANT le
   corps, un lecteur doit savoir sur quoi porte ce qu'il va lire. */
.etat {
  display: inline-flex; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--trait-fort); border-style: dashed;
  /* Rayon MOYEN et non plein : sur 360 px la phrase tient sur trois lignes, et
     une pastille à bouts ronds de trois lignes de haut devient un galet. Le
     rectangle arrondi supporte le retour à la ligne, la gélule non. */
  border-radius: var(--radius-md);
  font-size: var(--text-sm); color: var(--c-text-muted);
  margin-bottom: var(--space-5);
}
/* La pastille est en CONTOUR : dans la langue du système, le contour veut dire
   « à faire ». Un point plein dirait « fait », c'est-à-dire l'inverse. Elle est
   `aria-hidden` dans le balisage et doublée du mot, jamais seule.
   `margin-top` : alignée optiquement sur la hauteur d'x de la première ligne,
   pas sur le haut de la boîte — sinon elle flotte au-dessus du texte. */
.etat__puce {
  width: .6em; height: .6em; flex: none; border-radius: var(--radius-full);
  border: 2px solid var(--c-border-strong);
  margin-top: .45em;
}

.ouverture__titre {
  /* clamp sur des jetons : 36 px sur un téléphone, 56 px sur un écran large.
     Aucune valeur intermédiaire n'est écrite, c'est la viewport qui interpole. */
  font-size: clamp(var(--text-3xl), 6vw, var(--text-chiffre-xl));
  max-width: 18ch;                 /* mesure de titre, pas de texte */
  margin-bottom: var(--space-4);
}
.ouverture__these {
  font-size: var(--text-lg);
  color: var(--c-text-muted);
  max-width: var(--largeur-lecture);
  margin-bottom: var(--space-6);
}
.ouverture__gestes { display: flex; flex-wrap: wrap; gap: var(--space-3); }

/* ── Les trois refus ────────────────────────────────────────────────────────
   L'idée mémorable de la page. Tout ce qui distingue Robur est un REFUS, et
   trois suffisent à le montrer. Registre, pas cartes : trois filets et trois
   phrases. Le filet gauche est celui du système (`--filet-nature`), à l'encre —
   il dit « ceci est de la même nature », pas « attention ». */
.refus {
  list-style: none; margin: var(--space-8) 0 0; padding: 0;
  display: grid; gap: var(--space-4);
}
.refus li {
  border-left: var(--filet-nature) solid var(--c-text);
  padding-left: var(--space-4);
  max-width: var(--largeur-lecture);
}
.refus b {
  display: block;
  font-family: var(--font-texte);
  font-size: var(--text-lg); font-weight: var(--poids-demi);
  line-height: var(--leading-titre);
  margin-bottom: var(--space-1);
}
.refus span { display: block; font-size: var(--text-sm); color: var(--c-text-muted); }

@media (min-width: 52rem) {
  .refus { grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
  .refus li { max-width: none; }
}

/* ── Sections ───────────────────────────────────────────────────────────────
   `.section` et `.section__tete` viennent de `components.css` : mêmes petites
   capitales, même numéro en Fraunces, même filet de 2 px. C'est l'ornement
   unique du système et il porte l'ordre de lecture. La vitrine ne s'en invente
   pas un autre — c'est ce qui fait qu'elle et l'application sont le même objet. */
.section { margin-top: var(--space-10); scroll-margin-top: var(--space-12); }
.section__intro { font-size: var(--text-lg); max-width: var(--largeur-lecture); }

/* Sur 360 px, le titre de section et sa note se partagent 328 px : les deux se
   coupent en deux lignes imbriquées (« LE CADRE DE / SÉCURITÉ » face à
   « gratuit, sans / expiration ») et le filet perd sa ligne de base. La note
   prend donc sa propre rangée, sous le titre, et retourne à droite dès qu'il y
   a la place. Mobile d'abord : c'est le cas étroit qui est écrit par défaut. */
.section__tete { flex-wrap: wrap; }
.section__note { flex: 1 0 100%; margin-left: 0; }
@media (min-width: 34rem) {
  .section__note { flex: 0 1 auto; margin-left: auto; }
}

/* ── Le registre — étiquette à gauche, fait à droite ────────────────────────
   Repris de `.tarif` : deux colonnes, une ligne de base commune, un filet fin
   au-dessus. Il sert partout où il y a des couples « cas → règle » : les
   paliers d'âge, ce que le serveur sait et ne sait pas, les familles de mesure.
   Le filet est DÉCORATIF (il aère) ; l'information est portée par les mots et
   par l'alignement, jamais par le trait. */
   Balisage : `<dl>` + un `<div>` par couple (autorisé en HTML5) quand il s'agit
   d'une définition ; `<ul>`/`<li>` quand il s'agit d'une énumération. Les deux
   sélecteurs sont là parce que la forme du contenu commande le balisage, pas
   l'inverse. */
.registre { list-style: none; margin: 0; padding: 0; max-width: var(--largeur-lecture); }
.registre > li,
.registre > div {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1) var(--space-4);
  padding: var(--space-3) 0;
  border-top: var(--trait);
}
.registre dt, .registre__cle {
  font-size: var(--text-sm); font-weight: var(--poids-demi);
  text-transform: uppercase; letter-spacing: var(--tracking-etiquette);
  color: var(--c-text);
}
.registre dd, .registre__val {
  margin: 0; font-size: var(--text-sm); line-height: var(--leading-normal);
  color: var(--c-text-muted);
}
/* À partir de 34rem la colonne d'étiquettes tient sans casser les mots. En
   dessous, l'étiquette passe au-dessus de sa valeur : deux colonnes sur 360 px
   donneraient « MOINS DE » / « 12 ANS » sur deux lignes, ce qui n'est plus une
   étiquette mais un bégaiement. */
@media (min-width: 34rem) {
  .registre > li,
  .registre > div { grid-template-columns: 13rem minmax(0, 1fr); align-items: baseline; }
}

/* Deux registres côte à côte : « ce que le serveur sait » / « ce qu'il ignore ».
   Ils ne se comparent QUE s'ils sont à la même hauteur d'œil. */
.deux-colonnes { display: grid; gap: var(--space-6); }
@media (min-width: 46rem) { .deux-colonnes { grid-template-columns: 1fr 1fr; gap: var(--space-8); } }
.colonne__titre {
  font-family: var(--font-texte);
  font-size: var(--text-sm); font-weight: var(--poids-demi);
  text-transform: uppercase; letter-spacing: var(--tracking-etiquette);
  color: var(--c-text); margin-bottom: var(--space-3);
}
/* La colonne « ce que le serveur ne sait pas » est en POINTILLÉ. C'est la même
   grammaire que partout ailleurs dans Robur : ce qui n'existe pas se dessine en
   pointillé, jamais en gris. Un trou est un trou, il ne se maquille pas. */
.colonne--absent .registre > li,
.colonne--absent .registre > div { border-top-style: dashed; border-top-color: var(--c-border-strong); }

/* Liste à puces simple, un fait par ligne, filet d'aération entre les lignes. */
.faits { list-style: none; margin: 0; padding: 0; max-width: var(--largeur-lecture); }
.faits li {
  padding: var(--space-3) 0; border-top: var(--trait);
  font-size: var(--text-sm); line-height: var(--leading-normal);
}
.faits li:first-child { border-top: 0; }

/* Variante à deux colonnes, réservée aux listes qui vivent EN PLEINE PAGE.
   La même classe sert dans la carte de la formule, large de 34rem : une règle
   qui se déclencherait sur la seule largeur de fenêtre y couperait la liste en
   deux colonnes de 12rem. D'où un modificateur explicite plutôt qu'une media
   query posée sur `.faits` — la largeur de la fenêtre ne dit rien de la largeur
   du conteneur. */
@media (min-width: 52rem) {
  .faits--large {
    max-width: none;
    columns: 2; column-gap: var(--space-8);
  }
  /* `break-inside` : sans lui, un fait de trois lignes se coupe entre les deux
     colonnes et son filet supérieur se retrouve orphelin en bas de la première. */
  .faits--large li { break-inside: avoid; }
  /* Le premier élément de la SECONDE colonne n'est pas `:first-child` : il porte
     donc un filet, que le premier de la PREMIÈRE colonne n'a pas. Les deux
     colonnes ne démarrent alors pas à la même hauteur, et l'œil le voit
     immédiatement. On rend son filet au premier élément : en deux colonnes, le
     trait de tête devient une ligne de départ commune, ce qu'il n'est pas en
     colonne unique (où il ferait doublon avec le blanc du paragraphe au-dessus). */
  .faits--large li:first-child { border-top: var(--trait); }
}

/* ── La note ────────────────────────────────────────────────────────────────
   Ce que la page doit dire mais qui n'est pas l'argument : l'avertissement
   médical, la conséquence assumée d'une décision, la source d'un chiffre.
   Filet gauche, texte en estompe, aucun fond coloré : ce n'est ni une alerte
   ni une réclame. */
.note {
  border-left: var(--filet-statut) solid var(--c-border-strong);
  padding-left: var(--space-4);
  margin-top: var(--space-5);
  font-size: var(--text-sm); color: var(--c-text-muted);
  max-width: var(--largeur-lecture);
}
.note strong { color: var(--c-text); font-weight: var(--poids-demi); }

/* La citation du rapport. Encadrée par un filet de 2 px à gauche — le même que
   le filet de section — parce qu'elle est du même ordre : elle porte une règle,
   pas un ornement. En Fraunces, comme tout ce qui se lit lentement. */
.citation {
  margin: var(--space-5) 0 0;
  border-left: var(--regle) solid var(--c-text);
  padding-left: var(--space-5);
  max-width: var(--largeur-lecture);
}
.citation p {
  font-family: var(--font-titre); font-variation-settings: var(--fv-titre);
  font-optical-sizing: none; font-weight: var(--poids-normal);
  font-size: var(--text-lg); line-height: var(--leading-normal);
  margin-bottom: var(--space-2);
}
.citation footer { font-size: var(--text-sm); color: var(--c-text-muted); }

/* ── Les disciplines ────────────────────────────────────────────────────────
   Vingt-huit noms. En colonne verticale ils feraient vingt-huit lignes qui
   hurlent « fonctionnalité » ; en énumération courante ils tiennent en quatre
   lignes et se lisent comme une liste, ce qu'ils sont.

   LE SÉPARATEUR EST UN FILET, PAS UN CARACTÈRE. Un point médian posé en
   `content:` est du texte généré, et une partie des lecteurs d'écran l'énonce :
   on entendrait « musculation, point médian, calisthénie ». Une bordure ne
   s'énonce jamais. C'est aussi, littéralement, le filet du système. */
.disciplines {
  list-style: none; margin: var(--space-5) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2) 0;
  max-width: var(--largeur-lecture);
}
.disciplines li {
  font-size: var(--text-sm); color: var(--c-text-muted);
  padding-inline: var(--space-3);
  border-left: var(--trait);
}
.disciplines li:first-child { padding-left: 0; border-left: 0; }

/* ── Les dessins d'exercice ─────────────────────────────────────────────────
   Copie de la partie DESSIN de `app/src/exos.css` (la partie « fiche » ne sert
   pas ici). Les nombres nus sont des épaisseurs en unités du repère SVG
   (viewBox 160 × 120) : ils s'échelonnent avec le dessin, ce ne sont pas des
   pixels, et il n'existe pas de jeton pour ça. Le SVG ne connaît AUCUNE
   couleur : tout vient d'ici, donc du thème. */
.exo-illu { display: block; width: 100%; height: auto; -webkit-user-select: none; user-select: none; }
.exo-sol { fill: none; stroke: var(--c-border-strong); stroke-width: 2; }
.exo-decor { fill: none; stroke: var(--c-border-strong); stroke-width: 2; }
.exo-axe { fill: none; stroke: var(--c-text-subtle); stroke-width: 1.5; stroke-dasharray: 2 4; }
.exo-traj, .exo-pointe {
  fill: none; stroke: var(--c-accent);
  stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
}
.exo-traj { stroke-dasharray: 5 4; }
.exo-corps { fill: none; stroke: var(--c-text); stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.exo-artic { fill: none; stroke: var(--c-text); stroke-width: 6.5; stroke-linecap: round; }
.exo-cable { fill: none; stroke: var(--c-border-strong); stroke-width: 1.5; stroke-linecap: round; }
.exo-poulie { fill: none; stroke: var(--c-border-strong); stroke-width: 2; }
.exo-charge { fill: var(--c-text); stroke: none; }

.exo-scene { margin: 0; }
.exo-scene .exo-illu, .exo-pose .exo-illu {
  background: var(--c-bg); border: var(--trait); border-radius: var(--radius-md);
}
.exo-scene__legende, .exo-pose__nom {
  display: block; margin-top: var(--space-2);
  font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-etiquette); color: var(--c-text-muted);
  text-align: center;
}
.exo-poses { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--space-3); }
.exo-pose { margin: 0; min-width: 0; }

/* Ce qu'on affiche quand il n'y a PAS de dessin. Le point le plus important de
   la section : on ne sert jamais un mouvement approchant. L'absence est en
   pointillé, comme tout ce qui manque dans Robur. */
.exo-manque {
  display: grid; place-items: center; gap: var(--space-2);
  min-height: 8rem; padding: var(--space-5) var(--space-4);
  text-align: center;
  background: var(--c-bg); border: var(--trait-fort); border-style: dashed;
  border-radius: var(--radius-md);
}
.exo-manque__mot {
  font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-etiquette); color: var(--c-text-muted);
}
.exo-manque p { margin: 0; font-size: var(--text-sm); color: var(--c-text-muted); }

/* La planche de dessins de la vitrine. `minmax(0, …)` et non `minmax(9rem, …)` :
   sur 360 px moins les gouttières il reste 328 px, et une colonne minimale de
   9rem forcerait un débordement horizontal dès qu'un dessin s'élargit. Le
   contenu large ne fait JAMAIS défiler la page. */
.planche { display: grid; gap: var(--space-5); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 34rem) { .planche { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 58rem) { .planche { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* Le dessin refusé et son explication. Ce n'est PAS une planche : il y a un
   dessin et du texte, et le texte a besoin d'une mesure de lecture. Sur une
   grille à quatre colonnes il se serait retrouvé dans une gouttière. */
.duo-manque { display: grid; gap: var(--space-5); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 46rem) {
  .duo-manque { grid-template-columns: minmax(0, 18rem) minmax(0, 1fr); gap: var(--space-6); align-items: start; }
}

.dessin { margin: 0; min-width: 0; }
.sous-section { margin-top: var(--space-8); }

/* La carte de la formule. `--largeur-lecture` et non une valeur inventée : le
   registre des tarifs se lit, il ne se scanne pas en colonnes. */
.carte--formule { max-width: var(--largeur-lecture); }

/* La famille de mesure d'un dessin. En --c-text-muted (7,04:1) et NON en
   --c-text-subtle (4,12:1) : `hierarchie.css` réserve le niveau 5 à la
   REDONDANCE, et ce mot-là est la seule source de l'information « ce mouvement
   appartient à la famille charge ». Un texte de niveau 5 qui porte une
   information seule, c'est le niveau qui est faux, pas la teinte. */
.dessin__famille {
  display: block; margin-bottom: var(--space-2);
  font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-etiquette); color: var(--c-text-muted);
}
.dessin__nom {
  display: block; font-size: var(--text-base); font-weight: var(--poids-demi);
  margin-bottom: var(--space-3);
}

/* Les deux lectures d'un dessin. `--anime` est servie par défaut ; `--fixe`
   (les positions clés côte à côte) prend sa place en mouvement réduit. Ce n'est
   pas une version dégradée : deux images fixes se comparent mieux qu'une boucle
   ne se suit — c'est la même décision que `exos/fiche.js` dans l'application.

   POURQUOI LES DEUX LECTURES SONT DANS LA PAGE, ET PAS CHOISIES PAR SCRIPT
   L'application décide à la construction, en JavaScript, parce qu'elle en a
   déjà. La vitrine n'a AUCUN script, et c'est un choix : une page qui promet
   qu'elle n'appelle rien à l'extérieur se lit mieux si elle n'exécute rien du
   tout. Le prix est de ~4 ko de balisage en double, et une réserve honnête :
   `display: none` retire l'illustration animée du rendu et de l'arbre
   d'accessibilité, mais n'arrête pas formellement le `<animate>` SMIL, qu'aucune
   règle CSS ne peut arrêter. Rien de visible ne bouge — la promesse est tenue
   à l'écran ; l'horloge, elle, continue de tourner dans le vide. */
.dessin__fixe { display: none; }
@media (prefers-reduced-motion: reduce) {
  .dessin__anime { display: none; }
  .dessin__fixe { display: block; }
}

/* ── Les emplacements de téléchargement ─────────────────────────────────────
   TROIS CANAUX, UNE SEULE ANATOMIE : un titre, un état écrit, un cadre carré à
   la taille exacte d'un QR, et une phrase qui dit quoi faire aujourd'hui.
   Le jour où un QR existe, il se pose DANS le cadre et rien ne bouge autour.

   POURQUOI PAS DE BADGE « TÉLÉCHARGER DANS L'APP STORE » NI « DISPONIBLE SUR
   GOOGLE PLAY » : ces marques ont des règles d'usage, et surtout un badge
   officiel AFFIRME une disponibilité. L'application n'est publiée sur aucun
   magasin. Une vitrine qui l'afficherait abîmerait exactement ce que le produit
   vend — le refus de deviner. Les plateformes sont donc nommées en toutes
   lettres, dans la typographie de la page. */
.canaux {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--space-4); grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 46rem) { .canaux { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.canal {
  display: flex; flex-direction: column; gap: var(--space-3);
  background: var(--c-surface); border: var(--trait);
  border-radius: var(--radius-md); padding: var(--space-4);
}
.canal__tete { display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.canal__nom { font-size: var(--text-lg); font-weight: var(--poids-demi); }
/* L'état est un MOT, dans un jeton de forme, jamais une couleur seule.
   `--ouvert` est plein (le plein veut dire fait), les autres sont en contour. */
.canal__etat {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--text-xs); font-weight: var(--poids-demi);
  text-transform: uppercase; letter-spacing: var(--tracking-etiquette);
  color: var(--c-text-muted);
}
.canal__etat::before {
  content: ''; width: .55em; height: .55em; border-radius: var(--radius-full);
  border: 2px solid var(--c-border-strong);
}
.canal[data-etat="ouvert"] .canal__etat { color: var(--c-text); }
.canal[data-etat="ouvert"] .canal__etat::before { background: var(--c-encre); border-color: var(--c-encre); }

/* LE CADRE. Sa taille est la même dans les deux états — c'est toute l'idée :
   poser le QR ne redessine pas la page. Carré, parce qu'un QR est carré. */
.canal__cadre {
  aspect-ratio: 1;
  width: 100%; max-width: 11rem;
  display: grid; place-items: center; align-content: center;
  gap: var(--space-2); padding: var(--space-3);
  border-radius: var(--radius-md);
  /* En attente : pointillé fort, fond de page. La même grammaire que
     `.exo-manque` et que la carte « rien de prévu » de l'application. Surtout
     pas un aplat gris « bientôt disponible » : un rectangle gris ne dit rien,
     et un faux QR décoratif mènerait nulle part une fois scanné. */
  background: var(--c-bg);
  border: var(--trait-fort); border-style: dashed;
  text-align: center;
}
.canal__mot {
  font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: var(--tracking-etiquette); color: var(--c-text-muted);
}
.canal__attente { margin: 0; font-size: var(--text-xs); color: var(--c-text-muted); }

/* Ouvert : le cadre devient une simple monture. Le QR apporte sa propre zone
   de silence et son propre fond clair (voir `outils/faire-qr.py`) — un lecteur
   optique a besoin d'un contraste franc, il ne suit pas le thème. */
.canal[data-etat="ouvert"] .canal__cadre {
  border-style: solid; border-color: var(--c-border); background: var(--c-surface);
  padding: 0;
}
.canal__qr { width: 100%; height: 100%; display: block; border-radius: var(--radius-sm); }

.canal__quoi { margin: 0; font-size: var(--text-sm); color: var(--c-text-muted); }
.canal__geste { margin-top: auto; }

/* Emplacement d'un lien qu'Adam n'a pas encore. Il se voit, il ne se clique
   pas, et il dit ce qu'il attend. Un `href="#"` qui ne mène nulle part serait
   la version web du faux QR. */
.a-remplir {
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-height: var(--cible-min); padding: var(--space-2) var(--space-3);
  border: var(--trait-fort); border-style: dashed; border-radius: var(--radius-sm);
  font-size: var(--text-sm); font-weight: var(--poids-demi); color: var(--c-text-muted);
}

/* ── Pied ───────────────────────────────────────────────────────────────────*/
.pied {
  margin-top: var(--space-12);
  border-top: var(--regle) solid var(--c-text);
  padding-block: var(--space-6) calc(var(--inset-bas) + var(--space-8));
  font-size: var(--text-sm); color: var(--c-text-muted);
}
.pied__rangs { display: grid; gap: var(--space-6); }
@media (min-width: 46rem) { .pied__rangs { grid-template-columns: 1.2fr 1fr 1fr; gap: var(--space-8); } }
.pied__titre {
  font-family: var(--font-texte);
  font-size: var(--text-xs); font-weight: var(--poids-demi);
  text-transform: uppercase; letter-spacing: var(--tracking-etiquette);
  color: var(--c-text); margin-bottom: var(--space-3);
}
.pied ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.pied a { color: var(--c-text-muted); }
.pied a:hover { color: var(--c-text); }
/* Même raison : cette ligne porte l'avertissement médical et la promesse
   « aucun cookie, aucun script ». Ce n'est pas de la mention d'unité, c'est du
   fond — donc --c-text-muted, 7,04:1, lisible au soleil comme le reste. */
.pied__mention { margin-top: var(--space-6); font-size: var(--text-xs); color: var(--c-text-muted); }

/* ── Garde-fou de largeur ───────────────────────────────────────────────────
   Rien ne fait défiler la page horizontalement. Les deux coupables habituels
   sont un mot long dans un titre et un SVG à largeur intrinsèque. */
html, body { overflow-x: clip; }
h1, h2, h3, .canal__nom, .dessin__nom { overflow-wrap: anywhere; }
img, svg { max-width: 100%; }
