/* ==================================================================
   Keiraku — charte graphique Rémy Serre Shiatsu Équin v2.0
   Charte « Encre », déclinaison sombre.

   L'application reste sur fond noir : un cheval couvert de 545 points
   colorés se lit mal sur clair, et l'éclairage de la scène 3D est réglé
   pour un fond sombre.

   ⚠️ L'interface y est volontairement SANS COULEUR. Les quatorze couleurs
   de méridiens sont des DONNÉES : violet et jade, notamment, ne sont pas
   décoratifs — ce sont le Vaisseau Gouverneur et le Vaisseau Conception.
   Les employer aussi pour des boutons, comme c'était le cas, revenait à
   peindre le mobilier avec l'encre des cartes. Le vermillon du sceau ne
   convient pas davantage pour le MOBILIER : il est à deux doigts de
   l'Intestin Grêle (#C23B3B), 6,7 d'écart ΔE. Le mobilier est donc en papier
   et en gris, et la couleur n'appartient qu'aux points.

   Deux exceptions, assumées.

   L'ambre des avertissements (#E3B04B) et le rouge d'un échec de révision
   (#E05C5C). Ce sont des SIGNAUX, pas du décor, et leur convention est plus
   forte que la gêne — un « à compléter » discret finit en ligne. Ils ne se
   posent jamais sur un code de point, contrairement au violet qui enveloppait
   les pastilles des tables jusqu'à ce jour.

   Le « RAKU » du mot-symbole, au sceau (#BF3B2E). C'est l'identité même du
   produit : la charte « Encre » ne tient qu'un seul rouge, et il sert à
   rattacher le nom japonais. Il était rouge sur la page d'offre et blanc dans
   l'application — un même logo de deux couleurs. La proximité avec l'Intestin
   Grêle ne joue pas ici : un mot n'est pas une pastille, il est dans la barre
   haute et jamais sur la scène. C'est le seul endroit de l'application où ce
   rouge paraît.
   ================================================================== */

/* Fontes de la charte « Encre », servies depuis le projet.
   Hébergées ici et non chez Google : l'application doit fonctionner hors
   connexion, et un appel au CDN transmet l'adresse IP du visiteur à un tiers.
   Sous-ensemble « latin » seulement — le latin étendu n'apporte aucun des
   caractères réellement employés (vérifié : ᵉ, ✦, ⚠, 経絡 n'y sont pas
   davantage et retombent sur la fonte système). */
@font-face { font-family: 'Newsreader'; src: url('../assets/fonts/newsreader-400-latin.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('../assets/fonts/newsreader-500-latin.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Newsreader'; src: url('../assets/fonts/newsreader-400i-latin.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'Inter'; src: url('../assets/fonts/inter-300-latin.woff2') format('woff2'); font-weight: 300; font-display: swap; }
@font-face { font-family: 'Inter'; src: url('../assets/fonts/inter-400-latin.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Inter'; src: url('../assets/fonts/inter-500-latin.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Inter'; src: url('../assets/fonts/inter-600-latin.woff2') format('woff2'); font-weight: 600; font-display: swap; }

:root {
  --encre: #131316;
  --papier: #EDEAE4;
  --sceau: #BF3B2E;           /* mot-symbole et erreurs — jamais sur la scène */
  /* 4,81:1 sur le panneau le plus clair de la charte, contre 4,38 avant —
     le seuil WCAG est à 4,5. Mesuré sur les trois fonds employés : fond de
     scène 5,56, panneau 5,20, panneau clair 4,81. */
  --gris: #918C85;

  --bg: #131316;
  --panel: #1A1A1D;
  --panel-2: #212125;
  --line: rgba(237,234,228,.14);
  --txt: #EDEAE4;
  --txt-dim: #9A958D;

  /* Accent du mobilier : le papier lui-même. Une teinte sans hue ne peut
     pas être confondue avec un méridien. */
  --accent: #EDEAE4;
  --accent-doux: rgba(237,234,228,.14);

  /* Anciens noms, le temps que tout le CSS bascule. */
  --violet: var(--accent);
  --violet-txt: var(--accent);
  --jade: var(--gris);
  --noir: var(--encre);
  --creme: var(--papier);
  --neutre: var(--papier);

  /* ---------------------------------------------------------------- */
  /* Matière, lumière, mouvement                                        */
  /*                                                                    */
  /* La charte s'interdit la couleur sur le mobilier (voir l'en-tête) : */
  /* tout le relief doit donc venir d'ailleurs. Trois familles de       */
  /* variables s'en chargent — une échelle d'élévation, un vernis de    */
  /* verre, et un vocabulaire de mouvement commun à tous les panneaux.  */
  /* Sans elles, chaque composant réinventait son ombre et sa durée, et */
  /* l'ensemble tombait à plat : un seul filet à 1 px partout.          */
  /* ---------------------------------------------------------------- */

  /* Ombres portées. Deux couches : un contact serré et très sombre, une
     diffusion large et douce. Une ombre à une seule couche paraît
     toujours collée ou sale. */
  --ombre-1: 0 1px 2px rgba(0,0,0,.4), 0 2px 8px -2px rgba(0,0,0,.35);
  --ombre-2: 0 2px 4px rgba(0,0,0,.45), 0 12px 28px -8px rgba(0,0,0,.6);
  --ombre-3: 0 4px 8px rgba(0,0,0,.5), 0 28px 64px -16px rgba(0,0,0,.75);

  /* Le trait de lumière du bord supérieur : c'est lui qui fait qu'une
     surface a une épaisseur au lieu d'être un aplat. */
  --lumiere: inset 0 1px 0 rgba(255,255,255,.055);

  /* Verre des panneaux flottants : le cheval doit continuer d'exister
     derrière eux. */
  --verre: rgba(22,22,25,.82);
  --verre-flou: saturate(140%) blur(22px);

  /* Mouvement. Une seule courbe pour tout ce qui entre et sort, une
     autre, plus vive, pour ce qui répond au doigt. */
  --sortie: cubic-bezier(.22,.61,.36,1);
  --ressort: cubic-bezier(.34,1.32,.64,1);
  --vite: 120ms;
  --moyen: 220ms;
  --ample: 380ms;

  --topbar-h: 58px;
  /* Hauteur du pied épinglé de la colonne, que le voile de défilement doit
     laisser libre. */
  --pied-h: 53px;
  /* 284 et non 268 : le sélecteur « Tous / Points clés / Shu du dos » se
     partage la largeur en trois, et « SHU DU DOS » ne tenait pas dans son
     tiers — les trois libellés se chevauchaient. Seize pixels de plus
     suffisent, et la colonne entière respire mieux. */
  --side-w: 284px;
  --detail-w: 380px;
  /* Largeur de la colonne de révision. Un peu plus que la fiche : un repère
     anatomique est une phrase, et se lit mal sur trois mots par ligne. */
  --rv-w: 400px;
  --r: 12px;

  --f-title: 'Newsreader', Georgia, 'Noto Serif CJK JP', serif;
  --f-ui: 'Inter', system-ui, -apple-system, sans-serif;
  --f-body: 'Inter', system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; overscroll-behavior: none; }

/* Le mouvement est un confort, jamais une condition pour comprendre
   l'écran. Qui demande à le réduire doit tout obtenir sans rien attendre :
   on ne ralentit pas, on supprime. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Entrées. Un panneau qui apparaît d'un coup se lit comme un défaut
   d'affichage ; le même, monté de huit pixels en deux dixièmes, se lit
   comme une réponse à ce qu'on vient de faire. */
@keyframes monte {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes glisse-droite {
  from { opacity: 0; transform: translateX(18px); }
  to   { opacity: 1; transform: none; }
}
@keyframes apparait {
  from { opacity: 0; }
  to   { opacity: 1; }
}

body {
  background: var(--bg);
  color: var(--txt);
  font-family: var(--f-body);
  /* 400, et non 300. Sur fond sombre, un texte trop maigre perd davantage
     encore que sur papier : les traits fins se referment à l'affichage. Le
     site marchand a été corrigé de la même manière. */
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

/* Halos radiaux « dark island » de la charte */
body::before {
  content: '';
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(64vw 52vh at 82% 6%,  rgba(237,234,228,.05), transparent 68%),
    radial-gradient(58vw 48vh at 12% 96%, rgba(237,234,228,.035), transparent 66%);
}

#app {
  position: relative; z-index: 1;
  height: 100%;
  display: grid;
  grid-template-columns: var(--side-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas: 'top top' 'side stage';
}
#app.has-detail { grid-template-columns: var(--side-w) 1fr var(--detail-w); grid-template-areas: 'top top top' 'side stage detail'; }
/* La révision prend la même troisième colonne que la fiche, et jamais les
   deux à la fois : pendant une série, la fiche est justement interdite
   puisqu'elle donne la réponse. Poser le panneau EN SURIMPRESSION masquait
   la croupe du cheval — c'est-à-dire l'endroit où il faut cliquer. */
#app.has-revision { grid-template-columns: var(--side-w) 1fr var(--rv-w); grid-template-areas: 'top top top' 'side stage revision'; }
/* La fiche est RETIRÉE de la grille pendant une série, et pas seulement
   masquée : sa zone `detail` n'existe pas dans la disposition ci-dessus, si
   bien qu'elle s'y fabriquait une colonne implicite de deux cents pixels.
   La scène s'en trouvait rétrécie d'autant et le cheval coupé. Elle n'a de
   toute façon rien à faire là : elle affiche le nom et le repère du point,
   c'est-à-dire la réponse. */
#app.has-revision .detail { display: none; }

/* ------------------------------------------------------------------ */
/* Barre supérieure                                                    */
/* ------------------------------------------------------------------ */

#topbar {
  grid-area: top;
  position: relative;
  display: flex; align-items: center; gap: 14px;
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: rgba(17,17,17,.72);
  backdrop-filter: saturate(140%) blur(14px);
  box-shadow: 0 1px 0 rgba(255,255,255,.03), 0 8px 24px -12px rgba(0,0,0,.8);
}
/* Un fil de lumière sous la barre, plus vif au centre. Il donne une arête à
   l'horizontale qui traverse tout l'écran et qui, sans lui, reste un simple
   trait gris. */
#topbar::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(to right,
    transparent, rgba(237,234,228,.16) 30%, rgba(237,234,228,.16) 70%, transparent);
  pointer-events: none;
}

/* Barre en trois colonnes : la marque et les actions poussent à parts égales
   pour que le champ de recherche tombe au milieu de la barre, et non au
   milieu de la place qui reste à droite de la marque. */
.brand {
  display: flex; align-items: baseline; gap: 8px;
  /* Elle s'étire pour équilibrer la barre, mais jamais en deçà de son
     propre texte : sinon le nom disparaît sur un écran étroit. */
  flex: 1 1 0; min-width: max-content;
}
.brand-mark { color: var(--jade); font-size: 14px; }
.brand-name {
  font-family: var(--f-ui); font-weight: 700; font-size: 21px;
  letter-spacing: 3px; text-transform: uppercase;
}
/* « RAKU » au sceau : voir l'exception consignée en tête de fichier. */
.brand-name em { font-style: normal; color: var(--sceau); font-weight: 400; }

/* Ni poussé à droite ni étiré : les deux pastilles qui l'équilibraient ont
   disparu, et « S'abonner » reste caché tant que l'état de l'abonnement est
   inconnu. Ce sont les deux colonnes latérales qui le maintiennent au centre. */
.search-wrap { position: relative; flex: 0 1 460px; }
.search-ico { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--gris); pointer-events: none; }
#search {
  width: 100%; height: 36px;
  padding: 0 34px 0 34px;
  background: var(--panel-2);
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--txt); font-family: var(--f-body); font-size: 14px;
  outline: none; transition: border-color .18s, box-shadow .18s;
}
#search::placeholder { color: #6d6862; }
#search:focus { border-color: var(--violet); box-shadow: 0 0 0 3px rgba(237,234,228,.14); }
#search::-webkit-search-cancel-button { display: none; }
#search-clear { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); }

.topbar-cale { flex: 1 1 0; }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px;
  background: transparent; border: 1px solid transparent; border-radius: 9px;
  color: var(--txt-dim); cursor: pointer; font-size: 14px;
}
.icon-btn:hover { background: rgba(245,240,234,.07); color: var(--txt); }
.icon-btn.small { width: 26px; height: 26px; font-size: 12px; }
#btn-menu { display: none; }

.chip-btn {
  height: 32px; padding: 0 13px;
  background: transparent;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--txt-dim); cursor: pointer;
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2px; text-transform: uppercase;
  transition: all .18s;
}
.chip-btn:hover { color: var(--txt); border-color: rgba(245,240,234,.3); }
.chip-btn[aria-pressed='true'] {
  background: rgba(237,234,228,.13); border-color: var(--accent); color: #fff;
}
.chip-btn.compte {
  background: var(--accent); border-color: var(--accent); color: var(--encre);
}
.chip-btn.compte:hover { background: var(--papier); border-color: var(--papier); color: var(--encre); }

/* ------------------------------------------------------------------ */
/* Panneau latéral                                                     */
/* ------------------------------------------------------------------ */

#sidebar {
  grid-area: side;
  position: relative;
  display: flex; flex-direction: column;
  border-right: 1px solid var(--line);
  background: rgba(20,20,20,.5);
  overflow: hidden;
}

/* Il reste du contenu sous la pliure.
   Cette colonne fait 1199 px pour 662 à 842 px de hauteur utile : sur un
   portable, la moitié des commandes est en dessous. La barre de défilement
   est en incrustation et ne se montre pas au repos ; sans ce voile, rien ne
   dit qu'il y a une suite. Il n'apparaît que si on n'est pas déjà en bas —
   un dégradé permanent ferait croire à du contenu inexistant. */
#sidebar::after {
  content: '';
  /* Au-dessus du pied épinglé, pas par-dessus. */
  position: absolute; left: 0; right: 0; bottom: var(--pied-h); height: 56px;
  background: linear-gradient(to top, var(--panel) 12%, rgba(26,26,29,0));
  opacity: 0; transition: opacity .18s;
  pointer-events: none;
}
#sidebar.a-suite::after { opacity: 1; }

.side-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 16px 14px 28px; }

/* Pied de colonne, hors défilement : voir le commentaire dans index.html. */
.side-pied {
  flex: 0 0 auto;
  padding: 10px 14px;
  border-top: 1px solid var(--line);
  background: var(--panel);
}
.side-pied .chip-btn { width: 100%; }
/* Rien à montrer tant que le bouton est caché — sur le serveur d'atelier,
   par exemple, où il n'y a pas d'abonnement à vendre. */
/* Le badge de l'école agrandit le pied : le fondu du haut doit remonter d'autant. */
#sidebar:has(.side-pied .badge-ecole) { --pied-h: 95px; }
#sidebar:not(:has(.side-pied .chip-btn:not([hidden]))) { --pied-h: 0px; }
#sidebar:not(:has(.side-pied .chip-btn:not([hidden]))) .side-pied { display: none; }
.side-scroll::-webkit-scrollbar { width: 8px; }
.side-scroll::-webkit-scrollbar-thumb { background: rgba(245,240,234,.14); border-radius: 4px; }

/* Les groupes de la colonne se posent l'un après l'autre, par paliers de
   45 ms. L'application se monte sous les yeux au lieu d'être déjà là : c'est
   ce décalage, très court, qui fait la différence entre un écran qui
   s'affiche et un écran qui s'ouvre. Le modèle 3D, lui, met plusieurs
   secondes — la colonne a tout le temps de s'installer avant lui. */
.side-block {
  margin-bottom: 26px;
  animation: monte var(--ample) var(--sortie) both;
}
.side-block:nth-child(1) { animation-delay: 40ms; }
.side-block:nth-child(2) { animation-delay: 85ms; }
.side-block:nth-child(3) { animation-delay: 130ms; }
.side-block:nth-child(4) { animation-delay: 175ms; }
.side-note, .side-legal { animation: apparait var(--ample) var(--sortie) 220ms both; }
/* 4 px d'interlettrage sur un corps de 14 faisait une ligne de capitales
   qu'on déchiffre au lieu de la lire — et qui ne tenait pas dans la colonne
   pour « MÉRIDIENS » face à « TOUT ». Ramené à 2,4, avec un filet qui prend
   le relais pour séparer les groupes : c'est le trait qui structure
   désormais, plus l'espacement des lettres. */
.side-h, .side-h-row h2 {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 11px;
  font-family: var(--f-ui); font-weight: 500; font-size: 12.5px;
  letter-spacing: 2.4px; text-transform: uppercase; color: var(--gris);
}
.side-h::after {
  content: ''; flex: 1 1 auto; height: 1px;
  background: linear-gradient(to right, var(--line), transparent);
}
/* Le filet vit dans la RANGÉE quand il y a un bouton à droite : posé dans le
   titre, il aurait poussé « TOUT » hors de la colonne. */
.side-h-row { margin-bottom: 11px; gap: 10px; }
.side-h-row h2 { margin: 0; flex: 0 0 auto; }
.side-h-row h2::after { display: none; }
.side-h-row::after {
  content: ''; order: 1; flex: 1 1 auto; height: 1px;
  background: linear-gradient(to right, var(--line), transparent);
}
.side-h-row .link-btn { order: 2; }
.side-h-row { display: flex; align-items: baseline; justify-content: space-between; }
/* `padding: 4px 0` et non `0` : sans lui la cible ne fait que 16 px de haut,
   sous le minimum de 24 px du critère WCAG 2.5.8 « taille de la cible ». On
   compense par une marge négative pour que rien ne bouge visuellement — cette
   appli se manie dans une écurie, parfois avec des gants. */
.link-btn {
  background: none; border: none; padding: 4px 0; margin: -4px 0; cursor: pointer;
  font-family: var(--f-ui); font-size: 13px; letter-spacing: 2px; text-transform: uppercase;
  color: var(--violet-txt);
}
.link-btn:hover { color: #fff; }

/* Sélecteur à trois volets.
   Les volets sont dimensionnés par LEUR CONTENU, en grille, et non en trois
   parts égales : « Tous » fait quatre lettres quand « Shu du dos » en fait
   dix, et le tiers fixe coupait les deux libellés longs. Le bandeau actif
   est un élément de grille placé dans la même colonne que le bouton allumé
   — il épouse donc exactement sa largeur, quelle qu'elle soit.
   Le compromis est assumé : une colonne de grille ne s'anime pas, on perd
   le glissement. Un libellé lisible vaut mieux qu'un bandeau qui coulisse. */
.seg {
  display: grid; grid-template-columns: repeat(3, auto); isolation: isolate;
  padding: 3px; margin-bottom: 12px;
  background: rgba(0,0,0,.28);
  border: 1px solid var(--line); border-radius: 11px;
  box-shadow: var(--lumiere);
}
/* Les quatre éléments sont placés À LA MAIN sur la même rangée. Laissé au
   placement automatique, le bandeau se fabriquait une quatrième colonne
   à lui et se retrouvait coincé entre deux boutons. */
.seg::before {
  content: ''; grid-row: 1; grid-column: 1; z-index: -1;
  background: rgba(237,234,228,.13);
  border: 1px solid rgba(237,234,228,.16);
  border-radius: 8px;
  box-shadow: var(--ombre-1), var(--lumiere);
}
.seg-btn:nth-child(1) { grid-area: 1 / 1; }
.seg-btn:nth-child(2) { grid-area: 1 / 2; }
.seg-btn:nth-child(3) { grid-area: 1 / 3; }
.seg:has(.seg-btn:nth-child(2).is-on)::before { grid-column: 2; }
.seg:has(.seg-btn:nth-child(3).is-on)::before { grid-column: 3; }
/* 11 px et un interlettrage réduit : « SHU DU DOS » doit tenir dans un tiers
   de 234 px, sinon les trois libellés se chevauchent et le bandeau glissant
   ne correspond plus à ce qu'on lit. */
.seg-btn {
  min-width: 0; height: 29px; padding: 0 11px;
  background: transparent; border: none; cursor: pointer;
  color: var(--txt-dim);
  font-family: var(--f-ui); font-size: 11px; letter-spacing: .5px; text-transform: uppercase;
  /* Si un libellé devait un jour déborder malgré tout, qu'il se coupe
     proprement plutôt que d'aller écraser son voisin. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color var(--moyen) var(--sortie);
}
.seg-btn:hover { color: var(--txt); }
.seg-btn.is-on { color: #fff; }

/* Cases à cocher dessinées, et non celles du navigateur : la case native
   arrive avec son bleu système, ses coins carrés et sa taille à elle —
   c'est le détail qui trahit une interface inachevée. */
.row-check {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; margin: 0 -8px; border-radius: 8px;
  font-size: 13.5px; cursor: pointer; color: var(--txt-dim);
  transition: background var(--vite) var(--sortie), color var(--vite) var(--sortie);
}
.row-check:hover { color: var(--txt); background: rgba(245,240,234,.05); }
.row-check input {
  appearance: none; -webkit-appearance: none;
  flex: 0 0 auto; width: 17px; height: 17px; margin: 0; cursor: pointer;
  background: rgba(0,0,0,.3);
  border: 1px solid rgba(237,234,228,.26); border-radius: 5px;
  transition: background var(--vite) var(--sortie), border-color var(--vite) var(--sortie);
}
.row-check:hover input { border-color: rgba(237,234,228,.45); }
.row-check input:checked {
  background: var(--accent); border-color: var(--accent);
}
/* La coche est tracée au trait, pas écrite en caractère : un glyphe change
   de dessin d'une plateforme à l'autre et se centre mal. */
.row-check input:checked::after {
  content: ''; display: block;
  width: 4.5px; height: 8.5px; margin: 1.5px auto 0;
  border: solid var(--encre); border-width: 0 2px 2px 0;
  transform: rotate(43deg);
}
.row-check input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

.mer-list { list-style: none; margin: 0 -8px; padding: 0; }
.mer-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px; border-radius: 8px; cursor: pointer;
  transition: background var(--vite) var(--sortie), opacity var(--moyen) var(--sortie);
}
.mer-item:hover { background: rgba(245,240,234,.06); }
.mer-item.is-off { opacity: .3; }
.mer-dot {
  width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto;
  box-shadow: 0 0 0 1px rgba(0,0,0,.4);
  transition: box-shadow var(--moyen) var(--sortie), transform var(--moyen) var(--ressort);
}
.mer-item:not(.is-off) .mer-dot {
  box-shadow: 0 0 0 1px rgba(0,0,0,.4), 0 0 10px -1px var(--c, transparent);
}
.mer-item:hover .mer-dot { transform: scale(1.18); }
.mer-code {
  font-family: var(--f-ui); font-weight: 700; font-size: 15px; letter-spacing: 1.5px;
  min-width: 26px; color: var(--txt);
}
.mer-name { font-size: 13px; color: var(--txt-dim); flex: 1; }
.mer-n { font-family: var(--f-ui); font-size: 13px; color: var(--gris); letter-spacing: 1px; }

.view-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.view-btn {
  height: 35px;
  background: linear-gradient(rgba(255,255,255,.045), rgba(255,255,255,.015));
  border: 1px solid var(--line); border-radius: 9px;
  box-shadow: var(--lumiere);
  color: var(--txt-dim); cursor: pointer;
  font-family: var(--f-ui); font-size: 12.5px; letter-spacing: 1.2px; text-transform: uppercase;
  transition: color var(--vite) var(--sortie), border-color var(--vite) var(--sortie),
              transform var(--vite) var(--sortie), box-shadow var(--vite) var(--sortie);
}
.view-btn:hover {
  color: #fff; border-color: rgba(237,234,228,.34);
  transform: translateY(-1px);
  box-shadow: var(--ombre-1), var(--lumiere);
}
/* L'enfoncement compte autant que le survol : sans lui, le bouton ne
   répond pas au doigt sur un écran tactile, où il n'y a pas de survol. */
.view-btn:active { transform: translateY(0) scale(.985); }

.side-note { font-size: 12px; line-height: 1.6; color: var(--gris); margin: 0; }
.side-legal { margin: 10px 0 0; font-size: 11.5px; color: var(--gris); }
.side-legal a {
  color: var(--gris); text-decoration: none;
  /* même raison : 14 px de haut sans cela. `inline-block` est nécessaire,
     un lien en ligne ignore le padding vertical pour le calcul de la cible. */
  display: inline-block; padding: 5px 2px; margin: -5px 0;
}
.side-legal a:hover { color: var(--txt-dim); text-decoration: underline; }

/* ------------------------------------------------------------------ */
/* Scène                                                               */
/* ------------------------------------------------------------------ */

#stage { grid-area: stage; position: relative; overflow: hidden; }
#view { display: block; width: 100%; height: 100%; cursor: grab; touch-action: none; }
#view:active { cursor: grabbing; }

#labels { position: absolute; inset: 0; pointer-events: none; }
/* Cinquante étiquettes à l'écran en même temps : chacune cerclée d'un trait
   plein à la couleur de son méridien, cela faisait cinquante rectangles
   colorés posés sur le cheval, et le cheval passait dessous. Le liseré est
   donc ramené à un peu plus de la moitié de son opacité, le fond gagne un
   flou qui décolle l'étiquette du pelage, et c'est la TIGE qui porte
   désormais la couleur franche — un trait fin se lit sans crier. */
.pt-label {
  position: absolute; top: 0; left: 0;
  padding: 2px 7px 1px;
  background: rgba(12,12,14,.74);
  backdrop-filter: blur(7px);
  border: 1px solid color-mix(in srgb, var(--c, #fff) 52%, transparent);
  border-radius: 5px;
  color: #fff;
  font-family: var(--f-ui); font-size: 12px; letter-spacing: .9px;
  white-space: nowrap; pointer-events: auto; cursor: pointer;
  transition: opacity var(--vite) var(--sortie),
              transform var(--vite) var(--sortie),
              border-color var(--vite) var(--sortie);
}
/* Au survol l'étiquette reprend sa couleur pleine et se soulève : sur un
   amas serré, c'est ce qui permet de viser sans cliquer au jugé. */
.pt-label:hover {
  border-color: var(--c, #fff);
  transform: translateY(-1px) scale(1.04);
  z-index: 3;
}
.pt-label::after {
  content: ''; position: absolute; left: 50%; top: 100%;
  width: 1px; height: 9px; background: var(--c, #fff); opacity: .7;
  transform: translateX(-50%);
}
.pt-label.is-dim { opacity: .3; }
/* Le point ouvert dans la fiche reste lisible même tourné à l'opposé : on
   l'a désigné, le griser avec les autres revient à le perdre. Le halo dit
   déjà qu'il est de l'autre côté. */
.pt-label.is-sel {
  background: var(--c, #fff); color: #111; font-weight: 700;
  border-color: var(--c, #fff);
  /* Deux halos : un serré qui détache du pelage, un large et très doux qui
     fait rayonner. Le point désigné doit se retrouver d'un coup d'œil dans
     un amas de cinquante. */
  box-shadow: 0 0 14px -2px var(--c), 0 0 34px -6px var(--c);
  opacity: 1;
  z-index: 4;
}

.legend {
  position: absolute; left: 14px; bottom: 14px;
  display: flex; flex-wrap: wrap; gap: 6px 12px; max-width: 60%;
  pointer-events: none;
}
.legend-item { display: flex; align-items: center; gap: 6px; font-family: var(--f-ui); font-size: 13px; letter-spacing: 1.5px; color: var(--txt-dim); }
.legend-dot { width: 9px; height: 9px; border-radius: 50%; }

#loading {
  position: absolute; inset: 0; display: grid; place-content: center; gap: 12px; justify-items: center;
  background: var(--bg); color: var(--gris);
  font-family: var(--f-ui); font-size: 15px; letter-spacing: 3px; text-transform: uppercase;
}
.spin { width: 26px; height: 26px; border: 2px solid rgba(237,234,228,.15); border-top-color: var(--accent); border-radius: 50%; animation: sp .8s linear infinite; }
@keyframes sp { to { transform: rotate(360deg); } }

/* Jauge de chargement.
   Le maillage pèse une douzaine de méga-octets : au fond d’une écurie,
   l'attente se compte en dizaines de secondes. Un rond qui tourne ne dit
   pas si l'on avance ; une barre, si. */
.jauge {
  width: 220px; height: 3px; border-radius: 2px;
  background: rgba(237,234,228,.12); overflow: hidden;
}
.jauge i {
  display: block; height: 100%; width: 0;
  background: var(--accent); border-radius: 2px;
  transition: width .25s ease-out;
}
/* Phase sans fraction connue : la barre balaie au lieu de rester à zéro. */
.jauge.indeterminee i {
  width: 38%; animation: balai 1.15s ease-in-out infinite;
}
@keyframes balai {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(264%); }
}

/* Résultats de recherche */
#results {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  width: min(440px, calc(100% - 28px)); max-height: 56%;
  /* Même verre que les autres panneaux flottants, et non un aplat presque
     opaque : la liste se pose SUR la scène, elle ne la remplace pas. */
  background:
    linear-gradient(rgba(255,255,255,.04), rgba(255,255,255,0) 90px),
    var(--verre);
  backdrop-filter: var(--verre-flou);
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--ombre-3), var(--lumiere);
  display: flex; flex-direction: column; overflow: hidden;
}
#results[hidden] { display: none; }   /* `display:flex` l'emporterait sur [hidden] */
.results-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 8px 8px 14px; border-bottom: 1px solid var(--line);
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2px; text-transform: uppercase; color: var(--gris);
}
#results-list { list-style: none; margin: 0; padding: 6px; overflow-y: auto; }
.res-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
}
.res-item:hover, .res-item.is-active { background: rgba(237,234,228,.09); }
.res-code { font-family: var(--f-ui); font-weight: 700; font-size: 15px; letter-spacing: 1px; min-width: 42px; }
.res-name { font-size: 13.5px; flex: 1; }
.res-name small { display: block; color: var(--gris); font-size: 12px; }

/* ------------------------------------------------------------------ */
/* Fiche du point                                                      */
/* ------------------------------------------------------------------ */

.detail {
  grid-area: detail;
  position: relative;
  border-left: 1px solid var(--line);
  /* Un dégradé très court en haut, et non un aplat : la fiche prend ainsi
     une source de lumière, comme une page posée sous une lampe. Sur un
     aplat parfaitement uniforme, un panneau de 380 px de large paraît
     toujours mort. */
  background:
    linear-gradient(rgba(255,255,255,.035), rgba(255,255,255,0) 180px),
    var(--panel);
  box-shadow: -1px 0 0 rgba(255,255,255,.04), var(--ombre-2);
  overflow-y: auto;
}
/* La fiche s'annonce au lieu de surgir. Elle ne rejoue qu'à l'ouverture :
   passer d'un point à l'autre ne la fait pas clignoter, puisque l'élément
   reste affiché. Le réglage « animations réduites » du système la neutralise
   par la règle globale plus haut. */
@keyframes fiche-entre {
  from { opacity: 0; transform: translateY(8px); }
}
.detail { animation: fiche-entre .2s ease-out both; }

.detail-close { position: absolute; top: 10px; right: 10px; z-index: 2; }
#detail-body { padding: 22px 22px 40px; }

.d-top { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 4px; }
.d-code {
  font-family: var(--f-ui); font-weight: 700; font-size: 34px; letter-spacing: 2px; line-height: 1;
}
.d-side {
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2px;
  border: 1px solid var(--line); border-radius: 5px; padding: 2px 7px; color: var(--txt-dim);
}
.d-int { font-family: var(--f-ui); font-size: 15px; letter-spacing: 2px; color: var(--gris); }
.d-pinyin { font-family: var(--f-title); font-size: 26px; font-weight: 500; margin: 6px 0 2px; }
.d-fr { font-family: var(--f-title); font-style: italic; font-size: 18px; color: var(--txt-dim); margin: 0 0 14px; }

.d-mer {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px 4px; border-radius: 999px; margin-bottom: 18px;
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2px; text-transform: uppercase;
}

.d-sec { margin-bottom: 20px; }
.d-sec h3 {
  margin: 0 0 7px;
  font-family: var(--f-ui); font-weight: 400; font-size: 13px;
  letter-spacing: 4px; text-transform: uppercase; color: var(--gris);
}
.d-sec p { margin: 0; font-size: 14.5px; line-height: 1.65; }
.d-sec.repere p { border-left: 2px solid var(--jade); padding-left: 12px; }
.d-sec.tech p { color: var(--txt-dim); font-size: 13.5px; line-height: 1.6; }

.tag-row { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  padding: 4px 10px 3px; border-radius: 999px;
  background: rgba(245,240,234,.07); border: 1px solid var(--line);
  box-shadow: var(--lumiere);
  font-size: 12.5px; color: var(--txt-dim);
  transition: background var(--vite) var(--sortie), color var(--vite) var(--sortie);
}
.tag:hover { background: rgba(245,240,234,.12); color: var(--txt); }
.tag.cat { border-color: rgba(237,234,228,.34); color: var(--papier); }

.badge {
  display: inline-block; padding: 2px 8px 1px; border-radius: 4px;
  font-family: var(--f-ui); font-size: 12px; letter-spacing: 1.5px; text-transform: uppercase;
}
.badge-warn { background: rgba(227,176,75,.16); color: #E3B04B; border: 1px solid rgba(227,176,75,.4); }
.badge-ok { background: rgba(237,234,228,.1); color: var(--txt-dim); border: 1px solid rgba(237,234,228,.28); }
.badge-cle { background: rgba(237,234,228,.14); color: var(--papier); border: 1px solid rgba(237,234,228,.42); }

.d-warn {
  margin: 0 0 18px; padding: 10px 12px;
  background: rgba(227,176,75,.09); border: 1px solid rgba(227,176,75,.3); border-radius: 8px;
  font-size: 13px; line-height: 1.55; color: #E8C87C;
}
/* Empilés, pas côte à côte : en capitales espacées, « Isoler ce méridien »
   ne tient pas dans une demi-colonne de 166 px et repassait à la ligne. */
.d-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 22px; }
/* Deux actions, deux poids. Les deux boutons étaient cerclés de papier plein
   et se disputaient le regard ; « Recadrer » est le geste courant, il prend
   le plein, « Isoler ce méridien » reste en retrait. */
.d-btn {
  flex: 1; height: 38px; border-radius: 9px; cursor: pointer;
  background: transparent;
  border: 1px solid rgba(237,234,228,.28); color: var(--txt);
  box-shadow: var(--lumiere);
  font-family: var(--f-ui); font-size: 13px; letter-spacing: 1.8px; text-transform: uppercase;
  transition: background var(--vite) var(--sortie), border-color var(--vite) var(--sortie),
              color var(--vite) var(--sortie), transform var(--vite) var(--sortie);
}
.d-btn:hover { border-color: var(--accent); background: rgba(237,234,228,.08); }
.d-btn:active { transform: scale(.985); }
.d-btn.principal {
  background: var(--accent); border-color: var(--accent); color: var(--encre);
  font-weight: 500;
}
.d-btn.principal:hover { background: #fff; border-color: #fff; }

/* ------------------------------------------------------------------ */
/* Responsive                                                          */
/* ------------------------------------------------------------------ */

@media (max-width: 1100px) {
  :root { --detail-w: 320px; --side-w: 236px; --rv-w: 360px; }
}

@media (max-width: 860px) {
  #app, #app.has-detail, #app.has-revision {
    grid-template-columns: 1fr;
    grid-template-rows: var(--topbar-h) 1fr;
    grid-template-areas: 'top' 'stage';
  }
  #btn-menu { display: inline-grid; }
  .brand-name { font-size: 18px; letter-spacing: 2px; }
  /* La cale ne sert qu'à centrer le champ quand la place le permet ; sur un
     téléphone, chaque pixel va au champ. */
  .topbar-cale { display: none; }

  #sidebar {
    position: fixed; z-index: 30; top: var(--topbar-h); bottom: 0; left: 0;
    width: 280px; background: var(--panel);
    transform: translateX(-102%); transition: transform .26s cubic-bezier(.4,0,.2,1);
    box-shadow: 24px 0 60px -20px rgba(0,0,0,.8);
  }
  #sidebar.is-open { transform: none; }

  /* En panneau bas, elle monte depuis le bord au lieu d'apparaître d'un
     bloc : le geste dit d'où elle vient et où la renvoyer. */
  @keyframes fiche-monte { from { transform: translateY(100%); } }
  .detail { animation: fiche-monte .26s cubic-bezier(.4,0,.2,1) both; }

  .detail {
    position: fixed; z-index: 31; left: 0; right: 0; bottom: 0;
    /* 55 vh et non 62 : il faut qu'il reste du cheval à regarder. */
    max-height: 55vh; border-left: none; border-top: 1px solid var(--line);
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -20px 60px -20px rgba(0,0,0,.85);
    padding-bottom: env(safe-area-inset-bottom);
  }
  #detail-body { padding: 20px 18px 32px; }
  .d-code { font-size: 28px; }
  .legend { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ------------------------------------------------------------------ */
/* Écran d'échec au démarrage                                          */
/* ------------------------------------------------------------------ */

#fatal {
  position: absolute; inset: 0; z-index: 40;
  display: grid; align-content: center; justify-items: start;
  gap: 4px; padding: 8vh clamp(20px, 6vw, 64px);
  background: var(--bg);
  overflow-y: auto;
}
#fatal[hidden] { display: none; }
.fatal-h {
  margin: 0 0 14px;
  font-family: var(--f-title); font-weight: 500; font-size: clamp(24px, 4vw, 34px);
  color: var(--txt);
}
#fatal-body { max-width: 62ch; font-size: 15px; line-height: 1.7; color: var(--txt-dim); }
#fatal-body p { margin: 0 0 14px; }
#fatal-body strong { color: var(--txt); font-weight: 500; }
#fatal-body code {
  padding: 1px 6px; border-radius: 4px;
  background: rgba(237,234,228,.09); color: var(--txt-dim);
  font-family: ui-monospace, monospace; font-size: 13.5px;
}
#fatal-body pre {
  margin: 0 0 14px; padding: 12px 14px;
  background: var(--panel-2); border: 1px solid var(--line);
  border-left: 2px solid var(--jade); border-radius: 8px;
  color: var(--txt); font-family: ui-monospace, monospace; font-size: 13.5px;
  overflow-x: auto;
}
#fatal-body .d-btn { flex: none; margin-top: 6px; padding: 0 18px; }

/* Cinq Éléments et provenance, dans la fiche du point */
.tag.elem { border-color: rgba(237,234,228,.34); color: var(--papier); }
.tag.act-tonification { border-color: rgba(237,234,228,.38); color: var(--papier); }
.tag.act-dispersion { border-color: rgba(227,176,75,.5); color: #E3B04B; }
.tag.act-ben { border-color: rgba(237,234,228,.3); color: var(--txt-dim); }
.d-src {
  margin: 10px 0 0;
  font-size: 12px; line-height: 1.5; color: var(--gris);
  font-style: italic;
}

/* Point situé sous la silhouette (face médiale du coude, de la hanche…) */
.d-note {
  margin: 0 0 18px; padding: 10px 12px;
  background: rgba(237,234,228,.06);
  border: 1px solid rgba(237,234,228,.2); border-radius: 8px;
  font-size: 13px; line-height: 1.55; color: var(--jade);
}
.d-note strong { color: #fff; font-weight: 500; }

/* ------------------------------------------------------------------ */
/* Bascule du mode édition                                             */
/* ------------------------------------------------------------------ */

.edit-btn {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; height: 38px;
  background: transparent; border: 1px solid var(--line); border-radius: 9px;
  color: var(--txt-dim); cursor: pointer;
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2.5px;
  text-transform: uppercase; transition: all .16s;
}
.edit-btn:hover { color: #fff; border-color: var(--violet); }
.edit-btn.is-on {
  background: rgba(237,234,228,.14); border-color: var(--accent); color: #fff;
}
.edit-ico { font-size: 15px; color: var(--violet-txt); }
.edit-btn.is-on .edit-ico { color: #fff; }
.edit-note {
  margin: 9px 0 0; font-size: 11.5px; line-height: 1.55; color: var(--jade);
}

/* Statut d'un point pendant l'édition, porté par son étiquette */
.pt-label.est-valide {
  border-color: var(--papier); box-shadow: 0 0 0 1px rgba(237,234,228,.55);
}
.pt-label.est-valide::before {
  content: '✓'; margin-right: 4px; color: var(--papier); font-weight: 700;
}
.pt-label.est-modif { border-color: #E3B04B; }
.pt-label.est-modif::before {
  content: '•'; margin-right: 4px; color: #E3B04B; font-weight: 700;
}
/* Verrouillé : le cadenas remplace la coche, sinon l'étiquette porterait les
   deux pour un point qui est presque toujours validé ET verrouillé. */
.pt-label.est-verrou { opacity: .72; }
.pt-label.est-verrou::before { content: '🔒'; margin-right: 3px; font-size: .85em; }
.edit-btn.revise { margin-bottom: 8px; }
.edit-btn.revise:hover { border-color: var(--jade); }
.edit-btn.revise .edit-ico { color: var(--jade); }

/* ------------------------------------------------------------------ */
/* Bandeau de démonstration                                            */
/* ------------------------------------------------------------------ */

.demo-bar {
  position: absolute; left: 14px; right: 14px; top: 12px; z-index: 20;
  display: flex; align-items: center; gap: 14px;
  padding: 10px 14px;
  background: rgba(26,26,29,.94); backdrop-filter: blur(12px);
  border: 1px solid rgba(237,234,228,.3); border-radius: var(--r);
}
.demo-txt { flex: 1; font-size: 13px; line-height: 1.5; color: var(--txt-dim); }
.demo-txt b { color: var(--violet-txt); font-weight: 500; }
.demo-cta {
  flex: 0 0 auto; height: 34px; padding: 0 18px;
  background: var(--violet); border: none; border-radius: 8px; color: #111;
  cursor: pointer;
  font-family: var(--f-ui); font-size: 14px; letter-spacing: 2.5px;
  text-transform: uppercase;
}
.demo-cta:hover { background: #fff; }
/* Le défi des 5 points, depuis le bandeau : doré, distinct de « S'abonner ». */
.demo-defi {
  flex: 0 0 auto; height: 34px; padding: 0 14px;
  background: transparent; border: 1px solid rgba(255,210,122,.55); border-radius: 8px; color: #ffd27a;
  cursor: pointer; font-family: var(--f-ui); font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase;
}
.demo-defi:hover { background: rgba(255,210,122,.1); }
/* Pendant le défi, le bandeau s'efface : la carte du jeu prend sa place. */
#stage.df-actif .demo-bar { display: none; }
.edit-btn.defi-btn { margin-bottom: 8px; }
.edit-btn.defi-btn:hover { border-color: #ffd27a; }
.edit-btn.defi-btn .edit-ico { color: #ffd27a; }
/* Même bandeau, ton d'information : la base vient du cache hors connexion. */
.demo-bar.est-cache { border-color: rgba(237,234,228,.32); }
.demo-bar.est-cache .demo-txt b { color: var(--papier); }

/* Fin du délai hors ligne : le bandeau reste affiché, il n'est plus une
   information de passage mais une chose à faire. */
.demo-bar.est-urgent { border-color: rgba(227,176,75,.55); }
.demo-bar.est-urgent .demo-txt b { color: var(--ambre, #E3B04B); }
@media (max-width: 640px) {
  .demo-bar { flex-direction: column; align-items: stretch; gap: 9px; }
  .demo-cta, .demo-defi { width: 100%; }
}
.edit-btn.tables { margin-bottom: 8px; }
.edit-btn.tables:hover { border-color: var(--papier); }
.edit-btn.tables .edit-ico { color: var(--txt-attenue, #9A958D); }

/* ══════════════════════════════════════════════════════════════════════
   Charte « Encre » — réglages typographiques de l'application
   ══════════════════════════════════════════════════════════════════════
   Les interlettrages du fichier ont été réglés pour BenchNine, une
   capitale très étroite qui réclamait 2 à 5 px pour respirer. Inter est
   nettement plus large : aux mêmes valeurs, les libellés de l'interface
   se disloquent et la colonne des méridiens déborde. On les ramène d'un
   cran en dessous, en une seule règle plutôt qu'en vingt-trois retouches.
                                                                        */
.top-actions .chip-btn, .seg-btn, .side-titre, .mer-code, .view-btn,
.d-code, .d-side, .badge, .tag, .demo-cta, .d-btn, .brand-name,
.res-code, .rv-titre, .tb-titre, .cp-btn {
  letter-spacing: .08em;
}
.brand-name { letter-spacing: .12em; font-weight: 600; }
.d-code { letter-spacing: .02em; font-weight: 500; }
.d-pinyin { letter-spacing: -.01em; }

/* Les codes de points et les chiffres s'alignent en colonne dans la liste
   des méridiens et dans les tables : sans chasse fixe, les colonnes
   dansent d'une ligne à l'autre. */
.mer-n, .res-code, .mer-code, .pt-label { font-variant-numeric: tabular-nums; }

/* Les libellés contraints par la largeur de leur bouton.
   « POINTS CLÉS », « FLANC GAUCHE » ou « SHU DU DOS » tenaient sur une
   ligne en BenchNine, capitale étroite. En Inter ils passaient à deux et
   cassaient la grille : on descend d'un point et on resserre encore. */
.seg-btn, .view-btn {
  font-size: 11.5px; letter-spacing: .04em; font-weight: 500;
  white-space: nowrap; padding: 0 4px;
}
.view-btn { font-size: 12px; }

/* Colonne étroite : le segment ne tient plus.
   Sous 1100 px la colonne passe de 268 à 236 px, ce qui ne laisse que 205 px
   au groupe pour 217 px de boutons — « Shu du dos » y perdait son S final,
   rogné par l'overflow hidden du groupe, sans que rien ne le signale.
   La règle doit être ICI et non dans le bloc @media plus haut : celui-ci
   précède la règle .seg-btn ci-dessus, de même spécificité, qui l'emportait
   donc à tous les coups. */
@media (max-width: 1100px) {
  .seg-btn { font-size: 10.5px; letter-spacing: .01em; padding: 0 2px; }
}
.chip-btn { font-size: 12.5px; letter-spacing: .05em; font-weight: 500; }
.side-titre { font-size: 11.5px; letter-spacing: .16em; font-weight: 600; }

/* Parcours du méridien, au bas de la fiche ------------------------- */
/* Un méridien se palpe dans l'ordre : on donne le point précédent et le
   suivant plutôt que d'obliger à les rechercher sur le modèle. */
.d-suite {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: 14px; padding-top: 14px;
  border-top: 1px solid rgba(237,234,228,.1);
}
.d-nav {
  display: inline-flex; align-items: center; gap: 7px;
  min-width: 84px; height: 32px; padding: 0 11px;
  background: transparent; border: 1px solid rgba(237,234,228,.16);
  border-radius: 8px; color: var(--papier); cursor: pointer;
  font-family: var(--f-ui); font-size: 13px; letter-spacing: .08em;
  transition: border-color .16s, color .16s;
}
.d-nav:last-child { justify-content: flex-end; }
.d-nav:hover:not(:disabled) { border-color: var(--violet); color: var(--violet-txt); }
.d-nav:disabled { opacity: .28; cursor: default; }
.d-nav-f { font-size: 15px; line-height: 1; opacity: .7; }
.d-rang {
  flex: 1; text-align: center;
  font-family: var(--f-ui); font-size: 12px; letter-spacing: .1em;
  color: var(--gris); white-space: nowrap;
}
.d-rang i { font-style: normal; opacity: .55; }

/* ------------------------------------------------------------------ */
/* Entrées des panneaux superposés                                     */
/*                                                                     */
/* Tables, révision et compte fabriquent leur propre feuille de style  */
/* dans leur module — mais aucun ne s'annonçait : les trois surgissaient*/
/* d'un bloc, ce qui se lit comme un défaut d'affichage plutôt que      */
/* comme une réponse au clic. Les entrées sont rassemblées ici, en un   */
/* seul endroit, pour que les trois panneaux partagent exactement la    */
/* même courbe et la même durée que le reste de l'application.          */
/* ------------------------------------------------------------------ */

/* Tables : le voile se lève, puis le contenu monte derrière lui. */
.tb.is-on { animation: apparait var(--moyen) var(--sortie) both; }
.tb.is-on .tb-body { animation: monte var(--ample) var(--sortie) 70ms both; }

/* Révision : le panneau est désormais une COLONNE de la grille, et non plus
   une barre centrée en bas. Les images clés reprenaient `translateX(-50%)`
   pour compenser ce centrage ; avec `both`, cet état FINAL persistait, et le
   panneau restait décalé de la moitié de sa largeur — deux cents pixels, la
   scène rétrécie d'autant et le cheval coupé. Il entre maintenant par la
   droite, comme la fiche. */
@keyframes rv-entre {
  from { opacity: 0; transform: translateX(18px); }
  to   { opacity: 1; transform: none; }
}
.rv:not([hidden]) { animation: rv-entre var(--moyen) var(--sortie) both; }

/* En colonne unique le panneau repasse en bas : il doit monter, pas glisser
   de côté. Nom DISTINCT, et non une redéfinition de `rv-entre` sous requête
   média : deux jeux d'images clés de même nom se contrarient, et le panneau
   restait figé sur son image de départ, décalé de dix-huit pixels. */
@keyframes rv-entre-bas {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
@media (max-width: 860px) {
  .rv:not([hidden]) { animation-name: rv-entre-bas; }
}

/* Compte : le fond s'assombrit vite, le dialogue arrive avec un léger
   ressort — c'est le seul endroit de l'application qui en demande un, parce
   que c'est le seul vrai dialogue modal. */
.cp-fond:not([hidden]) { animation: apparait var(--vite) var(--sortie) both; }
.cp-fond:not([hidden]) .cp { animation: monte var(--moyen) var(--ressort) both; }

/* Résultats de recherche : les lignes se posent par paliers de 22 ms. Au-delà
   de la huitième on arrête d'échelonner — sur une longue liste, l'attente
   cumulée deviendrait perceptible et le procédé se retournerait contre lui. */
/* La liste est centrée par `translateX(-50%)` : ses images clés doivent le
   reprendre, comme celles de la barre de révision. Animer `monte` tel quel
   remettait le transform à zéro et renvoyait le panneau un demi-écran à
   droite pendant toute la durée de l'entrée — puis l'y laissait. */
@keyframes res-entre {
  from { opacity: 0; transform: translateX(-50%) translateY(-8px); }
  to   { opacity: 1; transform: translateX(-50%); }
}
#results:not([hidden]) { animation: res-entre var(--moyen) var(--sortie) both; }
.res-item { animation: apparait 200ms var(--sortie) both; }
.res-item:nth-child(1) { animation-delay: 0ms; }
.res-item:nth-child(2) { animation-delay: 22ms; }
.res-item:nth-child(3) { animation-delay: 44ms; }
.res-item:nth-child(4) { animation-delay: 66ms; }
.res-item:nth-child(5) { animation-delay: 88ms; }
.res-item:nth-child(6) { animation-delay: 110ms; }
.res-item:nth-child(7) { animation-delay: 132ms; }
.res-item:nth-child(n+8) { animation-delay: 154ms; }

/* =====================================================================
   PRISE EN MAIN — 20 septembre 2026
   =====================================================================
   Rien à l'écran n'indiquait que le clic droit déplace la vue ni que la
   molette rapproche. On l'apprenait en tâtonnant, ou pas du tout.
   ===================================================================== */
.pem-fond {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  padding: 20px;
  background: rgba(10,10,12,.62);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity var(--moyen) var(--sortie);
}
.pem-fond.is-on { opacity: 1; }
.pem-fond[hidden] { display: none; }

.pem {
  width: min(690px, 100%);
  max-height: calc(100vh - 40px);
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--ombre-3), var(--lumiere);
  padding: 26px 28px 22px;
  /* Le panneau monte de huit pixels en apparaissant : un objet qui surgit
     sans déplacement paraît collé à l'écran. */
  transform: translateY(8px);
  transition: transform var(--moyen) var(--sortie);
}
.pem-fond.is-on .pem { transform: none; }

.pem-titre {
  font-family: var(--f-title); font-weight: 400; font-size: 27px;
  margin: 0 0 6px; letter-spacing: -.01em;
}
.pem-intro { margin: 0 0 20px; color: var(--txt-dim); font-size: 14.5px; }

.pem-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.pem-table th, .pem-table td {
  text-align: left; padding: 10px 8px;
  border-top: 1px solid var(--line); vertical-align: middle;
}
.pem-table thead th {
  border-top: 0; padding-top: 0;
  font-family: var(--f-ui); font-size: 11.5px; font-weight: 500;
  letter-spacing: 2px; text-transform: uppercase; color: var(--txt-dim);
}
.pem-table .pem-quoi { color: var(--txt); font-weight: 500; width: 30%; }
.pem-table tbody th { font-weight: 500; }
/* Le pictogramme et son texte sur la même ligne de base optique : la
   souris fait vingt-neuf pixels de haut, le texte quatorze. */
/* Pictogramme et texte en rangée : sans cela, une ligne qui se replie
   repartait sous le pictogramme au lieu de s'aligner sur elle-même. */
.pem-cell { display: flex; align-items: center; gap: 10px; }
.pem-ico { flex: none; color: var(--accent); }

.pem-reperes {
  margin: 22px 0 0; padding: 16px 0 0;
  border-top: 1px solid var(--line);
  display: grid; grid-template-columns: max-content 1fr;
  gap: 7px 16px; font-size: 14px;
}
.pem-reperes dt { color: var(--txt); font-weight: 500; }
.pem-reperes dd { margin: 0; color: var(--txt-dim); }

.pem-pied {
  margin-top: 22px; padding-top: 18px;
  border-top: 1px solid var(--line);
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
}
.pem-ok {
  font-family: var(--f-ui); font-size: 14px; font-weight: 500;
  letter-spacing: 1.4px; text-transform: uppercase;
  padding: 11px 22px; border-radius: 8px; cursor: pointer;
  background: var(--accent); color: var(--encre); border: 0;
  transition: filter var(--vite) var(--sortie);
}
.pem-ok:hover { filter: brightness(.92); }
.pem-note { margin: 0; flex: 1; min-width: 220px;
  font-size: 12.5px; color: var(--txt-dim); }

@media (max-width: 560px) {
  .pem { padding: 20px 18px 18px; }
  /* Le tableau à trois colonnes ne tient pas : on empile chaque geste. */
  .pem-table, .pem-table tbody, .pem-table tr, .pem-table th, .pem-table td {
    display: block; width: auto;
  }
  .pem-table thead { display: none; }
  .pem-table tr { border-top: 1px solid var(--line); padding: 10px 0; }
  .pem-table th, .pem-table td { border: 0; padding: 2px 0; }
  .pem-table .pem-quoi { width: auto; }
  .pem-reperes { grid-template-columns: 1fr; gap: 2px; }
  .pem-reperes dd { margin-bottom: 8px; }
}


/* Sélecteur de côté — « Vu » suit la caméra, G et D figent un flanc.
   Le réglage vit à côté des cases d'affichage, parce qu'il en est une.

   Classe PROPRE, et non `.seg` : celle-ci est une grille à trois colonnes
   avec un bandeau coulissant, réservée à « Tous / Points clés / Shu du dos ».
   L'avoir réutilisée cassait cette grille avec un quatrième bouton et
   écrasait la taille des libellés, qui se tronquaient en « POINTS … ». */
.row-cotes { display: flex; align-items: center; gap: .5rem;
             margin: .35rem 0 .6rem; }
.row-cotes-titre { font-size: .82rem; opacity: .78; }
.seg-cote { display: flex; margin-left: auto; border: 1px solid var(--line);
            border-radius: 8px; overflow: hidden; background: rgba(0,0,0,.28); }
.seg-cote button { background: none; border: 0; color: var(--txt-doux, inherit);
                   cursor: pointer; padding: .2rem .44rem; font: inherit;
                   font-size: .74rem; line-height: 1.2;
                   border-left: 1px solid var(--line); }
.seg-cote button:first-child { border-left: 0; }
.seg-cote button:hover { color: var(--txt); }
.seg-cote button.is-on { background: var(--accent); color: #fff; }

/* Recherche sans résultat en démonstration : on dit que la démo est
   partielle, et non que le point n'existe pas. */
.res-vide { padding: 10px 10px 12px; list-style: none; }
.res-vide p { margin: 0 0 12px; font-size: 14px; line-height: 1.5; color: var(--txt-dim); }
.res-vide-cta {
  height: 34px; padding: 0 18px; background: var(--violet); border: none; border-radius: 8px;
  color: #111; cursor: pointer; font-family: var(--f-ui); font-size: 14px; letter-spacing: 2.5px;
  text-transform: uppercase;
}
.res-vide-cta:hover { background: #fff; }

/* Carte de première visite (prise-en-main.js, carteAccueil). */
.pem-carte {
  position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
  width: min(360px, calc(100% - 28px)); z-index: 40;
  background: rgba(26, 26, 29, .94); border: 1px solid rgba(237, 234, 228, .16);
  border-radius: 14px; padding: 14px 16px 12px; color: var(--txt);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  animation: apparait 300ms var(--sortie) both;
}
.pem-carte p { margin: 0 0 6px; font-size: 15px; line-height: 1.45; }
.pem-carte b { font-weight: 500; color: var(--papier); }
.pem-carte-act { display: flex; gap: 8px; justify-content: flex-end; margin-top: 10px; }
.pem-carte-act button {
  min-height: 40px; padding: 0 14px; border-radius: 8px; cursor: pointer;
  font-family: var(--f-ui); font-size: 13px; letter-spacing: 1.5px; text-transform: uppercase;
}
.pem-carte-aide { background: none; border: 1px solid rgba(237, 234, 228, .25); color: var(--txt); }
.pem-carte-ok { background: var(--papier); border: none; color: #111; }

/* La liste de résultats passe AU-DESSUS du bandeau de démonstration
   (z-index 20) : sans cela, en démo, on ne voyait pas ses propres
   résultats de recherche, cachés sous le bandeau. */
#results { z-index: 25; }
/* Et le bandeau s'efface tant que la liste est ouverte : sous un résultat
   court, son bouton transparaissait à travers le verre de la liste. */
#stage:has(#results:not([hidden])) .demo-bar { visibility: hidden; }

/* Bandeau de démonstration resserré (main.js, annoncerDemo) : une ligne,
   le compte des points et le bouton, sur ordinateur comme sur téléphone. */
.demo-court { display: none; flex: 1; font-size: 13px; color: var(--txt-dim); white-space: nowrap; }
.demo-court b { color: var(--violet-txt); font-weight: 500; }
.demo-bar.est-reduit { padding: 6px 6px 6px 14px; flex-direction: row; align-items: center; gap: 10px; }
.demo-bar.est-reduit .demo-txt { display: none; }
.demo-bar.est-reduit .demo-court { display: block; }
.demo-bar.est-reduit .demo-cta { width: auto; height: 32px; padding: 0 14px; font-size: 13px; letter-spacing: 1.5px; }

/* Rappel des mesures en cun : bouton du menu, et « cun » cliquable dans
   les fiches (souligné discret, pour ne pas alourdir la lecture). */
.edit-btn.cun-btn { margin-bottom: 8px; }
.edit-btn.cun-btn:hover { border-color: #C94134; }
.edit-btn.cun-btn .edit-ico { color: #E07A6E; }
.edit-btn.horloge-btn { margin-bottom: 8px; }
.edit-btn.horloge-btn:hover { border-color: #D9A15B; }
.edit-btn.horloge-btn .edit-ico { color: #D9A15B; }
.edit-btn.elements-btn { margin-bottom: 8px; }
.edit-btn.theorie-btn { margin-bottom: 6px; border-color: rgba(210,173,114,.45); }
.edit-btn.theorie-btn:hover { border-color: #D2AD72; }
.edit-btn.theorie-btn .edit-ico { color: #D2AD72; }
.theorie-note { margin: 0; font-size: 12px; color: #8E8A84; line-height: 1.4; }
.edit-btn.elements-btn:hover { border-color: #4FAE7B; }
.edit-btn.elements-btn .edit-ico { color: #4FAE7B; }
.edit-btn .reserve { font-size: 11px; color: #8E8A84; margin-left: 4px; }
.lien-cun {
  font: inherit; color: inherit; background: none; border: none; padding: 0;
  cursor: pointer; text-decoration: underline dotted rgba(224, 122, 110, .9);
  text-underline-offset: 3px; text-decoration-thickness: 1.5px;
}
.lien-cun:hover { color: #fff; text-decoration-style: solid; }
/* Option réservée aux abonnés, grisée en démonstration. */
.row-check:has(input:disabled) { opacity: .55; cursor: not-allowed; }
.row-check .reserve { font-size: .85em; color: var(--txt-attenue, #9A958D); }

/* Favori et notes personnelles, dans la fiche d'un point. */
.d-fav {
  margin-left: auto; margin-right: 38px; display: inline-flex; align-items: center; gap: 6px; flex: none;
  background: none; border: 1px solid var(--line); border-radius: 999px;
  color: var(--txt-dim); cursor: pointer; padding: 4px 10px 4px 8px;
  font: 15px/1 var(--f-ui);
}
.d-fav span { font-size: 11.5px; letter-spacing: .5px; text-transform: uppercase; }
.d-fav:hover { color: var(--txt); border-color: var(--txt-dim); }
.d-fav[aria-pressed="true"] { color: #E8B04B; border-color: rgba(232,176,75,.55); }
.d-notes textarea {
  width: 100%; box-sizing: border-box; min-height: 74px; resize: vertical;
  background: rgba(0,0,0,.25); color: var(--txt); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 11px; font: 14px/1.5 var(--f-ui);
}
.d-notes textarea:focus { outline: none; border-color: var(--txt-dim); }
#nb-favoris { color: var(--txt-dim); font-size: .85em; }

/* Filigrane de licence : adresse du compte, discrète, non cliquable. */
.filigrane {
  position: absolute; right: 14px; bottom: 12px; z-index: 4; pointer-events: none;
  font: 11px/1 var(--f-ui); letter-spacing: .4px; color: rgba(237,234,228,.22);
  user-select: none; white-space: nowrap;
}
.d-licence { font-size: 11px; color: var(--txt-dim); opacity: .6; margin: 6px 0 12px; }

/* Filtre posé depuis un module « Comprendre la MTC » ------------------- */
.filtre-ids {
  position: absolute; left: 50%; top: 14px; transform: translateX(-50%); z-index: 24;
  display: flex; align-items: center; gap: 10px; padding: 7px 8px 7px 16px; border-radius: 999px;
  background: rgba(18, 18, 24, .78); border: 1px solid rgba(233, 178, 92, .55); color: #F3D7A6;
  font: 500 13px 'Inter', system-ui, sans-serif; backdrop-filter: blur(14px); white-space: nowrap;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}
.filtre-ids[hidden] { display: none; }
.filtre-ids button {
  width: 26px; height: 26px; border-radius: 50%; border: 1px solid rgba(245, 240, 234, .2);
  background: rgba(255, 255, 255, .06); color: #EDEAE4; cursor: pointer; font-size: 12px;
}

/* Accès fourni par une école : « Élève · Nom de l'école » ------------------ */
.badge-ecole {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 6px 10px; margin-bottom: 8px; border-radius: 10px;
  background: rgba(233, 178, 92, .1); border: 1px solid rgba(233, 178, 92, .4);
  font: 500 12px 'Inter', system-ui, sans-serif; color: #F3D7A6;
}
.badge-ecole-role {
  flex: none; font-size: 10px; letter-spacing: 1.2px; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; background: rgba(233, 178, 92, .22); color: #F8E4C0;
}
.badge-ecole-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge-ecole-haut { margin: 0; max-width: 280px; display: none; }
@media (min-width: 1100px) {
  .topbar-cale { display: flex; justify-content: flex-end; align-items: center; min-width: 0; }
  .badge-ecole-haut { display: flex; }
}
