@font-face {
  font-family: "Amiri Quran";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("AmiriQuran.woff2") format("woff2");
}
/*
 * LIGATURES HONORIFIQUES — U+FD47 « ʿalayhi as-salām », U+FD41 « raḍiya llāhu
 * ʿanh », U+FDFA « ṣallā llāhu ʿalayhi wa-sallam ». Ce sont de vraies
 * ligatures ESPAÇANTES (Unicode 16.0), calligraphiées d'un seul tenant comme
 * ﷺ — et non les signes combinants U+0611 / U+0613, qui ne donnaient qu'une
 * abréviation minuscule posée au-dessus de la dernière lettre.
 * Sous-ensemble de Scheherazade New (SIL OFL) : 5,9 ko pour 7 glyphes.
 */
@font-face {
  font-family: "Honorifics";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("Honorifics.woff2") format("woff2");
  unicode-range: U+FD40-FD42, U+FD47, U+FD4D, U+FDFA;
}

/*
 * TRANSLITTÉRATION — ḥ ṣ ḍ ṭ ẓ ā ī ū ʿ ʾ.
 *
 * Ces lettres manquent à beaucoup de polices système (Latin Extended
 * Additional, U+1E00-U+1EFF). Quand elles manquent, le navigateur SYNTHÉTISE
 * le caractère : il décompose « ḥ » en « h » + point souscrit combinant, et
 * comme la police n'a pas non plus d'ancre d'attache, le point atterrit ENTRE
 * la lettre et la suivante au lieu de se placer dessous. C'est exactement le
 * défaut constaté.
 *
 * On fournit donc ces seuls caractères, par `unicode-range`, depuis deux
 * sous-ensembles embarqués : Amiri (empattements) pour la police d'affichage,
 * DejaVu Sans pour le corps de texte. Tout le reste continue de venir de la
 * police système. Coût total : 9,3 ko.
 *
 * `size-adjust` RECALE leur taille sur celle du texte autour. Sans lui, ces
 * lettres paraissaient plus petites que leurs voisines : la hauteur d'x
 * d'Amiri vaut 0,420 em quand Georgia, Palatino ou Iowan Old Style tournent
 * autour de 0,48, et celle de DejaVu Sans (0,547) dépasse au contraire celle
 * d'Arial ou de Segoe UI (~0,52). On agrandit donc le premier et on réduit
 * légèrement le second — c'est la hauteur d'x, non celle des hampes, qui
 * décide de la taille perçue.
 */
@font-face {
  font-family: "Translit Serif"; font-style: normal; font-weight: 400; size-adjust: 110%;
  font-display: swap; src: url("TranslitSerif.woff2") format("woff2");
  unicode-range: U+0100-0101, U+012A-012B, U+016A-016B, U+02BE-02BF,
                 U+1E0C-1E0D, U+1E24-1E25, U+1E62-1E63, U+1E6C-1E6D, U+1E92-1E93;
}
@font-face {
  font-family: "Translit Serif"; font-style: normal; font-weight: 700; size-adjust: 110%;
  font-display: swap; src: url("TranslitSerif-Bold.woff2") format("woff2");
  unicode-range: U+0100-0101, U+012A-012B, U+016A-016B, U+02BE-02BF,
                 U+1E0C-1E0D, U+1E24-1E25, U+1E62-1E63, U+1E6C-1E6D, U+1E92-1E93;
}
@font-face {
  font-family: "Translit Sans"; font-style: normal; font-weight: 400; size-adjust: 95%;
  font-display: swap; src: url("TranslitSans.woff2") format("woff2");
  unicode-range: U+0100-0101, U+012A-012B, U+016A-016B, U+02BE-02BF,
                 U+1E0C-1E0D, U+1E24-1E25, U+1E62-1E63, U+1E6C-1E6D, U+1E92-1E93;
}
@font-face {
  font-family: "Translit Sans"; font-style: normal; font-weight: 700; size-adjust: 95%;
  font-display: swap; src: url("TranslitSans-Bold.woff2") format("woff2");
  unicode-range: U+0100-0101, U+012A-012B, U+016A-016B, U+02BE-02BF,
                 U+1E0C-1E0D, U+1E24-1E25, U+1E62-1E63, U+1E6C-1E6D, U+1E92-1E93;
}


/* ============================================================
   THÈME NUIT (défaut) — variables de couleur.
   ============================================================ */
/*
 * LA PALETTE, ET LE THÈME DE NUIT.
 *
 * Ce bloc porte les jetons communs aux deux thèmes ET les couleurs de la NUIT ;
 * `:root.light` juste en dessous ne redéclare que celles du JOUR.
 */
:root {
  /* Largeur de la frise chronologique. Le bouton Retour se range après elle,
     et le téléphone la réduit : un seul endroit pour les deux. */
  --frise-w: 138px;
  /* ----------------------------------------------------------------
   * LES JETONS DE LA PASSE VISUELLE.
   *
   * Ils vivaient dans un bloc appendu en fin de feuille, avec les règles qui
   * les emploient. Les règles sont reparties chacune dans la sienne ; les
   * jetons, eux, n'écrasent rien — ils nomment — et se posent ici, avec le
   * reste de la palette, une seule fois et pour les deux thèmes.
   * ---------------------------------------------------------------- */
  /* ============================================================================
   * 1. UNE ÉCHELLE TYPOGRAPHIQUE, AU LIEU DE CINQUANTE TAILLES.
   *
   * Mesuré : 142 déclarations `font-size`, une cinquantaine de valeurs
   * distinctes, 25 tailles réellement rendues à l'écran — 10,06 px, 11,42 px,
   * 11,68 px, 11,84 px, 12,16 px, 12,48 px… Des écarts de deux dixièmes de
   * pixel ne se voient pas : ils ne hiérarchisent rien, ils empêchent seulement
   * de reconnaître deux niveaux comme étant le même.
   *
   * Neuf crans les remplacent. Chacun est posé sur la valeur la plus EMPLOYÉE
   * de la grappe qu'il remplace, non sur une progression théorique : le but est
   * de faire tomber ensemble ce qui devait déjà se ressembler, pas de redessiner
   * le site. Les petits corps gardent donc leur finesse — 11,5 px et 12,5 px
   * étaient les deux valeurs dominantes, elles restent le plancher.
   * ========================================================================= */
  --fs-00: 0.72rem;   /* 11,5 px — mention, compteur, intitulé de rubrique */
  --fs-0:  0.78rem;   /* 12,5 px — interface secondaire */
  --fs-1:  0.82rem;   /* 13,1 px — interface courante */
  --fs-2:  0.9rem;    /* 14,4 px — saisie, ligne à lire dans un volet */
  --fs-3:  1rem;      /* 16 px   — corps de texte */
  --fs-4:  1.1rem;    /* 17,6 px — accroche, intertitre de volet */
  --fs-5:  1.3rem;    /* 20,8 px — titre de section */
  --fs-6:  1.45rem;   /* 23,2 px — nom du volet */
  --fs-7:  2rem;      /* 32 px   — titre de page */
  /* ============================================================================
   * 2. UNE ÉCHELLE DE RAYONS, AU LIEU DE ONZE VALEURS.
   *
   * Mesuré : 2, 3, 4, 5, 6, 7, 8, 10, 12 px, 50 % et 999 px, souvent à quelques
   * pixels d'écart sur des objets voisins. Un rayon dit la taille de l'objet ;
   * onze rayons ne disent plus rien.
   * ========================================================================= */
  --r-xs: 3px;    /* pastille, puce, marqueur */
  --r-sm: 6px;    /* bouton, champ, encadré d'outil */
  --r-md: 10px;   /* panneau, fenêtre, carte de réglage */
  --r-pill: 999px;
  /* ============================================================================
   * 3. TROIS NIVEAUX D'ÉLÉVATION, ET UNE SEULE FORMULE PAR THÈME.
   *
   * Les ombres étaient écrites une à une : `0 1px 2px rgba(0,0,0,.06)`,
   * `0 4px 14px rgba(0,0,0,.22)`, `0 8px 24px rgba(0,0,0,.3)`. Une ombre dit une
   * HAUTEUR au-dessus de la page ; trois hauteurs suffisent, et deux objets à la
   * même hauteur doivent porter la même ombre.
   * ========================================================================= */
  --ombre-1: 0 1px 2px rgba(0, 0, 0, 0.20), 0 1px 1px rgba(0, 0, 0, 0.12);
  --ombre-2: 0 4px 12px rgba(0, 0, 0, 0.26), 0 1px 3px rgba(0, 0, 0, 0.16);
  --ombre-3: 0 12px 32px rgba(0, 0, 0, 0.34), 0 2px 8px rgba(0, 0, 0, 0.18);
  /* ============================================================================
   * 4. LES DURÉES ET LES COURBES DEVIENNENT LA SEULE SOURCE.
   *
   * `--dur-teinte`, `--dur-geste`, `--dur-volet` et `--ease` existaient déjà en
   * tête de feuille, avec un commentaire expliquant qu'un geste de même nature
   * doit recevoir la même durée partout. Mesuré : ils servaient UNE fois, et la
   * feuille portait à côté 0,12 s, 0,14 s, 0,15 s, 0,18 s, 0,2 s, 0,22 s,
   * 0,28 s, 0,3 s — et 75 fois la courbe `ease`, qui accélère et décélère
   * symétriquement, donc traîne à l'arrivée.
   *
   * Trois courbes nommées : ce qui ARRIVE décélère (l'objet se pose), ce qui
   * PART accélère (il s'écarte), ce qui répond au doigt part vite et se pose net.
   * Une sortie est toujours plus brève qu'une entrée.
   * ========================================================================= */
  --ease-entree: cubic-bezier(0.16, 1, 0.3, 1);   /* décélère, se pose */
  --ease-vif:    cubic-bezier(0.2, 0, 0, 1);      /* réponse au doigt */
  /* ============================================================================
   * 5. L'OR QUI PORTE DU TEXTE N'EST PAS L'OR QUI PORTE UN TRAIT.
   *
   * Mesuré, thème JOUR : « Préférences d'affichage » 2,02:1 ; « Plus proche
   * ancêtre commun », « Croisement de tags », « Avancement du sourçage » 2,85:1
   * — les quatre intitulés principaux de la barre latérale, sous le seuil de
   * 4,5:1. En cause : `--c-ululazm` (#b3861a) est une couleur d'ACCENT, calibrée
   * pour un liseré (seuil 3:1) et employée comme encre.
   *
   * On ne touche pas à l'accent — il fait le liseré, le halo, l'anneau du
   * cartouche, et c'est l'identité de la page. On ajoute l'or ÉCRIT, plus
   * profond de deux crans le jour, inchangé la nuit où il passait déjà (7,34:1).
   * ========================================================================= */
  --gold-ink: var(--c-ululazm); --green-ink: var(--c-quran);
  /* LE SURVOL DOIT SE VOIR, et un or lisible est un or plus profond — donc plus
     proche du texte au repos, donc moins visible comme changement. On ne demande
     pas à la couleur du texte de porter seule le survol : le fond prend un voile
     doré, qui se voit de loin et ne coûte rien à la lisibilité. C'est aussi le
     seul signal qui marche quand le cadre est effacé — dans un outil, `.tool
     .tool-btn:hover` éteint la bordure pour que la section reste une section.
  
     LE VOILE EST PLUS MINCE LA NUIT, et ce n'est pas une préférence : de nuit
     l'intitulé est écrit dans l'or CLAIR, et le voile éclaircit le fond. Les deux
     se rapprochent donc au lieu de s'écarter — mesuré à 3,76:1 sur un outil déjà
     ouvert, contre 5,4 le jour où le voile éclaircit un fond que l'or écrit fonce.
     Dix pour cent suffisent à voir le survol sans rattraper l'écriture. */
  --voile-survol: 10%; --voile-survol-ouvert: 14%;

  /* Les contrôles dessinés par le SYSTÈME — cases à cocher, ascenseurs, fond
     des champs — suivent cette déclaration, pas la feuille. Sans elle, ils
     restent clairs sur le thème nuit : une barre de défilement blanche le long
     d'une page brun foncé, et des cases venues d'un autre site. */
  color-scheme: dark;

  /* Nuit : marron foncé (moins sombre qu'un noir) */
  --bg: #2b2015;
  --bg-raised: #3a2c1d;
  --bg-raised-2: #473724;
  --panel: #33271a;
  --banner-strong: #46331f;

  --line: #6a5a41;
  --c-son-link: #7f6c4e;
  --known-fg: #b39a6e;
  --line-soft: #4d3f2a;

  --text: #f2e9d8;
  --text-muted: #c4b192;
  /* Clarté relevée pour passer 4,5:1 : ce token porte les surnoms des cartes,
     donc du texte à lire, et il donnait 2,79:1 sur le thème jour. La teinte —
     le même brun, la même chaleur — ne bouge pas. Nuit : 4,40 -> 6,30 / 5,34 /
     4,52 sur les trois fonds (page, relief, carte). */
  --text-faint: #b7a07a;

  /* Une couleur par SOURCE — la même partout : pastille du filtre, puce de
     citation, bandeau d'origine, et bandes des jauges d'avancement. */
  --src-quran: #59c089;
  --src-ibnkathir: #c07ad0;
  --src-tabari: #d8a13a;
  /* Les généalogistes arabes : un vert-de-gris, la seule teinte que les six
     autres laissaient libre — ni l'or de Ṭabariy, ni le bleu des Isrāʾīliyyāt. */
  --src-nassaba: #5cb0a8;
  --src-israiliyyat: #6f97ca;
  /* Les documents et l'archéologie : une ardoise. C'est la seule teinte FROIDE
     et peu saturée que les six autres laissaient libre — le bleu des
     Isrāʾīliyyāt est franc, le gris du non-sourcé est chaud —, et elle dit la
     pierre gravée. */
  --src-archeo: #94a3b3;
  /* Une pastille n'est pas du texte : le seuil est 3:1, et il n'était pas
     atteint non plus (2,01:1 le jour). */
  --src-unsourced: #837562;

  /*
   * CE QUI FONDE UNE DATE — une ÉCHELLE, et non six familles.
   *
   * Les six sources sont des familles : rien ne les ordonne, elles ont donc
   * chacune leur teinte. Les cinq manières dont une date tient, elles, vont du
   * mieux fondé au moins fondé — un texte, puis une contemporanéité, puis une
   * interpolation, puis un compte de générations, puis rien. Une seule encre
   * qui s'éteint le dit ; cinq teintes le cacheraient. Et l'encre choisie est
   * celle du site, ce qui distingue au premier coup d'œil ce graphique de
   * celui des sources.
   */
  --dt-textual: #e6c168;
  --dt-contemp: #c3a052;
  --dt-interp: #9b8153;
  --dt-gen: #74654f;
  --dt-unknown: #4e4738;

  /* Catégories */
  --c-quran: #59c089;
  --c-ululazm: #e0b23e;
  --c-muhammad-bg: #196b3a;
  /* L'or du cartouche : plus clair que l'anneau, pour se détacher du vert. */
  --c-muhammad-gold: #f9e2a6;

  --c-desc-link: #e0b23e;
  --c-mrca: #e2574c;      /* mise en évidence « ancêtre commun » */

  --box-shadow: 0 2px 10px rgba(0, 0, 0, 0.28);
  /* L'ENFONCEMENT AU SURVOL. Une ombre INTERNE tombant du haut : la carte
     paraît s'enfoncer dans la page au lieu d'en sortir. L'ombre portée
     s'aplatit du même coup — un objet enfoncé ne projette plus. */
  --card-pressed: inset 0 3px 8px -2px rgba(0, 0, 0, 0.5);
  --box-shadow-pressed: 0 1px 4px rgba(0, 0, 0, 0.22);

  --card-bg: #3a2c1d;
  --card-bg-ululazm: #4a3719;
  --card-border: #5c4b34;
  --toggle-bg: #6a5a41;
  --toggle-fg: #f7efdd;

  --tag-plum: #c08fd0;  --tag-blue: #7ba7dd;
  --tag-amber: #e0b23e; --tag-red: #d98a72;   --tag-green: #6cc79a;
  --tag-teal: #6fc6c0;   --tag-crimson: #e0685c;  --tag-tribe: #b98cc9;
  --tag-orange: #e8994e; --tag-qurashi: #c9743a;  --tag-syriac: #8fb8a0;
  /* Moab : un olive qui ne se confond ni avec l'or des Tamīm ni avec le
     beige des peuples disparus d'Arabie — ce peuple-ci n'est pas arabe. */
  --tag-moab: #a9bd72;
  /* Les deux origines des Compagnons non arabes : deux teintes libres, aussi
     loin l'une de l'autre que du vert des Compagnons qui les entoure. */
  --tag-perse: #7f8fd4;  --tag-abyssin: #b8708f;
  --tag-pink: #e79ab8;   --tag-rose: #dd5f92;     --tag-caliph: #3f9d6c;
  /* LE TRAIT D'ALLIANCE A SA PROPRE TEINTE, et non celle de la pastille des
     Mères des croyants. Les deux étaient le même jeton : rendre le trait plus
     vif le jour aurait déteint sur la pastille, dont la teinte est mesurée
     pour rester lisible (tour 92). */
  --alliance: #dd5f92;
  --tag-clan: #b9784a;   --tag-teal2: #79c4a8;
  /* AHL AL-BAYT ET LES CINQ DU MANTEAU — une teinte à eux seuls.
     Le magenta est la seule plage libre du nuancier : le prune des
     prophètes bibliques est à vingt-cinq degrés d'ici, le rose des femmes
     à trente de l'autre côté, et aucune des deux ne se pose sur les mêmes
     cartes. Les deux tags la partagent, comme Badr, Uḥud et le Serment
     partagent la leur : c'est une famille. */
  --tag-bayt: #dd7fd6;
  /*
   * UNE COULEUR PAR CLAN DE QURAYCH. Ils partageaient tous le même brun : sur
   * la carte comme dans l'encadré, rien ne distinguait Banū Hāchim de Banū
   * Makhzūm. Quatorze teintes également réparties sur le cercle, à saturation
   * et clarté CONSTANTES : elles se distinguent l'une de l'autre sans qu'aucune
   * ne crie plus fort que sa voisine, et l'encadré d'un clan reprend exactement
   * la couleur de sa pastille.
   */
  --clan-hashim: #c58c63;      --clan-muttalib: #c5b663;
  --clan-nawfal: #aac563;      --clan-umayyah: #80c563;
  --clan-abd_al_dar: #63c570;  --clan-asad_uzza: #63c59a;
  --clan-zuhrah: #63c5c4;      --clan-taym: #639cc5;
  --clan-makhzum: #6372c5;     --clan-adiyy: #7e63c5;
  --clan-sahm: #a863c5;        --clan-jumah: #c563b8;
  --clan-amir_luayy: #c5638e;  --clan-harith_fihr: #c56364;
  /* L'ENCEINTE de Quraych : hors de la roue des clans — elle les contient,
     elle ne compte pas parmi eux. Un sable brûlé, plus sombre que le crème
     d'origine, qui se détache du fond au lieu de s'y fondre. */
  --encadre-enceinte: #b8a074;
  /*
   * LE TRAIT DES TRIBUS, PLUS PROFOND QUE LEUR TEINTE.
   *
   * Une tribu — Quraych, Banū Tamīm, Aws, Khazradj — n'est pas un clan de plus :
   * son cadre doit se voir d'un coup d'œil parmi les quatorze qu'il côtoie.
   * C'est le CONTOUR seul qui descend ; le fond garde la teinte du groupe, et
   * son opacité ne bouge pas d'un centième. En nuit, « plus foncé » s'arrête là
   * où le trait cesserait de se détacher du support : ces trois encres sont les
   * plus profondes qui restent lisibles sur un fond de nuit.
   */
  --tribu-trait-enceinte: #9a8250;
  --tribu-trait-tamim: #b0843e;
  --tribu-trait-clan: #9a5a2e;
  --tag-tamim: #d0a05e;
  /* LES DEUX MAISONS DU YÉMEN — Ḥimyar et Kahlān. Une famille de brique à
     elles deux : la souche du Sud ne se lit pas dans l'orange du Nord, et
     deux tons d'une même encre disent qu'elles sortent du même père. */
  --tag-himyar: #cd7a5c;
  --tag-qudaa: #d9a066;
  --tag-kahlan: #b5624a;
  /* ʿĀd et Thamūd : le gris-sable des demeures vides */
  --tag-ruin: #b0a08a;
  /* Fond de l'aire d'exemple du réglage des noms : un troisième niveau,
     distinct de la page ET de la carte qui s'y pose. */
  --ns-canvas: #322418;
  --panel-w: min(360px, 88vw);
  --tag-hijra: #9db4c6;  --tag-event: #a396e8;
  /* Halos de carte : bleu pour les prophètes, or pour les Ûlû-l-‘azm */
  --glow-prophet: 0 0 14px 1px rgba(123, 167, 221, 0.38);
  --glow-ululazm: 0 0 18px 2px rgba(224, 178, 62, 0.40);
  --name-glow: 0 0 10px rgba(240, 205, 118, 0.45), 0 0 3px rgba(240, 205, 118, 0.35);
  --c-select: #f2e9d8;
  --c-arabic: #c9a06a;
  --info-bg: #f2dfae;
  --info-fg: #3a2c1d;
  --legend-bg: #4a3a26;
  --card-bg-prophet: #33313d;
  /* LE FOND DES COMPAGNONS — un vert très pâle. En nuit il se compte en
     quelques points au-dessus du fond de carte : plus soutenu, le nom perdrait
     son contraste, et une case cesserait d'être une case. */
  --card-bg-sahabi: #2b3a33;

  --star-opacity: 0.5;

  /* « Amiri Quran » ferme les trois piles : c'est la seule police embarquée qui
     possède la ligature ﷺ (U+FDFA), présente jusque dans les textes latins. */
  /* « Translit … » vient en TÊTE : sa `unicode-range` ne couvre que ḥ ṣ ḍ ṭ ẓ
     ā ī ū ʿ ʾ, tout le reste retombe sur la police système juste après.

     TROIS ÉCRITURES ONT ÉTÉ ESSAYÉES ET RENDUES, au choix de l'utilisateur :
     Crimson Pro et Work Sans (tour 109), Spectral et Alegreya Sans (110), puis
     de nouveau les premières (111). Le site revient à ce qu'il était : le texte
     prend la police du LECTEUR, et il change donc d'aspect d'une machine à
     l'autre — c'est le prix, et il a été accepté en connaissance de cause. */
  --font-display: "Translit Serif", "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, "Honorifics", "Amiri Quran", serif;
  --font-body: "Translit Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, "Honorifics", "Amiri Quran", sans-serif;
  --font-arabic: "Amiri Quran", "Traditional Arabic", serif;
  /*
   * L'ÉCRITURE DES CASES NE CHANGE PAS, ET C'EST UNE CONTRAINTE DE DESSIN
   * AVANT D'ÊTRE UN GOÛT. La largeur d'une case est mesurée, et c'est elle qui
   * porte toute la mise en page : une autre police, ce sont mille cartes
   * déplacées et la planarité à reprendre.
   *
   * IL VAUT AUJOURD'HUI LA MÊME CHOSE QUE `--font-display`, et il reste : c'est
   * lui qui a permis de changer trois fois l'écriture du site sans qu'une seule
   * carte bouge. Le supprimer parce que les deux se ressemblent rendrait les
   * cases solidaires du prochain changement, et il faudrait le réécrire.
   * `tools/t_geo.js` vérifie carte par carte que rien n'a bougé.
   */
  /*
   * LA MARQUE A DEUX ÉTATS, ET C'EST LA CHARTE QUI LES DONNE — non deux
   * teintes choisies à l'œil. En nuit c'est « 19f », réserve sur encre, celui
   * que la charte réserve aux en-têtes sombres ; en jour « 19a », encre et or.
   * L'or FONCÉ sert au trait sur fond clair, l'or CLAIR au trait sur fond
   * sombre : ce sont deux valeurs d'une même couleur, jamais interchangeables.
   */
  --marque-encre: #f4efe2;
  --marque-or: #b39a6e;
  --font-carte: "Translit Serif", "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, "Honorifics", "Amiri Quran", serif;

  /*
   * DEUX ÉCHELLES NOMMÉES — écarts et durées.
   *
   * Les valeurs étaient écrites une à une : on trouvait 0,15 s, 0,18 s, 0,2 s
   * et 0,28 s pour des gestes de même nature. Trois durées, et trois
   * seulement : ce qui ne fait que changer de couleur, ce qui se déplace, ce
   * qui s'ouvre. Un geste de même nature reçoit alors la même durée partout.
   */
  --space-1: 0.25rem;  --space-2: 0.5rem;   --space-3: 0.75rem;
  --space-4: 1rem;     --space-5: 1.5rem;   --space-6: 2rem;
  --space-8: 4rem;

  --dur-teinte: 0.15s;
  --dur-geste: 0.22s;
  --dur-volet: 0.28s;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
}

/* ============================================================
   THÈME JOUR
   ============================================================ */
:root.light {
  color-scheme: light;
  /* Sur fond clair l'ombre est plus courte et moins noire : une ombre profonde
  sur du crème salit la page au lieu de soulever l'objet. */
  --ombre-1: 0 1px 2px rgba(80, 55, 20, 0.10), 0 1px 1px rgba(80, 55, 20, 0.06);
  --ombre-2: 0 4px 12px rgba(80, 55, 20, 0.14), 0 1px 3px rgba(80, 55, 20, 0.08);
  --ombre-3: 0 12px 32px rgba(80, 55, 20, 0.18), 0 2px 8px rgba(80, 55, 20, 0.10);
  --gold-ink: #6b4d08; --green-ink: #0b6e40;
  /* État « 19a » de la charte — voir le jeton du thème nuit. */
  --marque-encre: #1e1a12;
  --marque-or: #6b4d08;
  --voile-survol: 15%; --voile-survol-ouvert: 24%;

  --bg: #f4efe2;
  --bg-raised: #fbf8ef;
  --bg-raised-2: #ece3cf;
  --panel: #fbf8ef;
  --banner-strong: #6b4f31;

  --line: #cabd9f;
  --c-son-link: #9d8b62;
  --known-fg: #97794a;
  --line-soft: #ddd3bd;

  --text: #2a2317;
  --text-muted: #6b6047;
  /* Jour : 2,79 -> 4,58 / 4,96 / 5,26. Voir le token du thème nuit. */
  --text-faint: #746b59;

  --src-quran: #2f8f5b;
  --src-ibnkathir: #9b4cb0;
  --src-tabari: #b07a12;
  --src-nassaba: #2b8079;
  --src-israiliyyat: #3d6ea8;
  --src-archeo: #5d7183;
  --src-unsourced: #8f8877;

  /* La même échelle, à l'encre sur le parchemin. */
  --dt-textual: #6b4d08;
  --dt-contemp: #8d7028;
  --dt-interp: #ab9159;
  --dt-gen: #c6b48c;
  --dt-unknown: #ded6c2;

  --c-quran: #2f8f5b;
  --c-ululazm: #b3861a;
  --c-muhammad-bg: #1f7a4d;
  --c-muhammad-gold: #e4bd54;

  --c-desc-link: #a97e12;
  --c-mrca: #c0392b;

  --box-shadow: 0 3px 14px rgba(80, 55, 20, 0.10);
  --card-pressed: inset 0 3px 8px -2px rgba(80, 55, 20, 0.28);
  --box-shadow-pressed: 0 1px 4px rgba(80, 55, 20, 0.10);

  --card-bg: #ffffff;
  --card-bg-ululazm: #fdf5e3;
  --card-border: #ece3d3;
  /* 4,33:1 le jour, à un cheveu du seuil : le fond fonce d'un cran. La TAILLE,
     elle, ne bouge pas — elle entre dans la mesure des cartes. */
  --toggle-bg: #7a6449;
  --toggle-fg: #fffaf0;

  --tag-plum: #8b5ea3;  --tag-blue: #3d6fa8;
  --tag-amber: #a9781a; --tag-red: #b4523a;   --tag-green: #2f8f5b;
  --tag-teal: #2f8a86;   --tag-crimson: #c0392b;  --tag-tribe: #7d5ba6;
  --tag-orange: #c9691a; --tag-qurashi: #97501f;  --tag-syriac: #3f7a5c;
  --tag-moab: #556b16;
  --tag-perse: #37479b;  --tag-abyssin: #7d2448;
  --tag-pink: #c0507c;   --tag-rose: #93194f;     --tag-caliph: #16603a;
  /* Plus VIF que la teinte des pastilles : le prune sombre se lisait comme du
     noir sur le fond clair, et l'alliance ne se distinguait plus d'une
     filiation. 5,1:1 sur le fond de la page, bien au-dessus du seuil de 3:1
     d'un objet graphique. */
  --alliance: #c2185b;
  --tag-clan: #6d3810;   --tag-teal2: #3d7f66;
  /* Le même magenta, assombri pour le fond clair. */
  --tag-bayt: #8e1f86;
  /* Les mêmes quatorze teintes, assombries pour le fond clair. */
  --clan-hashim: #864f27;      --clan-muttalib: #867827;
  --clan-nawfal: #6c8627;      --clan-umayyah: #438627;
  --clan-abd_al_dar: #278634;  --clan-asad_uzza: #27865c;
  --clan-zuhrah: #278685;      --clan-taym: #275f86;
  --clan-makhzum: #273686;     --clan-adiyy: #412786;
  --clan-sahm: #6a2786;        --clan-jumah: #86277a;
  --clan-amir_luayy: #862751;  --clan-harith_fihr: #862728;
  /* Sur fond clair l'enceinte reste la teinte la plus discrète du dessin,
     mais c'est un trait fin, et un trait fin doit être FONCÉ pour se voir :
     une terre d'ombre, non le beige qui se perdait dans le fond crème. */
  --encadre-enceinte: #6f5528;
  /* En jour, rien ne borne la descente : le fond est crème, et plus l'encre
     est profonde, plus le cadre d'une tribu se distingue de ceux des clans. */
  --tribu-trait-enceinte: #4a3714;
  --tribu-trait-tamim: #5c4209;
  --tribu-trait-clan: #4a2408;
  --tag-tamim: #8a6415;
  /* Les deux maisons du Yémen, en plein jour : la même brique, assez profonde
     pour se lire sur le papier. */
  --tag-himyar: #a04a2c;
  --tag-qudaa: #8f6420;
  --tag-kahlan: #7a3620;
  --tag-ruin: #6f6350;
  --ns-canvas: #f6efe0;
  --panel-w: min(360px, 88vw);
  --tag-hijra: #3f5c73;  --tag-event: #4436a0;
  --glow-prophet: 0 0 13px 1px rgba(61, 111, 168, 0.26);
  --glow-ululazm: 0 0 16px 2px rgba(179, 134, 26, 0.30);
  --name-glow: 0 0 7px rgba(179, 134, 26, 0.20);
  --c-select: #2a2317;
  --c-arabic: #7a5a34;
  --info-bg: #f0d79a;
  --info-fg: #4a3a1c;
  --legend-bg: #fdfaf2;
  --card-bg-prophet: #f2f6fb;
  --card-bg-sahabi: #eef6f0;

  --star-opacity: 0;
}

* { box-sizing: border-box; scrollbar-color: var(--line) transparent; scrollbar-width: thin; }

/*
 * `hidden` DOIT CACHER. L'attribut ne cache que par une règle de la feuille du
 * NAVIGATEUR, la plus faible de toutes : le moindre `display` écrit ici la bat.
 * La liste des porteurs de tags portait `display: flex` et restait donc peinte
 * alors que le code la déclarait cachée — on cliquait pour la replier, il ne se
 * passait rien. Le piège guette les dix-neuf éléments que le JS bascule ainsi.
 */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
}
body { display: flex; flex-direction: column; }
.view { flex: 1; min-height: 0; }
.view:not(.active) { display: none; }
#view-home, #view-about, #view-contact, #view-tags, #view-concepts { overflow-y: auto; }
body.rtl { direction: rtl; }
body.rtl #tree-svg, body.rtl #map-container { direction: ltr; }

body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--star-opacity);
  transition: opacity 0.3s ease;
  background-image:
    radial-gradient(1px 1px at 8% 15%, rgba(236, 227, 209, 0.35), transparent),
    radial-gradient(1px 1px at 22% 68%, rgba(236, 227, 209, 0.25), transparent),
    radial-gradient(1.5px 1.5px at 38% 32%, rgba(236, 227, 209, 0.3), transparent),
    radial-gradient(1px 1px at 55% 78%, rgba(236, 227, 209, 0.2), transparent),
    radial-gradient(1.5px 1.5px at 68% 12%, rgba(213, 169, 51, 0.35), transparent),
    radial-gradient(1px 1px at 82% 55%, rgba(236, 227, 209, 0.25), transparent),
    radial-gradient(1px 1px at 92% 85%, rgba(236, 227, 209, 0.2), transparent),
    radial-gradient(1.5px 1.5px at 12% 90%, rgba(76, 175, 125, 0.3), transparent);
  background-repeat: repeat;
  background-size: 480px 480px;
}

/* 9. L'ANNEAU DE FOCUS VIT EN FIN DE FEUILLE, ET NULLE PART AILLEURS.
   Il y en avait DEUX : celui-ci, en or, et un `:where(…):focus-visible` en fin
   de feuille, à la couleur de sélection. Même poids de spécificité, donc c'est
   le dernier qui l'emportait — sur les éléments qu'il nomme seulement, l'or
   restant sur tous les autres. Deux anneaux de deux couleurs pour un même
   geste : on garde celui de la fin, et on retire celui-ci. */

/* ============================================================
   BANDEAU (navigation à gauche, thème à droite)
   ============================================================ */
.banner {
  position: sticky;
  top: 0;
  /*
   * AU-DESSUS DES FENÊTRES POSÉES SUR LE DESSIN (24 et 25), et en dessous du
   * reste. Le bandeau ne recouvre rien — il est en tête de la colonne, et tout
   * le reste est dessous —, mais ses DÉPLIANTS sortent de lui : `position:
   * fixed` ne les libère pas de son empilement, et à 20 le menu du globe
   * tombait derrière la fiche au large, où il n'y avait plus moyen de changer
   * de langue. Les deux onglets dépliants avaient déjà le défaut, sans qu'on
   * s'en aperçoive.
   */
  z-index: 28;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Le bandeau se replie sur deux lignes plutôt que de déborder à droite :
     à fort zoom, les onglets sortaient de l'écran et devenaient inaccessibles. */
  flex-wrap: wrap;
  row-gap: 0.4rem;
  gap: 1rem;
  padding: 0.8rem 1rem;
  background: var(--banner-strong);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.10);
}

/*
 * LIEN D'ÉVITEMENT — invisible tant qu'on ne tabule pas.
 *
 * Au clavier, atteindre le contenu demandait de traverser cinq onglets, le
 * menu dépliant des tags, les trois langues et le thème — et cela À CHAQUE
 * changement de vue. Le lien se pose sous la barre dès qu'il prend le focus.
 */
#skip-link {
  position: fixed;
  top: -100px;
  inset-inline-start: var(--space-4);
  z-index: 100;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--c-ululazm);
  border-radius: var(--r-xs);
  background: var(--bg-raised);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-3);
  text-decoration: none;
  box-shadow: var(--box-shadow);
  transition: top var(--dur-geste) var(--ease);
}
#skip-link:focus { top: calc(var(--banner-h, 64px) + var(--space-2)); }
#main { scroll-margin-top: var(--banner-h, 64px); }
#main:focus { outline: none; }   /* cible de saut, pas un objet à désigner */


/*
 * LA MARQUE DANS LE BANDEAU.
 *
 * Elle n'est pas un onglet de plus, et rien ne doit la faire lire comme tel :
 * pas de rembourrage d'onglet, pas de trait sous elle, jamais l'état actif.
 * Un filet vertical très pâle la sépare de la rangée — c'est ce qui dit
 * « ceci nomme le site, ceci navigue dedans » sans écrire un mot de plus.
 *
 * ELLE EST MONOCHROME, et c'est l'application que la charte donne elle-même
 * pour un bandeau sombre : à seize ou vingt pixels, l'or du losange et de la
 * branche ne se distingue plus de l'encre, et deux teintes qui se confondent
 * ne valent pas mieux qu'une. `currentColor` la tient donc sur la couleur du
 * texte de la barre, qui est la même dans les deux thèmes.
 */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.2rem 0.9rem 0.2rem 0.1rem;
  margin-inline-end: 0.35rem;
  border: none;
  border-inline-end: 1px solid rgba(255, 255, 255, 0.18);
  background: transparent;
  color: #efe2cb;
  cursor: pointer;
}
.brand-ico { width: 24px; height: 24px; flex: none; fill: currentColor; }
/* Le nom est un NOM PROPRE : il garde son écriture à empattements et son
   interlettrage, quelle que soit la langue de l'interface. */
.brand-mot {
  font-family: var(--font-display);
  font-size: var(--fs-4);
  letter-spacing: 0.05em;
  line-height: 1;
}
/* L'arabe ne prend ni interlettrage ni capitalisation (charte, § 05) et
   demande sa propre police : aucune des deux latines ne le couvre. */
body.rtl .brand-mot { font-family: var(--font-arabic); letter-spacing: 0; }
.brand:hover { color: #fff; }
.brand:focus-visible { outline: 2px solid #ffd98a; outline-offset: 2px; border-radius: 2px; }

.nav { display: flex; align-items: center; gap: 0.7rem; }

.nav-btn {
  padding: 0.5rem 1.05rem;
  border-radius: var(--r-sm);
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-3);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}

.banner .nav-btn, .banner .seg button, .banner .theme-toggle { color: #efe2cb; }
.banner .theme-toggle { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.25); }
.banner .seg { border-color: rgba(255,255,255,0.25); }
.banner .seg button { border-right-color: rgba(255,255,255,0.2); }
.nav-btn:hover { color: #fff; background: rgba(255,255,255,0.10); }

/*
 * L'ONGLET ACTIF SE MARQUE, IL NE SE REMPLIT PAS. Il portait à la fois une
 * couleur, une graisse, un fond teinté ET un trait inférieur : quatre signaux
 * pour une seule information. On garde les deux qui se lisent le plus vite —
 * la couleur et le trait — et l'on retire le fond, qui posait une pastille
 * pleine en haut de chaque page.
 */
.banner .nav-btn.active {
  color: #ffd98a;
  font-weight: 600;
  background: transparent;
  border-radius: 0;
  box-shadow: inset 0 -2px 0 #ffd98a;
}
.banner .nav-btn.active:hover { background: rgba(255, 255, 255, 0.07); }

/*
 * LES BOUTONS RONDS DU BANDEAU — le globe, le jour/nuit, le signet.
 *
 * Ils étaient un seul, et sa règle s'appelait de son nom. Ils sont trois
 * maintenant, côte à côte : trois pastilles de même taille, de même bord et de
 * même survol, sans quoi le coin de la barre se lirait comme trois objets de
 * trois familles. `.theme-toggle` reste écrit ici pour que rien de ce qui le
 * nommait déjà ne change.
 */
.theme-toggle, .banner-ico {
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--text);
  cursor: pointer;
  font-size: 1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}

.theme-toggle:hover, .banner-ico:hover { border-color: var(--c-ululazm); }
/*
 * DEUX DESSINS, ET NON DEUX CARACTÈRES.
 *
 * « ☀ » et « ☾ » sont rendus par la police du système : selon la plateforme
 * ils sortent en émoji couleur, à une taille et dans un style que la page ne
 * maîtrise pas. Le bouton porte donc les deux tracés (voir `index.html`) et
 * n'en montre qu'un — celui qu'il PROPOSE, non celui du thème courant.
 */
.theme-toggle svg, .banner-ico svg {
  width: 18px; height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.theme-toggle .ico-moon { fill: currentColor; stroke: none; }
.theme-toggle .ico-moon { display: none; }          /* nuit : on propose le soleil */
:root.light .theme-toggle .ico-sun { display: none; }
:root.light .theme-toggle .ico-moon { display: block; }

/*
 * LE DÉPLIANT DU GLOBE. Il reprend celui des onglets — même fond, même bord,
 * même survol —, resserré : trois noms de langue ne réclament pas les deux
 * cents pixels d'une entrée de menu. Chaque nom est écrit DANS SA LANGUE, et
 * l'arabe y prend sa police et son sens de lecture, sans quoi « العربية »
 * sortirait dans la police de la page.
 */
.lang-menu { display: inline-flex; }
.lang-drop { min-width: 148px; }
.lang-drop button[lang="ar"] {
  font-family: var(--font-arabic);
  direction: rtl;
  text-align: right;
  font-size: var(--fs-3);
}

/* ============================================================
   VUES
   ============================================================ */
.view { display: none; }
.view.active { display: block; }

#view-home {
  padding: 2rem 1.5rem;
  text-align: center;
  overflow-y: auto;
}
/*
 * L'accueil est CENTRÉ tant qu'il tient, et DÉFILE dès qu'il déborde.
 *
 * `align-items: center` seul débordait des DEUX côtés : au-delà de 150 % de
 * zoom, le titre passait AU-DESSUS de la zone défilable (top négatif à
 * scrollTop 0) et devenait inatteignable. Des marges automatiques sur le bloc
 * intérieur donnent le même centrage mais tronquent proprement : le contenu
 * commence au bord haut dès qu'il ne tient plus, et la barre de défilement le
 * rattrape.
 */
#view-home.active { display: flex; justify-content: center; }
#view-home.active > .home-inner { margin-block: auto; }

/* L'accueil tient sur un écran standard : le titre est plus large et plus
   petit, les espacements resserrés, de sorte que le réglage des noms reste
   visible sans défiler. */
.home-inner { max-width: 980px; margin: 0 auto; padding: 0 1rem; }

/*
 * LA MENTION DE CHANTIER, DANS LE COIN — MAIS SEULEMENT S'IL Y TIENT.
 *
 * Elle y était déjà, et elle en était sortie : une ligne tenait dans la marge,
 * le résumé du dernier tour qui la suit, non. À 1 024 px le bloc recouvrait la
 * carte des réglages de nom, et un élément fixe qui recouvre le contenu le
 * recouvre pendant tout le défilement.
 *
 * LA MARGE SE MESURE, ELLE NE SE DEVINE PAS. Le contenu de l'accueil est large
 * de 980 px et centré : ce qui reste de chaque côté vaut `(100vw − 980px) / 2`,
 * et c'est exactement la largeur qu'on donne au bloc, moins son écart au bord.
 * Il ne peut donc pas recouvrir la lecture, quelle que soit la fenêtre. Sous
 * 1 400 px cette marge tombe sous 170 px — trop peu pour une phrase :
 * le bloc reprend alors sa place en pied de contenu, où il ne gêne rien.
 *
 * `inset-inline-start` et non `left` : en arabe, le coin de départ est à
 * droite, et la mention s'y range d'elle-même.
 */
.build-corner {
  margin: var(--space-5) auto 0;
  /* C'est un <footer>, et la règle générale des pieds de page lui posait
     1,6 rem de rembourrage en haut, 1,5 sur les côtés et 2,6 en bas — de quoi
     tenir le bloc à quarante pixels du coin où on le voulait. Ce rembourrage
     est celui d'un pied de page de lecture, pas d'une marque d'atelier. */
  padding: 0;
  max-width: 50rem;
  text-align: start;
}
/* DANS LE COIN, ET DANS LE COIN POUR DE BON : la mention se tenait à un
   centimètre des deux bords, ce qui la faisait lire comme un pied de page
   décalé plutôt que comme une marque d'atelier. Elle descend et rentre. */
@media (min-width: 1400px) {
  .build-corner {
    position: fixed;
    inset-inline-start: 0.5rem;
    bottom: 0.5rem;
    z-index: 4;
    margin: 0;
    max-width: calc((100vw - 1020px) / 2 - 1rem);
  }
  /* DÉPLIÉ, IL NE MONTE PAS PLUS HAUT QUE LA MOITIÉ DE L'ÉCRAN. La colonne
     n'a ici que la marge pour largeur — 174 px à 1 400 —, et quatre points y
     font vingt-cinq lignes : sans borne, le pied repartait couvrir le titre.
     Il défile dans sa moitié basse, où il a été posé. */
  .build-corner .build-news { max-height: 45vh; overflow-y: auto; }
}
.build-mark {
  margin: 0;
  font-size: var(--fs-00);
  letter-spacing: 0.03em;
  color: var(--text-faint);
}
/*
 * IL SE CLIQUE, ET IL RESTE UN TEXTE — pas de cadre, pas de fond, pas de
 * chevron. Un souligné pointillé et le doigt du curseur suffisent à dire qu'il
 * se passe quelque chose ; sans rien du tout, personne ne trouverait les
 * nouvelles du tour. La classe n'est posée que s'il y a de quoi déplier.
 */
.build-mark-clic {
  cursor: pointer;
  text-decoration: underline dotted currentColor;
  text-underline-offset: 3px;
}
.build-mark-clic:hover,
.build-mark-clic:focus-visible { color: var(--gold-ink); }
/*
 * L'APERÇU DES NOUVEAUTÉS. Il se lit en dernier et ne doit jamais se disputer
 * la page avec le titre : même encre effacée que le numéro, un cran plus petit,
 * et des puces en tirets — une liste dans un coin, pas un sommaire.
 */
.build-news { margin-top: 0.42rem; color: var(--text-faint); font-size: var(--fs-00); }
.build-news-title {
  margin: 0 0 0.22rem;
  font-size: var(--fs-00);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.85;
}
/* LES POINTS L'UN SOUS L'AUTRE, toujours : dans la marge il n'y a de place que
   pour une colonne, et en pied de contenu une liste courte se lit mieux droite
   qu'appariée. */
.build-news ul { margin: 0; padding: 0; list-style: none; }
.build-news li {
  margin: 0 0 0.18rem;
  padding-inline-start: 0.7rem;
  line-height: 1.35;
  text-indent: -0.7rem;
}
.build-news li::before { content: "— "; }
@media (max-width: 700px) {
  /*
   * `#view-home.active` est un flex EN LIGNE ; la vue passe en colonne.
   *
   * `justify-content: flex-start` et non `center` : la vue défile, et un
   * contenu centré plus haut que sa zone se fait rogner par le HAUT, hors
   * d'atteinte (c'est le défaut que corrige la décision 163). Le centrage
   * vertical reste assuré par le `margin-block: auto` de `.home-inner`, qui
   * ne centre que s'il reste de la place et ne rogne jamais.
   */
  #view-home.active { flex-direction: column; justify-content: flex-start; }
  /*
   * En COLONNE, la largeur est l'axe transversal : une marge horizontale
   * `auto` y empêche l'étirement et laisse le bloc prendre sa largeur de
   * contenu — 376 px pour 342 disponibles, d'où un débordement de la page vers
   * la droite. On rend la marge inutile : le bloc s'étire, et c'est le
   * remplissage de la vue qui le tient à distance des bords, comme avant.
   */
  #view-home.active > .home-inner { margin-inline: 0; width: 100%; }
  .build-corner { margin-top: var(--space-6); }
  /* Au doigt, la recommandation est 44 px, et elle n'est pas décorative :
     en dessous, on vise à côté. */
  .pick-tag, .cross-op, .tagpick-nbtn, .fold-btn, .seg button,
  .nav-btn, .nav-drop button { min-height: 44px; }
  #close-panel-btn, #fiche-close, #hint-close, #mrca-banner-close,
  .cf-btn, .theme-toggle { min-width: 44px; min-height: 44px; }
  .sm-check, .prophets-toggle, .ns-opt { padding-block: 0.55rem; }
}

/*
 * LE VERROUILLAGE CENTRÉ — la marque, le nom, la ligne d'identité.
 *
 * C'est la disposition que la charte appelle « centré », et elle ouvre
 * maintenant la page : le site avait un titre de trois lignes et pas de nom,
 * si bien que rien n'y était reconnaissable d'un coup d'œil.
 *
 * L'air autour du dessin est celui que la charte impose — huit unités de sa
 * grille de 76, soit un dixième de sa largeur. Il est DANS le fichier SVG (la
 * marque est inscrite dans 46 × 45 au centre de 76 × 76) : il n'y a donc
 * aucune marge à écrire ici, et la réduire reviendrait à rogner le dessin.
 */
.brand-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: var(--space-5);
}
/* Le titre et l'invocation sont le SOUS-TITRE du nom : leurs marges propres,
   héritées du temps où ils ouvraient la page, les en éloignaient d'un espace
   entier. C'est l'écart du bloc qui les tient maintenant, et le titre reçoit
   seulement le cran qui le détache du nom. */
/* Le titre descend d'un cran DANS le bloc de marque : à 2,5 rem sous un nom de
   3,75 rem, le rapport n'était que de 1,5 et les deux se disputaient la tête de
   page. À 2,05 rem il vaut 1,8 — un nom, puis son sous-titre. */
/* `#view-home h1` PORTE UN IDENTIFIANT : une règle de classe ne peut pas le
   battre, si bien que la première écriture de celle-ci n'a rien changé du tout
   — le corps était le même à l'écran qu'avant. Elle reprend donc le même
   identifiant. C'est la leçon du mesureur des cartes (décision 50), et elle
   se vérifie au style calculé, jamais à l'œil. */
#view-home .brand-block h1 { margin: var(--space-2) 0 0; font-size: clamp(1.4rem, 2.8vw, 2.05rem); }
.brand-block .kicker { margin: 0; }
/* LA MARQUE EST INSCRITE DANS 46 × 45 D'UNE GRILLE DE 76 : le dessin n'occupe
   que six dixièmes de la boîte, le reste est l'air que la charte impose. Une
   boîte de 112 px donne donc 68 px de dessin, contre 60 px de hauteur de
   capitale au nom — c'est le rapport du verrouillage centré de la charte,
   où la marque fait le double du corps du nom. */
.brand-mark { width: 112px; height: 112px; display: block; }
/* Les deux encres de la marque, chacune sur son jeton de thème. Le losange du
   calame et la branche filée prennent l'or, la hampe et la voûte l'encre :
   c'est la couleur qui distingue ce qui relie de ce qui se transmet. */
.brand-mark .m-encre { fill: var(--marque-encre); }
.brand-mark .m-or { fill: var(--marque-or); }
.brand-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.5rem, 5.4vw, 3.75rem);
  line-height: 1;
  letter-spacing: 0.03em;
  color: var(--text);
}
/* Voir `.brand-mot` : l'arabe n'est ni interlettré ni capitalisé, et il lui
   faut Amiri — ni la police d'affichage ni celle du corps ne portent l'arabe, et la
   substitution casserait les liaisons. */
/* L'ARABE NE TIENT PAS DANS UN INTERLIGNE DE 1. L'encre d'Amiri monte de 0,95
   cadratin au-dessus de la ligne d'écriture et descend de 0,55 : à interligne
   égal au corps, elle DÉBORDE sa boîte des deux côtés, et le bāʾ final d'أنساب
   venait toucher le titre posé dessous. L'interligne latin de 1, qui convient à
   un mot en capitales et bas-de-casse, ne convient pas ici. */
body.rtl .brand-name { font-family: var(--font-arabic); letter-spacing: 0; line-height: 1.5; }

/*
 * LE ʿUNWĀN — le fronton d'ouverture.
 *
 * La page s'ouvrait sur ۞ (U+06DE), qui est un signe de DIVISION DU TEXTE
 * CORANIQUE : un décor de page lui retire le sens précis qu'il a. On le
 * remplace par le khātim à huit branches — deux carrés superposés, l'ornement
 * de reliure et de zellige —, DESSINÉ et non emprunté à une police, donc
 * identique partout. Le glyphe hérité du HTML est éteint par `font-size: 0`.
 *
 * Et une page d'ouverture de manuscrit ne commence pas par son titre : elle
 * commence par un fronton qui dit « ici commence le livre ». Le khātim en
 * devient le centre, entre deux filets qui courent jusqu'aux marges.
 *
 * QUATRE FORMES, DEUX PSEUDO-ÉLÉMENTS. Les deux carrés du khātim les occupent
 * déjà : les filets latéraux sont donc peints en FOND, deux dégradés d'un
 * pixel qui partent des marges et s'arrêtent avant le motif. Ils s'éteignent
 * vers l'extérieur — un filet de fronton ne bute pas contre le bord de la
 * page, il s'y perd.
 */
.ornament {
  --khatim-garde: 34px;      /* demi-largeur réservée au motif central */
  position: relative;
  height: 46px;
  /* Il ferme le fronton au lieu de l'ouvrir depuis le tour 110 : l'air se
     compte donc des DEUX côtés, non du seul côté bas. */
  margin-block: 0.4rem 1.35rem;
  font-size: 0;              /* le glyphe hérité ne s'affiche plus */
  color: transparent;
  background-image:
    linear-gradient(to right, transparent, color-mix(in srgb, var(--c-ululazm) 75%, transparent)),
    linear-gradient(to left,  transparent, color-mix(in srgb, var(--c-ululazm) 75%, transparent));
  background-size: calc(50% - var(--khatim-garde)) 1px;
  background-position: left center, right center;
  background-repeat: no-repeat;
}
.ornament::before, .ornament::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 21px;
  height: 21px;
  margin: auto;
  border: 1.5px solid var(--c-ululazm);
  opacity: 0.9;
}
.ornament::after { transform: rotate(45deg); }

/*
 * Le titre montait à 2,15 rem et le sous-titre à 1,14 rem : un rapport de 1,9
 * là où une page d'ouverture en demande le double. Il gagne donc en corps et
 * resserre son interlettrage.
 */
/*
 * DEUX DEGRÉS DE LECTURE, ET NON UN SEUL.
 *
 * Le titre montait à 3,1 rem et tenait sur trois lignes ; l'introduction, en
 * dessous, retombait à 1,06 rem. L'écart était si large que la page n'avait
 * plus qu'un niveau visible — le titre — et que tout le reste se lisait comme
 * une note de bas de page. Le titre redescend d'un cran, l'introduction monte
 * d'un cran : l'écart reste franc, mais il y a de nouveau deux degrés.
 */
#view-home h1 {
  margin: 0 0 var(--space-3);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.6rem, 3.2vw, 2.5rem);
  text-wrap: balance;
  line-height: 1.18;
  letter-spacing: -0.012em;
}

/* Honorifique (sous le titre) */
.kicker {
  display: block;
  font-family: var(--font-arabic);
  direction: rtl;
  font-size: 1.36rem;
  color: var(--c-ululazm);
  margin: 0 0 var(--space-4);
  /* Une écriture arabe posée au corps d'une écriture latine paraît toujours
     plus serrée : sa hauteur utile se joue sur la ligne médiane, et ses hampes
     demandent de l'air. Elle reçoit donc son propre interligne. */
  line-height: 1.9;
}

/* L'italique n'est pas une couleur de texte, c'est une marque : appliquée d'un
   bout à l'autre du sous-titre, elle ne marquait plus rien. Il revient au
   romain et ne garde l'italique que pour les titres d'ouvrages qu'il cite. */
.lead {
  margin: 0 auto var(--space-6);
  max-width: 46ch;
  color: var(--text-muted);
  font-size: var(--fs-4);
  line-height: 1.7;
  font-style: normal;
}
.lead em, .lead i { font-style: italic; }

/*
 * LE BOUTON D'ENTRÉE : UN SCEAU, PAS UNE PILULE. Une gélule dorée pleine est
 * la réponse par défaut de n'importe quel site, et c'était la tache la plus
 * lourde de la page. L'or passe au trait et à la lettre ; le plein est gardé
 * pour le SURVOL, c'est-à-dire pour le moment où il veut dire quelque chose.
 * Le rayon tombe à 2 px : ce n'est plus une pilule, c'est un cartouche.
 */
.cta {
  display: inline-block;
  padding: 0.8rem 2rem;
  border-radius: 2px;
  border: 1px solid var(--c-ululazm);
  background: transparent;
  color: var(--c-ululazm);
  font-family: var(--font-body);
  font-size: var(--fs-3);
  font-weight: 600;
  letter-spacing: 0.03em;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, transform 0.12s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
}

.cta:hover {
  background: var(--c-ululazm);
  color: var(--bg);
}


/* ============================================================
   BARRE LATÉRALE DE RÉGLAGES
   ============================================================ */
#view-tree.active { display: flex; flex-direction: row; }

/*
 * HAUTEUR DES DEUX BOUTONS DE RABAT — mesurée depuis le haut de la zone
 * d'arbre jusqu'à LEUR CENTRE. Elle tombe pile dans l'intervalle qui sépare le
 * bouton « Préférences d'affichage » (qui finit 48 px sous le haut du volet)
 * de la barre de recherche (qui commence 84 px sous ce même haut).
 *
 * Une seule valeur pour les deux : la pastille « ‹ » et l'engrenage qui la
 * remplace une fois le volet fermé doivent se trouver au MÊME endroit, sans
 * quoi fermer puis rouvrir fait sauter le regard.
 */
:root {
  --fold-y: 66px;
  /* La largeur du volet, écrite UNE fois : les deux languettes de rabat s'y
     accrochent, et elles doivent tomber sur son bord au pixel près. */
  --sb-w: 288px;
  /* CE QUE PARCOURT LE RABAT — deux valeurs, et elles ne se confondent pas.
     `--sb-glisse` est un DÉPLACEMENT : les languettes parcourent exactement la
     largeur du volet et arrivent au bord de l'arbre nu ; en arabe le volet est
     à droite, elles vont donc dans l'autre sens, d'où le changement de signe.
     `--sb-rentre` est une MARGE, celle qui range le volet hors champ : une
     marge qui replie est négative des deux côtés, et lui donner le signe du
     déplacement laissait le volet en place, poussé vers l'intérieur. Un pixel
     de plus que la largeur : celui de son filet, sans quoi il en resterait un
     trait à l'écran. */
  --sb-glisse: calc(-1 * var(--sb-w));
  --sb-rentre: calc(-1px - var(--sb-w));
}
body.rtl { --sb-glisse: var(--sb-w); }

#sidebar {
  /* Défilement à la molette / au doigt, mais sans barre visible : elle
     encombrait une colonne déjà étroite. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  position: relative;
  flex: none;
  width: var(--sb-w);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 0.95rem 1rem;
  background: var(--bg-raised);
  border-right: 1px solid var(--line-soft);
  overflow-y: auto;
  /*
   * UN VOLET GLISSE, IL NE SE DISSOUT PAS — ET IL NE GLISSE PLUS PAR SA MARGE.
   *
   * Il s'effaçait en 0,20 s pendant qu'il se déplaçait en 0,28 : à mi-course il
   * n'était déjà plus là, et l'on ne voyait pas d'où il venait ni où il allait.
   * Une seule durée, une seule courbe, et plus d'effacement du tout : le volet
   * sort par le bord de la fenêtre, qui suffit à le cacher.
   *
   * Restait le MOYEN. `margin-left` est une propriété de mise en page : animée,
   * elle obligeait le navigateur à replacer et à repeindre toute la zone du
   * dessin à chaque image, quand la languette de rabat, elle, voyageait par
   * `transform`. Le trajet est donc désormais conduit depuis `app.js`, par
   * `transform` lui aussi (voir « LE VOLET GLISSE, ET L'ARBRE NE BOUGE PAS »),
   * et la marge change d'un seul coup : une mise en page au lieu de dix-sept.
   * Aucune transition ici — elle remettrait la marge en mouvement.
   */
}
.sb-top, .sb-bottom { display: flex; flex-direction: column; gap: 0.6rem; }

.sb-searchrow { display: flex; align-items: center; }
.sb-searchrow #search-input { flex: 1; min-width: 0; }
/*
 * LA LOUPE EST DANS LE CHAMP, au bout, et il n'y en a plus qu'une.
 *
 * Il y en avait DEUX : un dessin décoratif à gauche, qui ne faisait rien, et
 * un bouton à côté du champ, qui agissait. Deux loupes pour un champ, dont une
 * inerte — on cliquait la mauvaise. Ne reste que celle qui agit, posée là où
 * l'œil la cherche : au bout de ce qu'on vient de taper.
 */
#search-go {
  position: absolute;
  inset-inline-end: 4px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  transition: color 0.15s, background 0.15s;
}
#search-go svg { width: 16px; height: 16px; fill: none; stroke: currentColor;
                 stroke-width: 1.9; stroke-linecap: round; }
#search-go:hover:not(:disabled) { color: var(--gold-ink); background: var(--bg-raised); }
#search-go:focus-visible { outline: 2px solid var(--c-select); outline-offset: 1px; }
/* Éteinte tant que le champ ne désigne personne : elle dit alors qu'il n'y a
   rien à retrouver, au lieu de ne rien faire. */
#search-go:disabled { opacity: 0.35; cursor: default; }
/*
 * LES DEUX BOUTONS DE RABAT — UNE SEULE ET MÊME LANGUETTE.
 *
 * L'un fermait le volet, l'autre le rouvrait, et ils ne se ressemblaient en
 * rien : une pastille ronde de 40 px à cheval sur le bord, contre une
 * languette rectangulaire de 56 px collée au bord de l'arbre. Deux formes pour
 * un seul geste — ouvrir ou fermer la frontière entre les réglages et le
 * dessin — laissaient croire à deux fonctions différentes.
 *
 * C'est donc la MÊME languette : même taille, même bord, même arrondi du côté
 * de l'arbre, même ombre, même centre vertical (voir --fold-y). Seule change
 * l'icône, parce que seule change la direction : le chevron ferme, l'engrenage
 * rouvre — replié, il n'y a plus de volet, et c'est lui qui dit « réglages ».
 *
 * TOUT EST ÉCRIT EN LOGIQUE (`inset-inline-start`, rayons `start`/`end`) :
 * en arabe le volet passe à droite, et les languettes suivent d'elles-mêmes.
 * La pastille, elle, gardait un `left: 268px` physique et se retrouvait au
 * milieu du dessin, loin du volet qu'elle ferme.
 */
#sidebar-hide, #sidebar-reopen {
  position: absolute;
  /* Centre commun aux deux languettes : voir --fold-y. */
  top: calc(var(--banner-h, 64px) + var(--fold-y) - 26px);
  /* AU-DESSUS DU VOILE DE LA FICHE FENÊTRÉE (24). Le voile occupe tout
     `#map-container` : sans cela, ouvrir la fenêtre rendait le volet des
     réglages impossible à replier ou à rouvrir tant qu'on ne l'avait pas
     refermée — or replié, la languette est le SEUL moyen d'y revenir. */
  z-index: 26;
  width: 46px; height: 52px;
  align-items: center; justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-inline-start: none;
  border-start-start-radius: 0;
  border-end-start-radius: 0;
  border-start-end-radius: 7px;
  border-end-end-radius: 7px;
  background: var(--bg-raised);
  color: var(--text-muted);
  cursor: pointer;
  box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.16);
  /*
   * LA LANGUETTE VOYAGE AVEC LE VOLET, et c'est ce qui manquait le plus.
   *
   * Elle était posée en absolu dans la VUE, non dans le volet : celui-ci
   * glissait, elle restait sur place et s'effaçait — un tiroir dont la poignée
   * ne suivrait pas le tiroir. Les deux languettes partent maintenant du MÊME
   * point, le bord du volet, parcourent la MÊME distance et se relaient en
   * chemin. `transform` ne déclenche aucune mise en page.
   *
   * LES SEPT PROPRIÉTÉS SONT ÉNUMÉRÉES ICI, ET NULLE PART AILLEURS. Chaque
   * languette avait sa propre déclaration de transition, plus bas ; or
   * `transition-property` est une propriété unique, et la seconde effaçait la
   * première — le voyage n'aurait jamais eu lieu. Ne restent, en dessous, que
   * les DÉLAIS, qui organisent le relais des deux icônes.
   *
   * `visibility` EST DE LA LISTE, et elle n'est pas décorative : la languette
   * cachée était auparavant retirée par `display: none`, ce qu'on ne peut pas
   * fondre. Rendue transparente, elle restait atteignable à la touche de
   * tabulation — un bouton invisible dans le parcours au clavier. Elle bascule
   * donc en `hidden`, mais seulement UNE FOIS LE VOYAGE FINI, d'où son délai.
   */
  transition-property: transform, opacity, visibility, color, background-color, border-color, box-shadow;
  transition-duration: var(--dur-volet), var(--dur-teinte), 0s, var(--dur-teinte), var(--dur-teinte), var(--dur-teinte), var(--dur-teinte);
  transition-timing-function: var(--ease-entree), linear, linear, var(--ease-vif), var(--ease-vif), var(--ease-vif), var(--ease-vif);
}
#view-tree.sidebar-collapsed #sidebar-hide,
#view-tree.sidebar-collapsed #sidebar-reopen { transform: translateX(var(--sb-glisse)); }
/* Le chevron est retourné en arabe : son parcours doit alors être écrit avec
   lui, `transform` étant une propriété unique. */
body.rtl #view-tree.sidebar-collapsed #sidebar-hide { transform: translateX(var(--sb-glisse)) scaleX(-1); }
#sidebar-hide:hover, #sidebar-reopen:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
/* Collée au bord intérieur du volet ; l'autre au bord de l'arbre nu. */
#sidebar-hide {
  inset-inline-start: var(--sb-w);
  display: flex;
  font-size: 2rem;
  line-height: 1;
  padding-bottom: 0.18rem;
}
/* Elle part du bord du volet, comme l'autre, et attend là, invisible, que le
   rabat l'amène au bord de l'arbre. `display: none` a disparu : on ne peut pas
   fondre ce qui n'est pas affiché. Le relais se fait par le DÉLAI — chacune
   attend que l'autre ait fini de s'effacer. */
#sidebar-reopen {
  inset-inline-start: var(--sb-w);
  display: flex;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
#sidebar::-webkit-scrollbar { width: 0; height: 0; }
/*
 * LE RELAIS DES DEUX ICÔNES. Elles occupent le même point : sans délai, on les
 * verrait toutes deux à demi effacées au milieu du parcours, l'engrenage à
 * travers le chevron. Chacune attend donc que l'autre soit partie — le délai
 * est posé sur l'ÉTAT VERS LEQUEL on va, ce qui donne le bon ordre dans les
 * deux sens.
 *
 * L'ordre des sept valeurs est celui de `transition-property` ci-dessus :
 * déplacement, opacité, visibilité, puis les quatre teintes du survol.
 */
#sidebar-hide { transition-delay: 0s, var(--dur-teinte), 0s, 0s, 0s, 0s, 0s; }
#view-tree.sidebar-collapsed #sidebar-hide {
  opacity: 0; visibility: hidden; pointer-events: none;
  transition-delay: 0s, 0s, var(--dur-volet), 0s, 0s, 0s, 0s;
}
#view-tree.sidebar-collapsed #sidebar-reopen {
  opacity: 1; visibility: visible; pointer-events: auto;
  transition-delay: 0s, var(--dur-teinte), 0s, 0s, 0s, 0s, 0s;
}

/* État replié : la barre glisse hors champ, la languette la ramène */
#view-tree.sidebar-collapsed #sidebar { margin-left: var(--sb-rentre); pointer-events: none; }
.gear-ico { width: 26px; height: 26px; fill: currentColor; }

/*
 * VOLET FERMÉ : L'ARBRE EST NU. On y flanquait « Tout déplier » et « Tout
 * replier » ; or fermer les réglages, c'est demander l'arbre sans ce qui
 * l'entoure. Seul l'engrenage subsiste, pour revenir. Les deux boutons
 * restent dans le volet, à leur place, sous le titre « Filtres ».
 */
#collapsed-fold { display: none; }
.cf-btn {
  width: 46px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-raised);
  color: var(--text-muted);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.14);
  transition: color 0.15s ease, border-color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.cf-btn:hover { color: var(--c-ululazm); border-color: var(--c-ululazm); }
.cf-btn .fold-ico { width: 22px; height: 22px; }
/*
 * L'AIR AU-DESSUS D'UN INTITULÉ DE RUBRIQUE. Il en recevait deux fois : douze
 * pixels de marge propre, plus les dix de l'écart entre blocs du volet — vingt-
 * deux au total, quand le titre lui-même en fait treize. La rubrique paraissait
 * détachée de ce qu'elle annonce. Quatre pixels de marge suffisent : l'écart
 * entre blocs porte déjà la séparation, la marge ne fait plus que la nuancer.
 */
.sb-title {
  margin-top: var(--space-1);
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.3;
  margin-bottom: var(--space-1);
}

/*
 * LA RECHERCHE N'EST PAS UN BOUTON. Elle avait le même cadre, le même fond et
 * le même rayon que les encadrés dépliants du volet, et l'œil ne distinguait
 * plus ce qui se tape de ce qui se clique. On lui donne une forme à elle :
 * creusée plutôt que posée, arrondie en gélule. La loupe qui y était en
 * filigrane a été retirée : elle doublait le bouton qui, lui, agit.
 */
#search-input {
  width: 100%;
  /* La place à la fin est celle de la loupe, qui vit maintenant DANS le champ ;
     au début il n'y a plus rien à dégager, le dessin décoratif est parti. */
  padding: 0.58rem 2.2rem 0.58rem 0.85rem;
  border-radius: var(--r-pill);
  /* UN CHAMP DOIT SE VOIR AVANT D'ÊTRE CLIQUÉ. Le creux (fond légèrement plus
   * dense + ombre intérieure) suffit sur fond clair, mais en thème sombre le
   * lavis de 7 % et une ombre noire sur un brun déjà sombre ne dessinent plus
   * rien : la gélule disparaissait dans le volet. Un liseré franc rend le champ
   * visible dans les deux thèmes sans lui redonner l'allure d'un bouton. */
  border: 1px solid var(--line);
  background-color: color-mix(in srgb, var(--text) 7%, var(--bg));
  background-size: 16px 16px;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.14);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
}
body.rtl #search-input { padding: 0.58rem 2.2rem 0.58rem 0.85rem; background-position: right 0.7rem center; }
#search-input::placeholder { color: var(--text-faint); }
#search-input:focus {
  outline: none;
  border-color: var(--c-ululazm);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--c-ululazm) 22%, transparent);
}
/* … mais au CLAVIER l'anneau revient : il suit la règle générale posée près
   de `.nav`, et doit être répété ici pour battre le `outline: none` ci-dessus,
   qui a la même spécificité. */
#search-input:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 0; }
/* Le petit triangle du datalist : teinté marron plutôt que noir */
#search-input::-webkit-calendar-picker-indicator {
  filter: invert(34%) sepia(35%) saturate(600%) hue-rotate(350deg) brightness(90%);
  opacity: 0.75;
  cursor: pointer;
}

.seg-full { width: 100%; }
.seg-full button { flex: 1; }

/* Deux boutons carrés côte à côte, avec pictogramme + libellé */
.fold-row { display: flex; gap: 0.5rem; }
.fold-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.6rem 0.35rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-0);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.fold-btn:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.fold-ico {
  width: 22px; height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Bloc « Sources des données » affiché en permanence */
#sources-block {
  width: 100%;
  padding: 0.55rem 0.6rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--bg);
  font-size: var(--fs-0);
}

/*
 * Titre de la bulle verte des filtres exclusifs — fin, en capitales et vert
 * (comme le titre « Sources des données »).
 *
 * IL RECEVAIT SON AIR DEUX FOIS. Premier enfant de l'encadré, il héritait déjà
 * du rembourrage de celui-ci, et y ajoutait sa propre marge : le titre flottait
 * au-dessus de ses cases au lieu de les coiffer. La marge haute part, et
 * l'intitulé se pose sur le groupe qu'il nomme. Même correction sur « Sources
 * des données », pour la même raison.
 */
.filter-only-title {
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--green-ink, var(--c-quran));
  margin-bottom: var(--space-1);
  font-weight: 500;
  line-height: 1.3;
  margin-top: 0;
}

/* Le volet latéral s'ouvre SOUS le bandeau : celui-ci (onglets, langue, thème)
   reste donc entièrement visible et fixe, aucun décalage nécessaire. */

/* ============================================================
   LÉGENDE
   ============================================================ */

/* Une seule bulle verte englobant les deux cases à cocher */
.filter-toggles {
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  padding: 0.4rem 0.6rem;
  border-radius: var(--r-sm);
  border: 1px solid color-mix(in srgb, var(--c-quran) 55%, transparent);
  background: color-mix(in srgb, var(--c-quran) 10%, transparent);
}
.filter-toggles .prophets-toggle {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  line-height: 1.25;
  cursor: pointer;
  border: none;
  background: none;
  padding: 0;
  font-size: var(--fs-0);
}


.prophets-toggle input { accent-color: var(--c-quran); cursor: pointer; margin-top: 2px; width: 16px; height: 16px; }
/* Une option QUI DÉPEND d'une autre se met en retrait sous elle : le décalage
   dit la subordination mieux qu'une phrase. */
.filter-toggles .sub-toggle { margin-inline-start: 1.5rem; font-size: 0.9em; opacity: 0.92; }
/*
 * ET ELLE RESTE VISIBLE QUAND SA CONDITION N'EST PAS REMPLIE.
 *
 * Elle disparaissait ; or on ne cherche pas un réglage dont on ignore
 * l'existence, et l'encadrement des clans se découvrait par hasard. Éteinte,
 * elle apprend deux choses d'un coup : qu'elle existe, et qu'il faut cocher
 * celle du dessus pour s'en servir. `cursor: default` sur toute l'étiquette —
 * un pointeur de main sur une case qui ne répond pas est un mensonge de plus.
 */
.filter-toggles .sub-toggle.indisponible { opacity: 0.42; cursor: default; }
.filter-toggles .sub-toggle.indisponible input { cursor: default; }

/*
 * UNE OPTION ET SON « ? », CÔTE À CÔTE.
 *
 * Le bouton est HORS de l'étiquette — dedans, un clic dessus cocherait la case
 * en même temps qu'il ouvre la fenêtre —, d'où cette rangée. L'étiquette prend
 * la place qui reste, le bouton garde la sienne.
 */
.filter-toggles .sub-row { display: flex; align-items: flex-start; gap: 0.35rem; }
.filter-toggles .sub-row .sub-toggle { flex: 1 1 auto; }
/*
 * ET IL RESTE VIF QUAND SON OPTION EST ÉTEINTE : c'est justement là qu'on se
 * demande à quoi elle sert. Un point d'interrogation grisé avec ce qu'il
 * explique n'explique plus rien.
 */
.qm-help {
  flex: 0 0 auto;
  margin-top: 1px;
  width: 17px; height: 17px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid color-mix(in srgb, var(--c-quran) 60%, transparent);
  border-radius: 50%;
  background: transparent;
  color: var(--c-quran);
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  padding: 0;
  transition: background 0.15s ease, color 0.15s ease;
}
.qm-help:hover { background: var(--c-quran); color: var(--panel); }
.qm-help:focus-visible { outline: 2px solid var(--c-select); outline-offset: 2px; }
@media (pointer: coarse) {
  /* La cible tactile passe à quarante-quatre pixels sans que le disque grossisse :
     c'est le rembourrage qui s'étend, comme pour les autres boutons du volet. */
  .qm-help { width: 44px; height: 44px; border: none; font-size: var(--fs-1); }
  .qm-help:hover { background: transparent; color: var(--c-quran); }
}

/*
 * ENCADRÉS DE CLANS ET DE TRIBUS.
 *
 * La teinte vient du TAG lui-même : le groupe porte sa classe `tag-<clé>`, qui
 * ne pose que `color`, et le contour comme l'étiquette la reprennent par
 * `currentColor`. Un clan a donc dans l'arbre exactement la couleur qu'il a
 * dans sa pastille, sans qu'aucune valeur soit écrite deux fois.
 */
.clan-boxes { pointer-events: none; }
.clan-box path {
  fill: currentColor;
  fill-opacity: 0.07;
  stroke: currentColor;
  /* Le TRAIT porte le groupe, le fond ne fait que le teinter : il monte donc
     presque au plein, quand le remplissage ne bouge pas. */
  stroke-opacity: 0.95;
  stroke-width: 3;
  stroke-dasharray: 12 7;     /* un contour de regroupement, pas une case */
  stroke-linejoin: round;
}
/*
 * UNE ENCEINTE — un cadre qui en CONTIENT d'autres.
 *
 * Les encadrés s'emboîtent sur trois rangs : les Banū ʿAdnān tiennent
 * Quraych, qui tient ses quatorze clans. Donné à tous la même densité, le
 * cadre du dessus se lisait comme le voisin de ceux qu'il entoure. Deux
 * choses le distinguent d'un coup d'œil : un trait plus fin, et des tirets
 * longs. Le remplissage tombe presque à rien — il est déjà traversé par les
 * fonds des cadres qu'il contient, et les superposer troublait les deux.
 * L'ENCRE, elle, reste celle du groupe : c'est ce qui dit lequel on regarde.
 */
.clan-box.clan-enceinte path {
  fill-opacity: 0.025;
  stroke-opacity: 0.95;
  stroke-width: 2;
  stroke-dasharray: 34 16;
}
/*
 * QURAYCH GARDE SON ENCRE À ELLE — et c'est la seule enceinte qui en ait une.
 *
 * Sa teinte de tag était trop claire pour qu'on la voie : un trait de deux
 * pixels dans le beige le plus pâle du dessin se confondait avec le fond, on
 * devinait l'enceinte sans la lire. Elle descend donc de plusieurs crans dans
 * les deux thèmes — c'est le CONTOUR qui change, pas le fond, dont l'opacité
 * ne bouge pas d'un centième.
 */
.clan-box.tag-qurashi, .clan-tag.tag-qurashi,
.clan-lien.tag-qurashi { color: var(--encadre-enceinte); }
.clan-box.tag-qurashi path { stroke: var(--tribu-trait-enceinte); }
/*
 * LES AUTRES TRIBUS — Banū Tamīm, Aws, Khazradj.
 *
 * Elles ne sont pas des buṭūn de Quraych : elles se tiennent au même rang que
 * lui, et leur cadre le dit par un trait plus profond que celui des clans.
 * Seul le TRAIT change — le fond garde `currentColor`, donc la teinte exacte
 * de la pastille du tag, et la pastille elle-même n'est pas touchée.
 */
/*
 * LE CADRE DES SANS-LIGNÉE — celui qui ne dit pas une descendance.
 *
 * Les autres cernent la maison d'un homme ; celui-ci réunit ceux à qui aucun
 * texte n'en donne. Il ne doit donc pas se lire comme un clan de plus : son
 * trait est POINTILLÉ MENU là où les clans ont de longs tirets, et son fond
 * ne teinte presque rien. La teinte est celle des peuples dont il ne reste
 * que le nom — la même famille que ʿĀd et Thamūd —, parce que c'est le même
 * genre de silence.
 */
.tag-sans_lignee  { color: var(--tag-ruin); --tag-c: var(--tag-ruin); }
.clan-box.tag-sans_lignee path {
  fill-opacity: 0.035;
  stroke-width: 2;
  stroke-dasharray: 3 6;
}
/* Son nom ne renvoie à aucun tag : le clic ne mettrait rien en évidence. */
.clan-tag.tag-sans_lignee { pointer-events: none; cursor: default; }
/*
 * LE CADRE DES COMPAGNONS NON ARABES — l'autre qui ne dit pas une descendance.
 *
 * Même dispositif que le précédent, et pour la même raison : ce qui réunit ces
 * six-là est qu'aucune généalogie arabe ne les porte. La teinte est celle des
 * Compagnons, puisque c'est ce qu'ils sont.
 */
.tag-sahaba_non_arabes { color: var(--tag-green); --tag-c: var(--tag-green); }
.clan-box.tag-sahaba_non_arabes path {
  fill-opacity: 0.035;
  stroke-width: 2;
  stroke-dasharray: 3 6;
}
.clan-tag.tag-sahaba_non_arabes { pointer-events: none; cursor: default; }
/*
 * ET LES QUATRE ORIGINES, DEDANS.
 *
 * Elles disent d'où viennent ces Compagnons-là — Perse, Abyssinie, Banū
 * Isrāʾīl, Égypte. Chacune prend l'encre de ce qu'elle nomme : les deux
 * dernières celle du tag que leurs membres portent déjà, les deux premières
 * celle de leur tag neuf. Le trait est celui d'un cadre ordinaire ; c'est leur
 * enceinte qui se dessine autrement, comme toutes les enceintes.
 */
.tag-orig_perse     { color: var(--tag-perse); --tag-c: var(--tag-perse); }
.tag-orig_abyssin   { color: var(--tag-abyssin); --tag-c: var(--tag-abyssin); }
.tag-orig_israelite { color: var(--tag-tribe); --tag-c: var(--tag-tribe); }
.tag-orig_copte     { color: var(--tag-teal2); --tag-c: var(--tag-teal2); }
/* Leur nom ne renvoie à aucun tag de MÊME clé : le clic ne mettrait rien en
   évidence, comme pour les deux cadres qui ne disent pas une descendance. */
.clan-tag.tag-orig_perse, .clan-tag.tag-orig_abyssin,
.clan-tag.tag-orig_israelite, .clan-tag.tag-orig_copte { pointer-events: none; cursor: default; }
.clan-box.tag-tamimi path { stroke: var(--tribu-trait-tamim); }
.clan-box.tag-aws path,
.clan-box.tag-khazraj path { stroke: var(--tribu-trait-clan); }
/*
 * LE NOM DU CLAN, DANS SA PASTILLE.
 *
 * Il vit dans `.clan-tags`, au-dessus des liens (voir `drawClanBoxes`), et sa
 * bulle est OPAQUE : c'est elle qui garantit la lisibilité quand un cadre est
 * trop étroit pour que le nom trouve une place dégagée.
 *
 * ET ELLE NE DOIT PAS POUVOIR SE LIRE COMME UNE CASE (choix de l'utilisateur).
 * C'était un rectangle à coins arrondis, au fond du dessin, portant un nom
 * propre en serif : exactement la silhouette d'une carte de personnage, et
 * « Sans généalogie connue » se prenait pour quelqu'un. Trois choses l'en
 * séparent maintenant, et aucune carte n'en a une seule — les bouts
 * ENTIÈREMENT ronds (`rx` vaut la demi-hauteur, posé par `drawClanBoxes`),
 * le fond TEINTÉ à l'encre du groupe, et les PETITES CAPITALES espacées : un
 * nom de carte s'écrit en bas de casse.
 */
.clan-tags { pointer-events: none; }
/*
 * LE NOM EST CLIQUABLE — le groupe qui le porte reprend donc la souris que sa
 * couche lui refuse. Elle la refuse pour les TRAITS et le vide autour d'eux,
 * qui doivent laisser passer le déplacement du dessin ; la bulle, elle, est
 * un objet qu'on vise. Au survol elle donne la notice du groupe, au clic elle
 * met ses membres en évidence : ce que fait une pastille de tag partout
 * ailleurs.
 */
.clan-tag { pointer-events: auto; cursor: pointer; }
/* Le fond reste OPAQUE — la teinte se mélange au fond du dessin, elle ne s'y
   fond pas : un nom posé sur un trait doit rester lisible. */
.clan-tag rect {
  fill: color-mix(in srgb, currentColor 14%, var(--bg));
  stroke: currentColor;
  stroke-opacity: 0.55;
  stroke-width: 1.5;
}
.clan-tag:hover rect { stroke-opacity: 1; }
/* CHOISI. `.tag.tag-on` se sert d'un fond et d'une ombre portée, dont aucune
   ne s'applique à du SVG : la pastille dit la même chose avec ce qu'elle a —
   son liseré plein et épaissi, et un ton plus soutenu que son ton de repos. */
.clan-tag.tag-on rect {
  stroke-opacity: 1;
  stroke-width: 3;
  fill: color-mix(in srgb, currentColor 34%, var(--bg));
}
/*
 * LE PETIT L QUI RELIE DEUX NOMS EN ESCALIER.
 *
 * Deux cadres emboîtés ont souvent le même coin, et leurs noms se rangent
 * alors en marches (voir `poseEtiquette`). Le trait dit qu'ils vont ensemble
 * et dans quel sens on les lit ; il est de la couleur du nom qu'il rejoint,
 * un peu effacé, et son épaisseur suit l'échelle inverse du nom — il vit dans
 * le plan du dessin, pas dans la bulle.
 */
.clan-lien {
  fill: none;
  stroke: currentColor;
  stroke-opacity: 0.55;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.clan-tag text {
  fill: currentColor;
  font-family: var(--font-serif, Georgia, serif);
  /* Un nom de cadre se lit de loin, à l'échelle où l'on embrasse tout le
     groupe : à 26 px il fallait déjà zoomer pour savoir de quel clan il
     s'agissait. La bulle est mesurée sur le texte rendu, elle suit.
     LES PETITES CAPITALES SONT PLUS COURTES QUE LES BAS DE CASSE à corps
     égal : le corps monte donc de quatre points pour que le nom se lise
     d'aussi loin qu'avant. L'arabe n'a pas de casse et ne bouge pas. */
  font-size: 44px;
  font-weight: 600;
  font-variant-caps: all-small-caps;
  letter-spacing: 0.06em;
  dominant-baseline: alphabetic;
}

/* Segmenté calendrier */
.seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow: hidden;
}
.seg button {
  padding: 0.35rem 0.7rem;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-0);
  cursor: pointer;
  border-right: 1px solid var(--line);
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.seg button:last-child { border-right: none; }
.seg button.active { background: var(--c-ululazm); color: #ffffff; font-weight: 600; }


.legend-item { display: inline-flex; align-items: center; gap: 0.4rem; }

.line-solid {
  width: 22px;
  border-top: 2px solid var(--c-son-link);
  display: inline-block;
  flex: none;
}

.line-dashed {
  width: 24px;
  border-top: 2px dashed var(--c-desc-link);
  display: inline-block;
  flex: none;
}
/* La légende montre le trait qu'on voit : resserré, il est en points. */
body.tight-y .line-dashed { border-top-style: dotted; border-top-width: 3px; }

/* L'échantillon montre le trait qu'on voit. L'alliance est UN SEUL filet rose,
   et une servante le même filet en pointillé — partout : arbre complet, arbre
   restreint, atelier. Seul l'arbre restreint porte cet encadré. */
.line-spouse {
  width: 26px;
  border-top: 1.6px solid var(--alliance);
  display: inline-block;
  flex: none;
}
.line-spouse.servante { border-top-style: dashed; }


#map-container {
  position: relative;
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  cursor: grab;
  border-top: 1px solid var(--line-soft);
}
#map-container:active { cursor: grabbing; }
#tree-svg { width: 100%; height: 100%; display: block; }

/* ============================================================
   LE FOND DU DESSIN — deux trames, d'une seule encre.
   ============================================================
 *
 * UNE TRAME, ET RIEN DE PLUS. Chacune est faite d'UNE encre, posée très pâle
 * sur la couleur du thème : le semis de points, et la toile du papier. Elles
 * aident l'œil à mesurer les distances dans un dessin qui n'a ni bord ni
 * repère, et rien de plus — le motif se devine, il ne se regarde pas.
 *
 * ELLE NE SUIT PAS LE DÉPLACEMENT. Le fond est fixe, comme le ciel de la
 * page : c'est une texture du support, pas un quadrillage du plan. Suivre le
 * zoom demanderait de recalculer la trame à chaque image, pour un dessin qui
 * n'a pas d'échelle métrique — l'axe du temps n'est pas linéaire.
 *
 * CHAQUE MOTIF EST ÉCRIT UNE FOIS pour trois emplois : le grand arbre,
 * l'arbre restreint des fiches, et l'échantillon du bouton qui le choisit.
 *
 * LA TOILE DU PAPIER EST UNE IMAGE, non un dégradé — un SVG posé dans la
 * feuille, en toutes lettres. Ce n'est pas un détail d'écriture : un
 * `repeating-linear-gradient` ne se relit pas, alors qu'une image se recopie
 * telle quelle dans le PNG de l'arbre restreint. Le téléchargement n'a donc
 * pas à connaître la géométrie d'aucun motif : il lit le fond du cadre et le
 * repose (voir « LA TRAME DE FOND, DANS L'IMAGE COMME À L'ÉCRAN » dans app.js).
 * L'ENCRE Y EST ÉCRITE EN DUR, parce qu'une image est un document à part et
 * n'hérite d'aucune variable de la page : c'est pourquoi les deux thèmes se
 * lisent l'un sous l'autre juste en dessous.
 */
:root {
  /* Le semis de points se devinait à peine : son encre monte de 55 à 78 % du
     filet du thème. Il reste une trame — on la voit sans la regarder. */
  --fond-trait: color-mix(in srgb, var(--line) 78%, transparent); --fond-pas: 24px;
  /* Thème NUIT — une encre d'or pâle. */
  --fond-papier-tuile: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><g stroke='%23c8b184' fill='none' stroke-width='0.7'><path opacity='0.12' d='M0 0.5 H24M0 4.5 H24M0 8.5 H24M0 12.5 H24M0 16.5 H24M0 20.5 H24'/><path opacity='0.17' d='M0.5 0 V24M4.5 0 V24M8.5 0 V24M12.5 0 V24M16.5 0 V24M20.5 0 V24'/></g></svg>");
  --fond-papier-vignette: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><g stroke='%23c8b184' fill='none' stroke-width='1'><path opacity='0.36' d='M0 0.5 H24M0 4.5 H24M0 8.5 H24M0 12.5 H24M0 16.5 H24M0 20.5 H24'/><path opacity='0.48' d='M0.5 0 V24M4.5 0 V24M8.5 0 V24M12.5 0 V24M16.5 0 V24M20.5 0 V24'/></g></svg>");
}
:root.light {
  /* Thème JOUR — un brun de plume, plus dense sur le crème. */
  --fond-papier-tuile: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><g stroke='%238a6b3d' fill='none' stroke-width='0.7'><path opacity='0.15' d='M0 0.5 H24M0 4.5 H24M0 8.5 H24M0 12.5 H24M0 16.5 H24M0 20.5 H24'/><path opacity='0.21' d='M0.5 0 V24M4.5 0 V24M8.5 0 V24M12.5 0 V24M16.5 0 V24M20.5 0 V24'/></g></svg>");
  --fond-papier-vignette: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><g stroke='%238a6b3d' fill='none' stroke-width='1'><path opacity='0.42' d='M0 0.5 H24M0 4.5 H24M0 8.5 H24M0 12.5 H24M0 16.5 H24M0 20.5 H24'/><path opacity='0.55' d='M0.5 0 V24M4.5 0 V24M8.5 0 V24M12.5 0 V24M16.5 0 V24M20.5 0 V24'/></g></svg>");
}

body[data-fond="dots"] #map-container, body[data-fond="dots"] .rt-frame,
#bg-control button[data-bg="dots"] .bg-swatch {
  background-image: radial-gradient(circle at 1px 1px, var(--fond-trait) 1px, transparent 0);
  background-size: var(--fond-pas) var(--fond-pas);
}
/*
 * LE PAPIER EST UNE TOILE, ET NON UN BRUIT.
 *
 * Il a été un grain calculé par le navigateur (`feTurbulence`). Un bruit est
 * fait de PIXELS : agrandi, il se voit pour ce qu'il est, et le fond avait
 * l'air pixelisé plutôt que texturé. Ce sont maintenant des TRAITS — deux
 * familles de fils fins qui se croisent à angle droit, tous les quatre pixels,
 * comme la chaîne et la trame d'une toile. Un trait n'a pas de résolution : il
 * reste net à toutes les échelles, et la tuile ne pèse plus que trois cents
 * octets au lieu de huit cents.
 *
 * LES DEUX FAMILLES N'ONT PAS LA MÊME ENCRE. À encre égale on lit un
 * quadrillage ; en donnant à la trame un tiers d'encre de plus qu'à la chaîne,
 * on lit un tissage. C'est toute la différence entre du papier millimétré et
 * du papier à grain.
 */
body[data-fond="papier"] #map-container, body[data-fond="papier"] .rt-frame,
#bg-control button[data-bg="papier"] .bg-swatch {
  background-image: var(--fond-papier-tuile);
  background-size: 24px 24px;
}

/* Le choix, dans les préférences d'affichage : trois pastilles, chacune montrant
   son fond. */
.bg-pills { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-bottom: 0.2rem; }
.bg-pills button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.28rem 0.5rem 0.28rem 0.3rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 0.74rem;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.bg-pills button:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.bg-pills button.active { border-color: var(--c-ululazm); color: var(--text); background: var(--bg-raised-2); }
.bg-swatch {
  /* Le pas de l'échantillon, plus court que celui du dessin : sur seize
     pixels de côté, la trame du grand arbre ne montrerait qu'un seul point. */
  --fond-pas: 8px;
  width: 18px; height: 18px;
  flex: none;
  border: 1px solid var(--line-soft);
  border-radius: 3px;
  background-color: var(--panel);
}
/*
 * LA PASTILLE MONTRE LE FOND, PAS SA RÉDUCTION.
 *
 * La GRAVURE, réduite de cent quarante à dix-huit pixels, ne donnait qu'un
 * voile gris — un trait d'un pixel posé à douze pour cent d'encre ne survit pas
 * à une division par huit. Chaque trame a donc sa VIGNETTE : le même motif, un
 * seul exemplaire, tracé assez franchement pour se reconnaître à la taille d'un
 * ongle. C'est le même métier que le pas raccourci des points juste au-dessus,
 * et la même raison.
 *
 * La règle vient après celles des trames, qu'elle corrige ; à spécificité
 * égale, c'est l'ordre qui décide.
 */
#bg-control button[data-bg="papier"] .bg-swatch {
  background-image: var(--fond-papier-vignette);
  background-size: 100% 100%;
}

.link { fill: none; stroke: var(--c-son-link); stroke-width: 1.6px; }
.link.descendant { stroke: var(--c-desc-link); stroke-width: 1.6px; stroke-dasharray: 7 5; }
/*
 * RESSERRÉ, LE TIRET DEVIENT UN POINT.
 *
 * Un tiret de sept pixels suivi d'un blanc de cinq se lit sur la longue
 * descente du dessin aéré. Resserré, la même descente ne mesure plus que
 * quelques dizaines de pixels : deux tirets, parfois un seul, et le
 * « descendant de » ne se distinguait plus du trait plein. Des points ronds
 * espacés de leur propre diamètre se reconnaissent sur n'importe quelle
 * longueur — c'est ce que dit le mot « pointillé ».
 */
body.tight-y .link.descendant { stroke-dasharray: 0 6; stroke-linecap: round; stroke-width: 2.4px; }

/* Légende des liens, en bas à gauche de l'arbre */
#link-legend {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  z-index: 8;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.9rem 1.15rem;
  border-radius: 3px;
  border: 1px solid var(--line);
  background: var(--legend-bg);
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);
  font-size: var(--fs-2);
  color: var(--text);
}
#link-legend .legend-item { gap: 0.6rem; }
#link-legend .line-solid, #link-legend .line-dashed { width: 34px; }


/* ============================================================
   CARTES (style calqué sur la maquette)
   ============================================================ */
.node-wrap { position: relative; width: 100%; height: 100%; padding: 16px 16px 0; }

/*
 * `#measure` et `#name-sample` portent déjà la classe `card` (voir `cardSize`
 * et `renderNameSample`) : les nommer ici en plus était non seulement inutile,
 * mais NUISIBLE. Un sélecteur d'id l'emporte sur n'importe quelle classe, si
 * bien que ce `border: 1px` écrasait le `border-width: 2px` de `.card.ululazm`
 * — dans le mesureur seulement, pas dans l'arbre. Les cinq prophètes ūlū
 * l-ʿazm étaient donc mesurés deux pixels trop étroits et trop courts, et
 * démentaient leur taille estimée dès qu'ils entraient à l'écran.
 */
/*
 * LE CARTOUCHE. Un second filet, très pâle, tiré en retrait du bord : c'est le
 * djadwal du folio ramené à l'échelle de la carte, et c'est ce qui distingue
 * un cartouche d'une simple boîte.
 *
 * ATTENTION — il est posé en `box-shadow`, JAMAIS en `border`. C'est la raison
 * du choix : une bordure de plus aurait changé la taille mesurée des cartes,
 * donc la mise en page entière, donc la planarité. La leçon des cinq prophètes
 * ūlū l-ʿazm mesurés deux pixels trop petits vaut ici aussi.
 *
 * Il est déclaré en VARIABLE, et non écrit dans chaque règle. `box-shadow` est
 * une propriété unique : toute déclaration ultérieure — le survol, la
 * sélection, le halo d'un prophète — efface celles d'avant. Écrit à la main,
 * le cartouche disparaissait donc dès qu'on survolait la carte, et n'existait
 * pas du tout sur les prophètes, dont la règle propre est plus spécifique.
 * Chaque variante redéfinit `--cartouche` à SA couleur (le filet reprend celle
 * de la bordure) et le cite dans toutes ses ombres.
 */
.card {
  --cartouche:
    inset 0 0 0 3px var(--card-bg),
    inset 0 0 0 4px color-mix(in srgb, var(--c-ululazm) 26%, transparent);
  position: relative;
  display: inline-flex;
  flex-direction: column;
  gap: 4px;
  min-width: 215px;
  max-width: 430px;
  padding: 10px 14px 16px;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  background: var(--card-bg);
  box-shadow: var(--cartouche), var(--box-shadow);
  cursor: pointer;
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
/* Un peu de place en bas quand le bouton +/− côtoie un surnom ou des tags. */
.card.roomy { padding-bottom: 21px; }
/* Carte sans surnom ni tag : plus de hauteur pour dégager le bouton « i ». */
.card.bare { padding-bottom: 30px; }
/*
 * UN SEUL NOM, RIEN D'AUTRE : LE NOM DEVIENT LA CARTE.
 *
 * Quand une case ne porte qu'une forme de nom — l'arabe OU le latin — et que
 * les surnoms comme les étiquettes sont masqués, il ne reste qu'un mot posé en
 * haut à gauche d'un rectangle vide. Le nom se met alors au MILIEU, dans les
 * deux sens, et grandit de moitié : la case n'a plus rien d'autre à porter,
 * autant que ce qu'elle porte se lise de loin.
 *
 * Les 32 px de rembourrage latéral ne sont pas décoratifs : le disque du
 * bouton « i » s'arrête à 30 px du bord droit, et le nom, centré, ne peut donc
 * jamais passer dessous. La symétrie gauche/droite est ce qui le garde centré.
 *
 * La règle vient APRÈS `.card.bare`, qu'elle corrige : les deux ont la même
 * spécificité, c'est l'ordre qui décide, et le rembourrage bas de 30 px
 * dégagé pour le bouton décentrerait le nom.
 */
.card.solo {
  align-items: center;
  justify-content: center;
  padding: 16px 32px;
}
.card.solo .card-fr { font-size: 25px; }
/*
 * LE NOM ARABE EST REMONTÉ DE TROIS HUITIÈMES DE CADRATIN, et ce n'est pas un
 * réglage à l'œil.
 *
 * Amiri déclare une hauteur de 1,8 cadratin au-dessus de la ligne d'écriture
 * et 0,65 en dessous — 2,45 en tout, quand l'interligne n'en vaut que 1,4. Le
 * navigateur répartit la différence de part et d'autre, ce qui pose la ligne
 * d'écriture 0,575 cadratin SOUS le milieu de la boîte ; l'encre, elle, monte
 * de 0,95 et descend de 0,55, donc son milieu tombe 0,375 cadratin trop bas.
 * Mesuré : le nom finissait à quatre pixels du bord inférieur d'une case qui
 * en compte seize de rembourrage. Il en compte seize des deux côtés
 * maintenant.
 *
 * `top` ne déplace RIEN dans la mise en page : la case garde sa hauteur, seule
 * l'encre remonte — c'est justement ce qu'on veut, la case étant déjà à la
 * bonne taille.
 */
.card.solo .card-ar { font-size: 30px; top: -0.375em; }
.card { width: 100%; }
/* Une carte de l'arbre est dans un `foreignObject` : l'anneau y suit le tracé
   de la case, d'où le décalage un peu plus large qu'ailleurs. */
.card:focus-visible { outline: 2px solid var(--c-select); outline-offset: 3px; }
/* VUE DE LOIN — la carte n'est plus qu'un cadre : à cette échelle il n'y a
   rien à lire, et l'on épargne tout le contenu HTML de plusieurs centaines de
   cartes. La couleur de catégorie, elle, reste : c'est la seule chose qui se
   lise encore. */
/* Le survol ENFONCE la carte au lieu de la soulever. L'enfoncement est cité
   APRÈS le cartouche : les ombres s'empilent du dessus vers le dessous, le
   filet reste donc net et l'ombre s'insinue dessous. */
.card:hover { box-shadow: var(--cartouche), var(--card-pressed), var(--box-shadow-pressed); }

/* Mesureur hors écran (calcule la taille réelle de chaque carte).
   width:auto est indispensable : sinon la carte prend la largeur maximale.
   Il est déporté vers le HAUT et non vers la gauche : en écriture arabe
   (direction: rtl) un décalage horizontal énorme empêche le navigateur de
   peindre la page entière. */
#measure, #measure.card {
  position: absolute;
  left: 0;
  top: -99999px;
  width: auto;
  visibility: hidden;
  pointer-events: none;
  white-space: normal;
}

/* Même cachette que #measure, pour un lot entier de cartes. */
#measure-batch {
  position: absolute;
  left: 0;
  top: -99999px;
  width: 4000px;
  visibility: hidden;
  pointer-events: none;
  white-space: normal;
}
/* Chaque carte du lot est posée EXACTEMENT comme `#measure` : positionnée en
   absolu, largeur automatique. Deux boîtes en position absolue ne s'influencent
   pas, elles peuvent donc toutes tenir au même endroit — et chacune retrouve
   au pixel la largeur qu'elle aurait eue seule dans le mesureur. En flux
   ordinaire, une carte s'étire jusqu'à son `max-width` (430 px) au lieu de se
   replier sur son contenu, et les noms suivis d'une ligature honorifique se
   replient un pixel plus loin. */
#measure-batch > div {
  position: absolute;
  left: 0;
  top: 0;
  width: auto;
}

.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.card-fr {
  font-family: var(--font-carte);
  font-size: 17px;
  line-height: 1.15;
  color: var(--text);
  white-space: nowrap;
}
.card-ar {
  font-family: var(--font-arabic);
  direction: rtl;
  font-size: 21px;
  line-height: 1.4;
  position: relative;
  top: -3px;
  color: var(--c-arabic);
  white-space: nowrap;
}
/* LA FILIATION D'UNE CASE — « fille de Hārān », « bint Khuwaylid ». Elle ne
   paraît que dans l'arbre restreint, sur les épouses et les deux parents, et
   se tient sous le nom : c'est une précision sur le nom, pas un surnom, d'où
   le romain là où le surnom est en italique. */
.card-fil {
  font-family: var(--font-carte);
  font-size: 12.5px;
  line-height: 1.25;
  color: var(--text-muted);
  max-width: 340px;
  margin-top: 3px;
}
.card-nick {
  font-family: var(--font-carte);
  font-style: italic;
  font-size: 12.5px;
  line-height: 1.25;
  color: var(--text-muted);
  max-width: 340px;
  margin-top: 3px;
  margin-bottom: 3px;
}
/*
 * LE COIN DU BOUTON « i » EST RÉSERVÉ.
 *
 * Le bouton est un disque de 11 px de rayon, centré à 19 px du bord droit :
 * il mord donc de 16 px dans la zone de contenu, dont le bord est à 14 px. Une
 * étiquette qui arrivait jusque-là passait dessous — 191 cartes sur 1 048, et
 * jusqu'à 15 px de mot recouvert. Ce rembourrage rend ces 16 px (plus 2 px
 * d'air) : la rangée d'étiquettes s'arrête avant le disque, et la carte
 * s'élargit d'autant — mais SEULEMENT quand ce sont les étiquettes qui
 * dictent sa largeur, c'est-à-dire exactement dans les cas concernés.
 * Mesuré : 0 recouvrement, 214 cartes élargies (+18 px au plus), aucune
 * hauteur changée.
 *
 * `padding-right`, et non `padding-inline-end` : le bouton est posé sur le
 * bord DROIT physique (`right: 8px`), et le dessin est toujours en `ltr`,
 * même quand l'interface est en arabe.
 */
.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 2px;
  padding-right: 18px;
}

/* Étiquettes (tags) */
/*
 * L'ÉTIQUETTE PREND L'ÉCRITURE DU SITE — SAUF DANS UNE CASE, où elle prend
 * celle de la case. Une même pastille paraît dans le volet, dans la fiche, sur
 * la page des tags et dans les cases de l'arbre ; seules les dernières sont
 * MESURÉES, et sur 214 cartes ce sont les étiquettes qui dictent la largeur.
 * `.card .tag` est plus spécifique et l'emporte : le dessin ne bouge pas d'un
 * pixel, et partout ailleurs la pastille cesse de jurer avec le texte qui
 * l'entoure.
 */
.tag {
  font-family: var(--font-display);
  font-size: 11px;
  line-height: 1;
  padding: 4px 7px;
  border-radius: var(--r-xs);
  border: 1px solid currentColor;
  white-space: nowrap;
}
.card .tag { font-family: var(--font-carte); }
/* NOM D'USAGE — « ibn Masʿūd », « Abū Dharr al-Ghifārī ». Plus clair que le
   prénom pour qu'on distingue les deux d'un coup d'œil, mais assez contrasté
   pour rester lu : ce n'est pas une mention secondaire, c'est le nom que tout
   le monde emploie. */
.known { color: var(--known-fg); font-weight: 400; }

.tag-prophete     { color: var(--tag-blue); --tag-c: var(--tag-blue); }
.tag-prophete_bib { color: var(--tag-plum); --tag-c: var(--tag-plum); }
.tag-ululazm      { color: var(--tag-amber); --tag-c: var(--tag-amber); }
.tag-roi          { color: var(--tag-red); --tag-c: var(--tag-red); }
/* Tubbaʿ est le titre de ce roi-là : même famille de teinte que « Roi ». */
.tag-tubba        { color: var(--tag-red); --tag-c: var(--tag-red); }
.tag-banu         { color: var(--tag-tribe); --tag-c: var(--tag-tribe); }
/* Les trois tags de lignée arabe partagent la même famille orange */
.tag-arabe        { color: var(--tag-orange); --tag-c: var(--tag-orange); }
.tag-adnaniy      { color: var(--tag-orange); --tag-c: var(--tag-orange); }
.tag-qahtaniy     { color: var(--tag-orange); --tag-c: var(--tag-orange); }
/* Quraysh est une sous-lignée des ‘Adnâniy : même famille, ton plus profond */
.tag-qurashi      { color: var(--tag-qurashi); --tag-c: var(--tag-qurashi); }
/* Banū Tamīm : tribu ʿadnānite du même rang que Quraych, sans en être un clan —
   même famille de bruns, teinte propre. */
.tag-tamimi       { color: var(--tag-tamim); --tag-c: var(--tag-tamim); }
/* Les deux maisons du Yémen, sous Qaḥṭāniy comme Quraych est sous ʿAdnāniy :
   une famille de brique, un ton par maison. */
.tag-himyari      { color: var(--tag-himyar); --tag-c: var(--tag-himyar); }
/* Quḍāʿiy ne relève d'aucune des deux souches : sa teinte ne peut donc être
   ni celle du Nord ni celle du Sud. Un brun-doré qui reste dans la famille
   des tags arabes sans se ranger dans l'une des deux maisons. */
.tag-qudaiy       { color: var(--tag-qudaa); --tag-c: var(--tag-qudaa); }
.tag-kahlani      { color: var(--tag-kahlan); --tag-c: var(--tag-kahlan); }
/* Le clan (baṭn) est la subdivision la plus fine de Quraych : ton le plus profond */
/* ʿĀd, Thamūd et les ʿAmāliq : des peuples disparus, non des clans vivants —
   une teinte à eux, la même pour les trois, qui ne les range ni chez les
   Arabes du Nord ni chez ceux du Sud. Leur tag père la porte aussi : c'est
   la disparition que la teinte dit, et il est ce qui la nomme. */
.tag-arab_baida   { color: var(--tag-ruin); --tag-c: var(--tag-ruin); }
.tag-aad          { color: var(--tag-ruin); --tag-c: var(--tag-ruin); }
.tag-thamud       { color: var(--tag-ruin); --tag-c: var(--tag-ruin); }
.tag-amalecite    { color: var(--tag-ruin); --tag-c: var(--tag-ruin); }
/* Aws et Khazradj sont des clans eux aussi : même famille de teinte */
.tag-aws          { color: var(--tag-clan); --tag-c: var(--tag-clan); }
.tag-khazraj      { color: var(--tag-clan); --tag-c: var(--tag-clan); }
.tag-syriaque     { color: var(--tag-syriac); --tag-c: var(--tag-syriac); }
.tag-copte        { color: var(--tag-teal2); --tag-c: var(--tag-teal2); }
.tag-moabite      { color: var(--tag-moab); --tag-c: var(--tag-moab); }
.tag-perse        { color: var(--tag-perse); --tag-c: var(--tag-perse); }
.tag-abyssin      { color: var(--tag-abyssin); --tag-c: var(--tag-abyssin); }
.tag-sahabi       { color: var(--tag-green); --tag-c: var(--tag-green); }
/* La maison du Prophète ﷺ, et les cinq du manteau : même famille, même encre. */
.tag-ahl_bayt     { color: var(--tag-bayt); --tag-c: var(--tag-bayt); }
.tag-ahl_kisa     { color: var(--tag-bayt); --tag-c: var(--tag-bayt); }
/* Tābiʿiy : la génération d'après les Compagnons, même famille, ton plus clair */
.tag-tabii        { color: var(--tag-teal2); --tag-c: var(--tag-teal2); }
/* Les deux moitiés de Médine : émigrés et accueillants, même famille de teinte */
.tag-muhajirun    { color: var(--tag-hijra); --tag-c: var(--tag-hijra); }
.tag-ansar        { color: var(--tag-hijra); --tag-c: var(--tag-hijra); }
/* Les journées : Badr, Uḥud, le Serment de l'Agrément */
.tag-badr         { color: var(--tag-event); --tag-c: var(--tag-event); }
.tag-uhud         { color: var(--tag-event); --tag-c: var(--tag-event); }
.tag-ridwan       { color: var(--tag-event); --tag-c: var(--tag-event); }
.tag-femme        { color: var(--tag-pink); --tag-c: var(--tag-pink); }
/* Les Mères des croyants : même famille que « Femme », en rose foncé */
.tag-mere_croyants { color: var(--tag-rose); --tag-c: var(--tag-rose); }
/* Califes : même vert foncé pour le titre et sa forme « bien guidé » */
.tag-calife        { color: var(--tag-caliph); --tag-c: var(--tag-caliph); }
.tag-calife_rashid { color: var(--tag-caliph); --tag-c: var(--tag-caliph); }
/* Les Dix promis au Paradis : le vert-bleu, réservé à eux seuls */
.tag-achara        { color: var(--tag-teal); --tag-c: var(--tag-teal); }
.tag-fondateur    { color: var(--tag-crimson); --tag-c: var(--tag-crimson); }
/* Chaque tribu d'Israël et chaque clan de Quraych est un tag à part
   entière, mais la COULEUR reste celle de la famille : une tribu se
   reconnaît d'un coup d'œil comme une tribu. */
[class*="tag-tribu_"] { color: var(--tag-tribe); --tag-c: var(--tag-tribe); }
/* Chaque clan a SA teinte ; le brun générique ne sert plus que de repli pour
   un clan qui n'aurait pas encore la sienne. */
[class*="tag-clan_"]  { color: var(--tag-clan); --tag-c: var(--tag-clan); }
.tag-clan_hashim      { color: var(--clan-hashim); --tag-c: var(--clan-hashim); }
.tag-clan_muttalib    { color: var(--clan-muttalib); --tag-c: var(--clan-muttalib); }
.tag-clan_nawfal      { color: var(--clan-nawfal); --tag-c: var(--clan-nawfal); }
.tag-clan_umayyah     { color: var(--clan-umayyah); --tag-c: var(--clan-umayyah); }
.tag-clan_abd_al_dar  { color: var(--clan-abd_al_dar); --tag-c: var(--clan-abd_al_dar); }
.tag-clan_asad_uzza   { color: var(--clan-asad_uzza); --tag-c: var(--clan-asad_uzza); }
.tag-clan_zuhrah      { color: var(--clan-zuhrah); --tag-c: var(--clan-zuhrah); }
.tag-clan_taym        { color: var(--clan-taym); --tag-c: var(--clan-taym); }
.tag-clan_makhzum     { color: var(--clan-makhzum); --tag-c: var(--clan-makhzum); }
.tag-clan_adiyy       { color: var(--clan-adiyy); --tag-c: var(--clan-adiyy); }
.tag-clan_sahm        { color: var(--clan-sahm); --tag-c: var(--clan-sahm); }
.tag-clan_jumah       { color: var(--clan-jumah); --tag-c: var(--clan-jumah); }
.tag-clan_amir_luayy  { color: var(--clan-amir_luayy); --tag-c: var(--clan-amir_luayy); }
.tag-clan_harith_fihr { color: var(--clan-harith_fihr); --tag-c: var(--clan-harith_fihr); }
.tag-chef_etat    { color: var(--tag-red); --tag-c: var(--tag-red); }
/* LA TEINTE DE LA PASTILLE SE RAPPROCHE DE L'ENCRE — et cette règle doit
 * venir APRÈS la liste des teintes ci-dessus, pas avant.
 *
 * Chaque `.tag-x` pose sa couleur pure ET son `--tag-c`. Les deux sélecteurs
 * pèsent pareil (0,1,0) : c'est donc l'ORDRE qui décide, et le mélange n'a le
 * dernier mot que s'il est écrit plus bas. Le remonter dans la règle `.tag`
 * générale rendrait sa teinte pure à chaque pastille — mesuré, quatorze
 * couleurs repassent sous le seuil de contraste. */
.tag {
  color: color-mix(in oklab, var(--tag-c, currentColor) 65%, var(--text));
  border-color: var(--tag-c, currentColor);
}
.tag[data-tag] { cursor: help; }
/* Carte en arabe seul : le nom arabe se place du côté fin (droite en LTR interne) */
.card-head.ar-only { justify-content: flex-end; }

/* Accent de catégorie sur la carte */
.card.quran {
  /* Bordure et fond plus soutenus qu'auparavant (60 % / fond neutre), plus un
     halo bleu : un prophète doit se repérer d'un coup d'œil dans l'arbre. */
  /* Le filet du cartouche prend la couleur de la carte, et non l'or commun :
     sur une carte de prophète, l'or et le bleu se disputeraient le même bord.
     Le fond du premier anneau suit lui aussi celui de la carte, sans quoi le
     cartouche se dessinerait dans une couleur qui n'est pas la sienne. */
  --cartouche:
    inset 0 0 0 3px var(--card-bg-prophet),
    inset 0 0 0 4px color-mix(in srgb, var(--tag-blue) 45%, transparent);
  border-color: color-mix(in srgb, var(--tag-blue) 85%, var(--card-border));
  background: var(--card-bg-prophet);
  box-shadow: var(--cartouche), var(--box-shadow), var(--glow-prophet);
}
.card.quran:hover { box-shadow: var(--cartouche), var(--card-pressed), var(--box-shadow-pressed), var(--glow-prophet); }

/*
 * LES COMPAGNONS ﵁ — un fond vert très pâle, et RIEN D'AUTRE.
 *
 * Ils sont plus de deux cents, dispersés parmi mille personnes : rien ne les
 * rassemblait à l'œil, il fallait lire les étiquettes case par case. Le fond
 * les donne d'un coup d'œil — la génération de Médine se voit comme une nappe
 * dans le bas du dessin.
 *
 * NI BORDURE, NI REMBOURRAGE, NI CORPS : la largeur d'une case est mesurée et
 * porte toute la mise en page ; la moindre de ces trois choses déplacerait
 * mille cartes et il faudrait reprendre la planarité. Un fond ne coûte rien.
 *
 * `--cartouche` est REDÉFINI, et il le faut : son premier anneau est peint à la
 * couleur du fond de carte, et laissé tel quel il aurait dessiné un liseré
 * blanc à trois pixels du bord. La règle du filet des prophètes, juste
 * au-dessus, dit la même chose pour la même raison.
 */
.card.sahabi {
  --cartouche:
    inset 0 0 0 3px var(--card-bg-sahabi),
    inset 0 0 0 4px color-mix(in srgb, var(--c-ululazm) 26%, transparent);
  background: var(--card-bg-sahabi);
  border-color: color-mix(in srgb, var(--tag-green) 32%, var(--card-border));
}
/* Léger halo lumineux autour des noms de prophètes (surtout en mode nuit) */
.card.quran .card-fr, .card.ululazm .card-fr, .card.muhammad .card-fr,
.card.is-prophet .card-fr { text-shadow: var(--name-glow); }
.card.quran .card-ar, .card.ululazm .card-ar, .card.muhammad .card-ar { text-shadow: var(--name-glow); }
.card.ululazm  {
  --cartouche:
    inset 0 0 0 3px var(--card-bg-ululazm),
    inset 0 0 0 4px color-mix(in srgb, var(--c-ululazm) 50%, transparent);
  border-color: var(--c-ululazm);
  border-width: 2px;
  background: var(--card-bg-ululazm);
  box-shadow: var(--cartouche), var(--box-shadow), var(--glow-ululazm);   /* halo doré */
}
.card.ululazm:hover { box-shadow: var(--cartouche), var(--card-pressed), var(--box-shadow-pressed), var(--glow-ululazm); }
/*
 * ═══════════════════════════════════════════════════════════════════════════
 * LE CARTOUCHE EST ROMPU : QUATRE ÉQUERRES D'OR, ET NON PLUS UN ANNEAU.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Les couleurs ne changent pas et le halo doré reste (choix de l'utilisateur) :
 * c'est le STYLE de l'encadré qui change. C'était un anneau d'or plein, à deux
 * pixels du bord et large de deux — un second liseré parallèle au premier, si
 * près de lui qu'à la distance de lecture les deux se lisaient comme une
 * bordure épaisse et un peu molle. À la place, le filet intérieur est ROMPU :
 * il ne subsiste qu'aux quatre ANGLES, en équerres fines. C'est le cadre d'une
 * page enluminée, où le trait de réglure ne se referme pas et où les angles
 * portent le travail.
 *
 * IL EST PEINT DANS LE FOND, ET NON DANS L'OMBRE — c'est ce qui le rend
 * meilleur que l'anneau qu'il remplace. `box-shadow` est une propriété UNIQUE :
 * le survol et la sélection la réécrivent, et chaque variante devait donc
 * recopier son cartouche dans chacune de ses ombres (voir `.card`). Un fond ne
 * se réécrit jamais : les équerres tiennent au survol, à la sélection et sous
 * le cadre multicolore des tags, sans que rien ne les répète.
 *
 * ET RIEN NE BOUGE D'UN PIXEL. Une image de fond n'occupe pas de place : ni la
 * bordure, ni le rembourrage, ni la police ne changent, donc pas une carte de
 * l'arbre ne se déplace — `tools/t_geo.js` le vérifie.
 */
.card.muhammad {
  /* Le creux du fond, qui donne à la case l'épaisseur d'une plaque. Il reste
     dans `--cartouche` parce que la sélection et le survol le citent. */
  --cartouche: inset 0 2px 5px rgba(0, 0, 0, 0.28);
  --or-equerre: var(--c-muhammad-gold);
  border: 2px solid var(--c-muhammad-gold);
  background-color: var(--c-muhammad-bg);
  /* Huit traits : deux bras par angle. */
  background-image:
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre)),
    linear-gradient(var(--or-equerre), var(--or-equerre));
  background-repeat: no-repeat;
  background-size:
    14px 1.5px, 1.5px 14px,
    14px 1.5px, 1.5px 14px,
    14px 1.5px, 1.5px 14px,
    14px 1.5px, 1.5px 14px;
  /* La forme longue (« right 4px top 4px ») et non `calc(100% - 4px)` : la
     seconde pose le BORD GAUCHE du trait à cette abscisse, et les équerres de
     droite sortaient de la case. */
  background-position:
    left 4px top 4px, left 4px top 4px,
    right 4px top 4px, right 4px top 4px,
    left 4px bottom 4px, left 4px bottom 4px,
    right 4px bottom 4px, right 4px bottom 4px;
  box-shadow: var(--cartouche), 0 0 0 1px var(--c-muhammad-gold),
              0 0 22px 3px color-mix(in srgb, var(--c-muhammad-gold) 50%, transparent);
}
.card.muhammad .card-fr { color: #fdf6e3; }
.card.muhammad .card-ar { color: #f6e2ac; }
.card.muhammad .card-nick { color: #e8dcb8; }
.card.muhammad .tag { color: #f2e2b6; border-color: currentColor; }
/* ET LA LIGATURE ﷺ REPREND L'OR DE SA CARTE. `.ah` porte sa propre couleur —
   l'encre arabe, un brun doré — et cette couleur-là l'emporte sur celle du nom
   qui la contient : sur le vert profond de cette carte, elle donnait un brun
   sombre qu'on ne lisait plus, en thème jour comme en thème nuit. Elle prend
   donc l'or franc du cartouche, celui de l'anneau. */
.card.muhammad .ah { color: var(--c-muhammad-gold); }
/* Compteur de cases dépliées : présent sans se faire remarquer. */
#visible-count {
  position: absolute;
  top: 10px; right: 14px;
  z-index: 6;
  padding: 0.18rem 0.55rem;
  border-radius: 999px;
  background: var(--bg-raised);
  color: var(--text-muted);
  font-size: var(--fs-00);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  pointer-events: none;
}
body.rtl #visible-count { right: auto; left: 14px; }
/* La fiche recouvre le coin droit : le compteur se décale pour rester lu. */
body.panel-open #visible-count { right: calc(var(--panel-w) + 14px); }
body.rtl.panel-open #visible-count { right: auto; left: calc(var(--panel-w) + 14px); }
#visible-count { transition: right 0.28s ease, left 0.28s ease; }

/*
 * LE MESSAGE DE DESSIN VIDE.
 *
 * Il se pose AU MILIEU de l'aire du dessin, là où l'œil cherche l'arbre, et
 * non dans un coin : c'est la seule chose à lire quand il n'y a rien d'autre.
 * Une carte de lecture, dans les tons du volet — pas une alerte : rien n'est
 * cassé, les filtres font ce qu'on leur a demandé.
 */
#tree-empty {
  position: absolute;
  top: 50%; left: 50%;
  z-index: 7;
  transform: translate(-50%, -50%);
  width: min(30rem, calc(100% - 3rem));
  padding: 1.4rem 1.6rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--ombre-2);
  text-align: center;
}
#tree-empty p { margin: 0; color: var(--text); font-size: var(--fs-4); }
#tree-empty .empty-sub {
  margin-top: 0.5rem;
  color: var(--text-muted);
  font-size: var(--fs-1);
  line-height: 1.5;
}
#tree-empty button {
  margin-top: 1rem;
  padding: 0.42rem 1rem;
  border: 1px solid var(--c-ululazm);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-ululazm);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
#tree-empty button:hover { background: var(--c-ululazm); color: var(--bg); }

/*
 * MISE EN ÉVIDENCE PAR TAG — un liseré aux couleurs des tags choisis.
 *
 * Il est porté par un pseudo-élément et non par `box-shadow` sur la carte :
 * l'ombre y sert déjà à la sélection, au survol et à la carte du Prophète ﷺ,
 * et les trois se marcheraient dessus. Les bandes sont CONCENTRIQUES — une par
 * tag —, ce qui respecte l'arrondi de la carte : bicolore à deux tags,
 * tricolore à trois, et ainsi de suite.
 */
.card.tag-hi::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 7px;
  padding: 2px;                       /* l'épaisseur du cadre */
  pointer-events: none;
  /* Un dégradé conique découpé en secteurs NETS : chaque tag prend une part
     égale du tour de la carte. Le masque ne garde que la bordure, de sorte
     que le cadre est UNIQUE — la moitié d'une couleur, la moitié de l'autre —
     et non des anneaux emboîtés les uns dans les autres. */
  background: conic-gradient(from 135deg, var(--hi1) 0 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.card.tag-hi.hi-2::after {
  background: conic-gradient(from 135deg, var(--hi1) 0 50%, var(--hi2) 50% 100%);
}
.card.tag-hi.hi-3::after {
  background: conic-gradient(from 135deg, var(--hi1) 0 33.34%, var(--hi2) 33.34% 66.67%,
                             var(--hi3) 66.67% 100%);
}
.card.tag-hi.hi-4::after {
  background: conic-gradient(from 135deg, var(--hi1) 0 25%, var(--hi2) 25% 50%,
                             var(--hi3) 50% 75%, var(--hi4) 75% 100%);
}
/* Le tag choisi, là où il s'affiche : il se remplit de sa propre couleur. */
.tag.tag-on {
  background: color-mix(in srgb, currentColor 22%, transparent);
  border-radius: 3px;
  box-shadow: 0 0 0 1px currentColor;
}

/* Sélection : anneau doux + ombre portée renforcée */
.card.selected,
.card.quran.selected, .card.ululazm.selected, .card.muhammad.selected {
  box-shadow: var(--cartouche),
              0 0 0 3px color-mix(in srgb, var(--c-ululazm) 45%, transparent),
              0 8px 24px rgba(0, 0, 0, 0.28);
}

/* Bouton d'information « i » (au survol) */
.info-btn {
  position: absolute;
  bottom: 6px;
  right: 8px;
  width: 22px; height: 22px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--info-bg);
  color: var(--info-fg);
  /* Le « i » est un DESSIN de lettre, non un mot : il prend l'italique de
     l'écriture du site, qui est maintenant embarquée — Georgia, écrite ici en
     dur, n'existe pas sur toutes les machines. Le bouton est en position
     absolue : sa lettre ne peut pas changer la largeur d'une case. */
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: 13px;
  line-height: 22px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease;
}
/*
 * Le « i » se montre AU SURVOL — et il n'y a de survol que là où il y a un
 * pointeur. Sur un écran tactile, le navigateur simule un survol qui reste
 * collé après le doigt : le bouton restait alors affiché en permanence sur la
 * carte qu'on venait de toucher. On le réserve donc aux pointeurs, et sur
 * tactile on le donne à la carte SÉLECTIONNÉE, où il a un sens : c'est le
 * moyen sûr de rouvrir la fiche.
 */
@media (hover: hover) {
  .card:hover .info-btn { opacity: 1; }
}
/* La carte SÉLECTIONNÉE garde son « i » : c'est par lui qu'on rouvre la fiche
   après l'avoir fermée, et sur tactile c'est le seul moyen de l'ouvrir. */
.card.selected .info-btn { opacity: 1; }

/*
 * LA PASTILLE DU VERSET — À CHEVAL SUR LE COIN, et elle porte sa référence.
 *
 * Elle ne paraît que sous le filtre des évoqués dans le Qurʾān, et elle écrit
 * la sourate et le verset : « 19:56 ». Une rosette disait qu'il y a un verset ;
 * deux nombres disent LEQUEL, et se retiennent.
 *
 * À CHEVAL SUR LE COIN BAS GAUCHE, comme le « + » l'est sur le bord bas : elle
 * mord sur la case au lieu de se ranger dessous. Elle ne coûte toujours pas un
 * pixel de largeur mesurée — donc pas une carte ne se déplace —, et elle ne
 * rencontre rien : le bouton « i » tient le coin haut droit, le « + » le
 * milieu du bord bas.
 *
 * CE QUI BORNE SON DÉBORDEMENT, C'EST LE `foreignObject`, qui DÉCOUPE ce qui
 * sort de lui. Il ne laisse que `FO_PAD` — seize pixels — à gauche de la carte
 * et vingt-six dessous. Le débordement latéral est donc calé sur ces seize
 * pixels : au-delà, la pastille serait rognée net, sans que rien dans la
 * feuille ne le dise.
 */
.verse-btn {
  position: absolute;
  inset-inline-start: -16px;
  top: 100%;
  transform: translateY(-50%);
  padding: 2px 9px;
  display: inline-flex; align-items: center;
  border-radius: 999px;
  background: var(--bg-raised);
  border: 1px solid var(--c-ululazm);
  color: var(--gold-ink);
  font-family: var(--font-carte);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  direction: ltr;
  white-space: nowrap;
  cursor: help;
  box-shadow: 0 1px 3px rgba(0,0,0,0.20);
  z-index: 3;
}
.verse-btn:hover { background: var(--c-ululazm); color: var(--bg-raised); }
.verse-btn:focus-visible { outline: 2px solid var(--c-select); outline-offset: 2px; }

/* Bouton +/− (carré arrondi, à cheval sur le bord bas) */
.toggle-btn {
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translate(-50%, 50%);
  width: 22px; height: 22px;
  border: none;
  border-radius: 4px;
  z-index: 2;
  background: var(--toggle-bg);
  color: var(--toggle-fg);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.20);
  transition: filter 0.15s ease;
}
.toggle-btn:hover { filter: brightness(1.12); }
/* Zone cliquable élargie sans changer l'aspect du bouton */
.toggle-btn::after, .up-btn::after { content: ""; position: absolute; inset: -7px; }

/*
 * Bouton de CÔTÉ — l'exception d'Adam et de Ḥawwāʾ. Sur le bord droit, à
 * cheval, et non en bas : ce qu'il déplie n'est pas une descendance mais une
 * épouse, posée à côté. C'est le seul de son espèce dans tout l'arbre.
 */
.side-btn {
  position: absolute;
  top: 50%;
  inset-inline-end: 0;
  transform: translate(50%, -50%);
  width: 22px; height: 22px;
  border: none;
  border-radius: 4px;
  background: var(--toggle-bg);
  color: var(--toggle-fg);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.20);
  z-index: 2;
  transition: filter 0.15s ease;
}
.side-btn:hover { filter: brightness(1.12); }
.side-btn::after { content: ""; position: absolute; inset: -7px; }

/* Trait d'alliance : UN filet rose, le même que dans l'arbre restreint et dans
   l'atelier. Il ne se confond ni avec le trait plein du « fils de » ni avec le
   pointillé du « descendant de » — ce n'est pas une descendance, et l'encre le
   dit à elle seule. */
.spouse-link {
  fill: none;
  stroke: var(--alliance);
  stroke-width: 1.4px;
  stroke-linecap: round;
  opacity: 0.9;
}
/* Prise de survol, invisible et large (comme `.link-hit` pour les filiations) */
.spouse-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 16px;
  pointer-events: stroke;
  cursor: help;
}

/* Bouton symétrique en haut : replier / afficher les ancêtres */
.up-btn {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -50%);
  width: 22px; height: 22px;
  border: none;
  border-radius: 4px;
  background: var(--toggle-bg);
  color: var(--toggle-fg);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.20);
  z-index: 2;
  transition: filter 0.15s ease;
}
.up-btn:hover { filter: brightness(1.12); }

/* ============================================================
   PANNEAU LATÉRAL (drawer)
   ============================================================ */
#detail-panel {
  /* LA GÉOMÉTRIE DU RUBAN DU SIGNET, et le rembourrage du volet : deux règles
     s'en servent — le ruban lui-même, et l'en-tête à qui l'on réserve sa
     colonne. Écrites deux fois, elles finiraient par diverger. */
  --ruban-w: 22px;
  --ruban-x: 3.2rem;
  --ruban-place: calc(var(--ruban-x) + var(--ruban-w) + 0.35rem);
  --volet-pt: 1.5rem;
  --volet-px: 1.5rem;
  --volet-pb: 1.6rem;
  position: fixed;
  top: var(--banner-h, 64px);
  right: 0;
  height: calc(100vh - var(--banner-h, 64px));
  width: var(--panel-w);
  background: var(--panel);
  border-left: 1px solid var(--line);
  padding: var(--volet-pt) var(--volet-px) var(--volet-pb);
  overflow-y: auto;
  z-index: 18;
  transform: translateX(100%);
  visibility: hidden;
  box-shadow: none;
  /* la visibilité ne bascule qu'une fois le glissement terminé */
  transition: transform 0.30s ease, visibility 0s linear 0.30s, box-shadow 0.30s ease;
}

#detail-panel.open {
  transform: translateX(0);
  visibility: visible;
  box-shadow: -14px 0 36px rgba(0, 0, 0, 0.28);
  transition: transform 0.30s ease, visibility 0s linear 0s, box-shadow 0.30s ease;
}

#close-panel-btn {
  position: absolute;
  top: 1rem;
  right: 1.1rem;
  background: none;
  border: none;
  color: var(--text-faint);
  font-size: var(--fs-5);
  cursor: pointer;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
}
#close-panel-btn:hover { color: var(--text); }


/* En-tête de fiche : français à GAUCHE, arabe à DROITE (passe dessous si étroit) */
/* La croix de fermeture est en position absolue dans le coin : l'en-tête doit
   lui réserver sa place, sinon le nom arabe (aligné à droite) passe dessous. */
/*
 * L'EN-TÊTE DÉGAGE LA COLONNE DU RUBAN (choix de l'utilisateur).
 *
 * Le nom ARABE se range au bout de la ligne du titre, et le ruban du signet
 * pend sur ce coin-là : mesuré, il mordait de treize pixels sur « هارون ». Le
 * retrait ne dégageait que la croix (2,2 rem) ; il vaut maintenant ce que le
 * ruban occupe vraiment, et la croix reste son plancher.
 *
 * C'est l'EN-TÊTE seul, et c'est le choix de l'utilisateur : le volet défile,
 * et ce qui passe sous le ruban en défilant n'est pas dégagé.
 */
.panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.15rem 0.8rem;
  margin-bottom: 0.2rem;
  padding-right: max(2.2rem, calc(var(--ruban-place) - var(--volet-px)));
}
/* Honorifique « ʿalayhi as-salām » écrit en toutes lettres, en petit */
/* Ligature honorifique — un seul caractère, après le nom, quel que soit le
   système d'écriture (elle suit donc aussi les noms latins). */
.ah {
  font-family: "Honorifics", var(--font-arabic);
  font-size: 1.15em;
  line-height: 1;
  color: var(--c-arabic);
  opacity: 0.92;
  white-space: nowrap;
  margin-inline-start: 0.15em;
}
#panel-name {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-6);
}
#panel-name.as-arabic { font-family: var(--font-arabic); direction: rtl; font-size: 1.78rem; }

.arabic {
  margin: 0;
  color: var(--text);
  font-family: var(--font-arabic);
  direction: rtl;
  text-align: right;
  font-size: 1.62rem;
  line-height: 1.3;
}

/* Le nom arabe est un élément flex : `text-align` ne suffit pas, il ne fait
   que la largeur de son texte. `margin-left: auto` le colle au bord droit de sa
   ligne — y compris quand il passe seul à la ligne suivante, cas où
   `justify-content: space-between` le ramènerait à gauche. */
/* L'interligne propre à l'écriture arabe (voir `.kicker`). */
#panel-arabic { margin-left: auto; line-height: 1.75; }

/* Naissance et mort tiennent sur une ligne, et cette ligne peut se replier
   dans un volet étroit : les deux pastilles se rangent donc côte à côte, et le
   tiret qui les sépare reste avec elles. */
.panel-date {
  margin: 0.5rem 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}
/* Le tiret n'est pas une pastille : il ne porte ni fond ni source, il ne fait
   que joindre les deux années — d'où l'encre atténuée. */
.date-tiret { color: var(--text-faint); }
.date-chip {
  display: inline-block;
  font-size: var(--fs-1);
  font-variant-numeric: tabular-nums;
  padding: 0.2rem 0.65rem;
  border-radius: var(--r-xs);
  background: color-mix(in srgb, var(--c-desc-link) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--c-desc-link) 45%, transparent);
  color: var(--text);
}

.kin { margin-bottom: 0.85rem; }
/*
 * LA RUBRIQUE DANS LA MARGE. Le copiste n'encadre pas un titre : il le pose
 * dans la marge et le marque d'un trait à l'encre rouge. Les intitulés de la
 * fiche reçoivent donc un court filet à l'endroit exact où le scribe l'aurait
 * tiré — le même dispositif que les titres des pages de texte, une seule idée
 * répétée plutôt que deux décors différents.
 *
 * La hauteur de ligne est IMPOSÉE, et le filet centré sur sa moitié : laissée
 * à l'héritage, elle valait celle des paragraphes, et le filet — calculé en
 * `em` sur le corps du titre — se posait deux tiers de ligne trop haut, comme
 * un tiret égaré au-dessus du mot.
 *
 * `inset-inline-start` : en arabe le filet passe de lui-même dans la marge de
 * droite.
 */
.kin-label {
  display: block;
  position: relative;
  padding-inline-start: 0.95rem;
  font-size: var(--fs-00);
  letter-spacing: 0.1em;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 0.35rem;
}
/* Cases de parenté cliquables : deux colonnes dès qu'il y a plusieurs noms */
.kin-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem; }
.kin-cards.single { grid-template-columns: 1fr; }
/* Noms centrés au milieu de la case */
.kin-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  background: var(--card-bg);
  color: var(--text);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/*
 * Le registre à filets — la fiche sans ses boîtes — a été essayé et ÉCARTÉ :
 * les boîtes à fond plein rappellent les cases de l'arbre, et cette parenté de
 * forme entre la fiche et le dessin vaut mieux que l'élégance du registre. Ne
 * subsiste de l'essai que ce qu'il avait de bon : le liseré doré tiré dans la
 * marge au survol, comme on coche l'entrée que l'on va suivre.
 *
 * `box-shadow` porte À LA FOIS le liseré et l'ombre de relief — c'est une
 * seule propriété, elle doit donc les énoncer d'un coup, sans quoi la seconde
 * déclaration effacerait la première.
 */
.kin-card:hover {
  border-color: var(--c-ululazm);
  box-shadow: inset 2px 0 0 0 var(--c-ululazm), var(--box-shadow);
}
body.rtl .kin-card:hover { box-shadow: inset -2px 0 0 0 var(--c-ululazm), var(--box-shadow); }
.kin-fr { font-family: var(--font-display); font-size: var(--fs-2); line-height: 1.2; text-align: center; }
/* L'interligne propre à l'écriture arabe (voir `.kicker`). */
/* Même correction que dans les cases de l'arbre, et pour la même raison :
   l'encre d'Amiri tombe sous le milieu de sa ligne, et le nom arabe touchait
   le bas de la case. `top` ne change pas la hauteur de la case — la remontée
   est purement visuelle. */
.kin-ar {
  font-family: var(--font-arabic); direction: rtl;
  font-size: 1.16rem; color: var(--c-arabic); line-height: 1.75;
  position: relative; top: -0.28em;
}
/* En une seule colonne : français à GAUCHE, arabe à DROITE dans la case */
.kin-cards.single .kin-card { flex-direction: row; justify-content: space-between; align-items: baseline; gap: 0.55rem; text-align: left; }
/*
 * FRATERNISATION — le frère de Médine. L'encadré se distingue des blocs de
 * parenté par un filet à gauche : ce n'est pas une filiation, c'est une
 * alliance. Quand le frère n'a pas de carte dans l'arbre, la case ne mène
 * nulle part : elle le dit en n'ayant ni curseur ni survol.
 */
.kin-akhi {
  border-inline-start: 3px solid var(--tag-green);
  padding-inline-start: 0.6rem;
}
.kin-card.kin-plain {
  cursor: default;
  border-style: dashed;
  background: transparent;
  color: var(--text-muted);
}
.kin-card.kin-plain:hover { border-color: var(--card-border); box-shadow: none; }
/*
 * DANS LE VOLET, LA PARENTÉ EST UNE LISTE — DES LIGNES, NON DES CASES.
 *
 * Les cases à fond plein rappellent celles de l'arbre, et cette parenté de
 * forme vaut ce qu'elle coûte dans la fiche au large, où la place ne manque
 * pas. Le volet, lui, est une colonne étroite : chaque case y valait deux
 * lignes de rembourrage pour un nom, et la parenté d'une personne un peu
 * entourée repoussait sa notice loin sous le pli. Une ligne dit la même chose,
 * se clique aussi bien, et se parcourt du regard sans sauter d'une colonne à
 * l'autre.
 *
 * LA FICHE FENÊTRÉE GARDE SES CASES : la règle est écrite sous
 * `#detail-panel`, elle ne sort pas du volet.
 */
#detail-panel .kin-cards { display: block; }
#detail-panel .kin-card {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  /* Au DÉBUT de la ligne : une personne dont on n'affiche que le nom arabe
     doit commencer là où commencent les autres, non au milieu. */
  justify-content: flex-start;
  gap: 0.5rem;
  width: 100%;
  /* Le retrait est celui du libellé de rubrique (`.kin-label`) : les noms
     s'alignent sous leur intitulé, et le filet du survol vient se poser dans
     la marge ainsi dégagée. */
  padding: 0.24rem 0.2rem 0.24rem 0.95rem;
  border: none;
  border-radius: 0;
  background: none;
  text-align: start;
}
body.rtl #detail-panel .kin-card { padding: 0.24rem 0.95rem 0.24rem 0.2rem; }
/* UN FILET SOUS CHAQUE LIGNE, y compris la dernière et y compris celle qui est
   seule de son bloc. Il n'était posé qu'ENTRE deux lignes : le père et la mère,
   seuls de leur rubrique, n'en avaient donc aucun, et la colonne se lisait par
   endroits comme un texte suivi. C'est une liste : chaque entrée se clôt. */
#detail-panel .kin-card { border-bottom: 1px solid var(--line); }
/* Y COMPRIS LA DERNIÈRE LIGNE DE LA DERNIÈRE RUBRIQUE. Le filet de la ligne et
   le filet de section qui suit tombaient l'un sous l'autre, à seize pixels :
   une double barre. C'est le filet de SECTION qui cède, non la ligne — sinon
   la dernière personne de la famille se retrouve sous un trait plus pâle et
   plus loin d'elle que toutes les autres, comme si elle n'était plus de la
   liste. La classe est posée par `derniereParente()`, la rubrique visible
   n'étant pas toujours la dernière du document. */
.panel-divider.apres-parente { display: none; }
/*
 * CE QUI DIT QU'UNE LIGNE MÈNE QUELQUE PART : LE GESTE D'UN LIEN DE TEXTE.
 *
 * Un chevron au bout de chaque ligne a été essayé et écarté : dix chevrons
 * alignés dans une colonne étroite font une colonne de chevrons, et l'œil les
 * lit avant les noms. Au repos la ligne reste donc nue — un nom, un filet de
 * séparation, rien d'autre. C'est le SURVOL qui répond : le filet doré dans la
 * marge, le fond qui s'éclaircit, et un fin souligné sous le nom latin, celui
 * qu'on suit du doigt sur une table des matières. Le souligné est posé en
 * `box-shadow` et non en `text-decoration` : il ne coupe donc pas les
 * jambages, et il ne coûte pas un pixel de hauteur.
 */
#detail-panel .kin-card:hover {
  background: var(--bg-raised);
  box-shadow: inset 2px 0 0 0 var(--c-ululazm);
}
body.rtl #detail-panel .kin-card:hover { box-shadow: inset -2px 0 0 0 var(--c-ululazm); }
#detail-panel .kin-card:hover .kin-fr {
  color: var(--c-ululazm);
  box-shadow: inset 0 -1px 0 0 color-mix(in srgb, var(--c-ululazm) 55%, transparent);
}
/* Le frère de fraternisation sans carte ne mène nulle part : il ne s'allume
   pas non plus. */
#detail-panel .kin-card.kin-plain:hover { background: none; box-shadow: none; }
#detail-panel .kin-card.kin-plain:hover .kin-fr { color: inherit; box-shadow: none; }
/* Le nom latin prend la place qui reste, l'arabe se plaque au bord opposé —
   comme dans une case seule de sa colonne, et pour la même raison. */
#detail-panel .kin-fr {
  flex: 1 1 auto; text-align: start; line-height: 1.35;
  /* Le souligné du survol se pose sur cette boîte : elle doit donc s'arrêter
     au nom, non courir jusqu'au bord de la ligne. */
  flex-grow: 0; margin-inline-end: auto;
  transition: color 0.15s ease, box-shadow 0.15s ease;
}
/*
 * L'ARABE SUR UNE LIGNE, ET NON DANS UNE CASE. Son interligne de 1,75 était
 * celui d'une case où le nom respire ; sur une ligne il ajoutait à lui seul
 * dix pixels de hauteur par personne. La remontée de l'encre d'Amiri se règle
 * du même coup : elle se mesure en `em` sur le corps, et le corps a changé.
 */
#detail-panel .kin-ar {
  flex: 0 0 auto; text-align: end; margin-left: auto;
  font-size: 1.05rem; line-height: 1.4; top: -0.14em;
}
body.rtl #detail-panel .kin-ar { margin-left: 0; margin-right: auto; }

.panel-divider {
  height: 1px;
  background: var(--line-soft);
  margin: 1rem 0;
}

#panel-description { font-size: var(--fs-3); line-height: 1.55; }

.note {
  font-size: var(--fs-1);
  color: var(--text-muted);
  font-style: italic;
  margin-top: 0.8rem;
  line-height: 1.45;
}

.source {
  margin-top: 0.9rem;
  font-size: var(--fs-1);
  color: var(--text-faint);
}
.source a {
  color: var(--gold-ink);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--c-ululazm) 45%, transparent);
}
.source a:hover { border-bottom-color: var(--c-ululazm); }

/* La SECONDE famille d'intitulés de la fiche : sans elle, « FILS » porterait
   le filet et « SOURCE » juste au-dessous ne l'aurait pas. */
.panel-more-label {
  display: block;
  position: relative;
  padding-inline-start: 0.95rem;
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--space-1);
  font-weight: 500;
  margin-top: var(--space-3);
}
.kin-label::before, .panel-more-label::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.7em;           /* = la moitié de line-height : centré sur la 1re ligne */
  width: 0.55rem;
  height: 1px;
  background: var(--c-ululazm);
  opacity: 0.75;
}


footer {
  padding: 1.6rem 1.5rem 2.6rem;
  text-align: center;
  color: var(--text-faint);
  font-size: 0.78rem;
  line-height: 1.5;
  max-width: 680px;
  margin: 0 auto;
}


/* Voir « Titre de la bulle verte » : la marge haute doublait le rembourrage
   de l'encadré, l'intitulé ne coiffait plus rien. */
.sm-title {
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--space-1);
  font-weight: 500;
  line-height: 1.3;
  margin-top: 0;
}

.sm-check {
  display: flex;
  align-items: flex-start;
  gap: 0.42rem;
  padding: 0.28rem 0;
  cursor: pointer;
  color: var(--text);
  line-height: 1.3;
  transition-property: color, background-color, border-color, box-shadow, opacity;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
  padding-block: 0.16rem;
}
.sm-check input { margin-top: 2px; cursor: pointer; accent-color: var(--c-ululazm); width: 16px; height: 16px; }
.sm-check input:disabled { cursor: not-allowed; }
.sm-check input:disabled + span { color: var(--text-muted); }


.sm-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 0.35rem;
  vertical-align: middle;
}
.dot-quran { background: var(--src-quran); }
.dot-ibnkathir { background: var(--src-ibnkathir); }
.dot-tabari { background: var(--src-tabari); }
.dot-israiliyyat { background: var(--src-israiliyyat); }
.dot-nassaba { background: var(--src-nassaba); }
.dot-archeo { background: var(--src-archeo); }
.dot-unsourced { background: var(--src-unsourced); }

/* ============================================================
   LIGNE D'ORIGINE (drawer)
   ============================================================ */
.panel-origin-wrap { margin-top: 1.2rem; }
.origin-line { margin: 0.3rem 0 0; }
.origin-chip {
  display: inline-block;
  font-size: var(--fs-0);
  padding: 0.24rem 0.6rem;
  border-radius: var(--r-xs);
  border: 1px solid var(--line);
}
.origin-chip.origin-unsourced { background: color-mix(in srgb, var(--text-faint) 14%, transparent); border-color: var(--text-faint); }
.origin-chip.origin-quran { background: color-mix(in srgb, var(--src-quran) 18%, transparent); border-color: var(--src-quran); }
.origin-chip.origin-ibnkathir { background: color-mix(in srgb, var(--src-ibnkathir) 18%, transparent); border-color: var(--src-ibnkathir); }
.origin-chip.origin-tabari { background: color-mix(in srgb, var(--src-tabari) 18%, transparent); border-color: var(--src-tabari); }
.origin-chip.origin-israiliyyat { background: color-mix(in srgb, var(--src-israiliyyat) 18%, transparent); border-color: var(--src-israiliyyat); }
.origin-chip.origin-nassaba { background: color-mix(in srgb, var(--src-nassaba) 18%, transparent); border-color: var(--src-nassaba); }
.origin-chip.origin-archeo { background: color-mix(in srgb, var(--src-archeo) 18%, transparent); border-color: var(--src-archeo); }

/* ============================================================
   ÉCHELLE TEMPORELLE (gauche)
   ============================================================ */
/* LA LARGEUR DE LA FRISE PORTE UN NOM. Elle était écrite trois fois — ici,
   plus bas, et une troisième dans le bloc étroit — et le bouton Retour, qui
   se range juste après elle, aurait été la quatrième. Une variable, et le
   téléphone la change en un seul endroit. */
#time-axis {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--frise-w);
  z-index: 6;
  /* La frise reçoit les gestes : y glisser fait défiler l'arbre, mais
     VERTICALEMENT seulement — c'est une frise, on la remonte ou on la
     descend. Les repères eux-mêmes restent transparents aux clics. */
  pointer-events: auto;
  cursor: ns-resize;
  touch-action: none;
}
#time-axis > * { pointer-events: none; }
/* Voile dégradé + flou sous la frise, pour rester lisible au-dessus des cartes */
#time-axis::before {
  content: "";
  position: absolute;
  inset: 0;
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  background: linear-gradient(to right,
    color-mix(in srgb, var(--bg) 92%, transparent) 0%,
    color-mix(in srgb, var(--bg) 78%, transparent) 55%,
    transparent 100%);
  mask-image: linear-gradient(to right, #000 0%, #000 55%, transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 0%, #000 55%, transparent 100%);
}
/* Petites barres légères (sous-graduations, non étiquetées) */
.axis-minor {
  position: absolute;
  left: 0;
  transform: translateY(-50%);
  width: 8px;
  height: 0;
  border-top: 1px solid var(--line);
  opacity: 0.4;
}
/* Graduation étiquetée : un trait horizontal (plus long pour les dates rondes)
   suivi de la date. Aucune pastille. */
.axis-tick {
  position: absolute;
  left: 0;
  z-index: 1;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 7px;
}
.axis-line {
  height: 0;
  border-top: 1.5px solid var(--c-desc-link);
  opacity: 0.7;
  flex: none;
}
.tick-s .axis-line { width: 12px; opacity: 0.5; }
.tick-c .axis-line { width: 18px; }
.tick-d .axis-line { width: 24px; }
.tick-m .axis-line { width: 30px; opacity: 0.95; }
.tick-m .axis-era { font-weight: 700; }
.axis-era {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ============================================================
   BOUTON D'AIDE « ? » + POPOVER
   ============================================================ */
#help-btn {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 35;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, #e7c877 55%, var(--line));
  background: color-mix(in srgb, #e7c877 82%, #fff);
  color: #5a4415;
  font-family: var(--font-display);
  font-size: var(--fs-5);
  font-weight: 400;
  cursor: pointer;
  box-shadow: var(--ombre-2);
  transition: transform 0.12s ease, right 0.30s ease;
  line-height: 1;
}
body.panel-open #help-btn { right: calc(min(360px, 88vw) + 1rem); }
body.panel-open #help-popover { right: calc(min(360px, 88vw) + 1rem); }
body.rtl.panel-open #help-btn,
body.rtl.panel-open #help-popover { right: auto; left: calc(min(360px, 88vw) + 1rem); }
#help-btn:hover { transform: translateY(-2px); }

#help-popover {
  position: fixed;
  right: 1rem;
  bottom: 4rem;
  transition: right 0.30s ease;
  z-index: 35;
  width: min(320px, 86vw);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 1rem 1.1rem;
  box-shadow: var(--ombre-3);
  font-size: var(--fs-1);
  line-height: 1.5;
  color: var(--text-muted);
  display: none;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-entree);
}
#help-popover.open { display: block; }
#help-popover h3 { margin: 0 0 0.5rem; font-family: var(--font-display); font-weight: 600; color: var(--text); font-size: var(--fs-4); }
#help-popover p { margin: 0 0 0.5rem; }
#help-popover b { color: var(--text); }
.hp-note { font-size: var(--fs-0); font-style: italic; color: var(--text-faint); border-top: 1px solid var(--line-soft); padding-top: 0.5rem; }

/* ============================================================
   VUE À PROPOS
   ============================================================ */
.about {
  max-width: 720px;
  margin: 0 auto;
  padding: 2.4rem 1.5rem 3rem;
}
.about h1 { font-family: var(--font-display); font-weight: 500; font-size: var(--fs-7); margin: 0 0 1rem; }
/* La rubrique dans la marge — même dispositif que les intitulés de la fiche
   (voir `.kin-label`), avec la même hauteur de ligne imposée. */
.about h2 {
  position: relative;
  padding-inline-start: 1.15rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-5);
  line-height: 1.3;
  letter-spacing: 0.005em;
  /* La ligne resserrée rapprochait le titre de son paragraphe : on rend au
     blanc inférieur ce que la hauteur de ligne lui a pris. */
  margin: 1.8rem 0 0.8rem;
  color: var(--gold-ink);
}
.about h2::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.65em;          /* = la moitié de line-height : centré sur la 1re ligne */
  width: 0.72rem;
  height: 2px;
  background: var(--gold-ink);
}
.about p { line-height: 1.65; color: var(--text-muted); margin: 0 0 0.8rem; }
/* L'interligne propre à l'écriture arabe (voir `.kicker`). */
.about :lang(ar) { line-height: 1.9; }
.about ul { line-height: 1.65; color: var(--text-muted); padding-left: 1.2rem; }
.about li { margin-bottom: 0.4rem; }
.about b { color: var(--text); }
/* Le filet se pose du côté où le texte COMMENCE : écrit en bordure gauche, il
   restait à gauche en arabe, à plusieurs centaines de pixels du paragraphe
   qu'il est censé accompagner. */
.about-warn { font-size: var(--fs-2); font-style: italic; color: var(--text-faint); border-inline-start: 3px solid var(--line); padding-inline-start: 0.9rem; }

/* LA PAGE CONTACT. Les champs reprennent le liseré des champs de recherche du
   site, pour qu'on les reconnaisse comme des endroits où écrire. */
.contact-form { display: flex; flex-direction: column; gap: 1rem; margin-top: 1.5rem; }
.contact-champ { display: flex; flex-direction: column; gap: 0.35rem; font-size: var(--fs-1); color: var(--text-muted); }
.contact-champ input,
.contact-champ textarea {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--text) 7%, var(--bg));
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
}
.contact-champ textarea { resize: vertical; min-height: 9rem; line-height: 1.5; }
.contact-champ input:focus,
.contact-champ textarea:focus { outline: none; border-color: var(--c-ululazm); }
.contact-champ input:focus-visible,
.contact-champ textarea:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 0; }
.contact-form .cta { align-self: flex-start; }
.contact-form .cta:disabled { opacity: 0.55; cursor: wait; }
/* Le piège à robots : réduit à rien sur place, et non `display: none`, que
   certains programmes savent reconnaître pour sauter le champ. PAS de
   `left: -10000px` : en arabe la page défile vers la gauche, et ces dix mille
   pixels devenaient une page de dix mille pixels de large. */
.contact-piege { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; overflow: hidden; clip-path: inset(50%); pointer-events: none; }
.contact-etat { margin: 0; font-size: var(--fs-1); color: var(--text-muted); }
.contact-etat[hidden] { display: none; }
.contact-etat.contact-ok { color: var(--c-ululazm); }
.contact-etat.contact-ko { color: var(--c-mrca); font-style: italic; }

/* ============================================================
   VUE CONCEPTS — le sommaire des articles, et le retour
   ============================================================ */
/* Une entrée de sommaire est un TITRE qu'on clique, pas un bouton : elle prend
   la largeur de la ligne et se lit dans la même police que les titres de la
   page, sans fond ni cadre qui en ferait une commande parmi d'autres. Le filet
   entre deux entrées est celui des sections de la fiche. */
.concept-arts { list-style: none; margin: 1.4rem 0 0; padding: 0; }
.concept-arts li { margin: 0; border-top: 1px solid var(--line-soft); }
.concept-arts li:last-child { border-bottom: 1px solid var(--line-soft); }
.concept-art {
  display: block;
  width: 100%;
  padding: 0.95rem 0;
  border: 0;
  background: none;
  text-align: inherit;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-4);
  line-height: 1.35;
  color: var(--text);
  cursor: pointer;
  transition-property: color;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.concept-art:hover { color: var(--gold-ink); }
.concept-art:lang(ar) { line-height: 1.9; }
/* Le retour se pose AU-DESSUS du titre de l'article : c'est le premier point
   d'appui de la page, et le lecteur qui entre par erreur en ressort sans
   parcourir le texte. */
.concept-back {
  display: inline-block;
  margin: 0 0 1.2rem;
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--fs-2);
  color: var(--text-muted);
  cursor: pointer;
  transition-property: color;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.concept-back:hover { color: var(--gold-ink); }

/* ============================================================
   INFO-BULLE DES TAGS
   ============================================================ */
#tag-tip {
  position: fixed;
  z-index: 60;
  /* JAMAIS PLUS GRAND QUE L'ÉCRAN. `placeTip` sait recaler l'encadré dans la
     fenêtre, mais il ne peut rien pour celui qui est plus grand qu'elle : la
     citation d'Ibn Kathīr sur l'âge de Nūḥ fait plus de mille pixels de haut,
     soit davantage que n'importe quel écran, et l'encadré débordait par le bas
     quoi qu'on fasse. On le borne donc AUX DEUX AXES, et ce qui ne tient pas
     se fait défiler — le texte entier reste lisible dans la fiche. */
  max-width: min(260px, calc(100vw - 16px));
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.6rem 0.75rem;
  border-radius: var(--r-md);
  /* encadré et texte à la couleur du tag (var --tip-c posée en JS) */
  border: 1.5px solid var(--tip-c, var(--line));
  background: color-mix(in srgb, var(--tip-c, var(--panel)) 12%, var(--panel));
  color: var(--tip-c, var(--text));
  box-shadow: var(--ombre-3);
  font-size: var(--fs-1);
  line-height: 1.45;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.14s ease;
  pointer-events: none;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-entree);
}
#tag-tip.show { opacity: 1; visibility: visible; pointer-events: auto; }
#tag-tip .tip-text { margin-bottom: 0.45rem; }
#tag-tip .tip-extra {
  margin-bottom: 0.45rem;
  color: var(--text-muted);
  font-size: var(--fs-0);
  line-height: 1.4;
}
/* L'OPÉRATION, écrite pour être refaite au crayon : un pavé à part, chiffres
   alignés, pour qu'on la distingue de la phrase qui explique la méthode. */
#tag-tip .tip-calc {
  margin-bottom: 0.5rem;
  padding: 0.35rem 0.5rem;
  border-inline-start: 2px solid var(--line-soft);
  background: var(--card-bg);
  border-radius: 3px;
  font-size: var(--fs-0);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  /* Une opération se lit toujours de gauche à droite, même en arabe. */
  direction: ltr;
  text-align: start;
}
/* Ligne de catégorie : mise en page en ligne (le flex séparait « Catégorie »,
   « : » et la valeur en éléments distincts, qui se renvoyaient à la ligne). */
#tag-tip .tip-src {
  padding-top: 0.4rem;
  border-top: 1px solid var(--line-soft);
  color: var(--text);
  font-size: var(--fs-0);
  line-height: 1.5;
}
#tag-tip .tip-src .sm-dot { margin-right: 0.35rem; }
#tag-tip .tip-src b { font-weight: 700; }
/* La source elle-même : la citation (verset) et sa référence */
#tag-tip .tip-cite {
  margin: 0.15rem 0 0.5rem;
  padding: 0.45rem 0.55rem;
  border-radius: 5px;
  background: color-mix(in srgb, var(--cite) 10%, transparent);
  border-inline-start: 3px solid color-mix(in srgb, var(--cite) 55%, transparent);
}
/* COULEUR D'UNE CITATION — elle est celle de sa CATÉGORIE, et le vert
   n'appartient qu'au Qurʾān et à la Sunna. Une citation biblique ne doit pas
   emprunter la couleur du texte révélé : la couleur dit d'où vient la parole,
   avant même qu'on lise la référence. Les teintes sont celles déjà employées
   par les pastilles des filtres, pour qu'un lecteur les reconnaisse. */
.tip-cite { --cite: var(--c-quran); }
.tip-cite.cite-israiliyyat { --cite: var(--src-israiliyyat); }
.tip-cite.cite-ibnkathir   { --cite: var(--src-ibnkathir); }
.tip-cite.cite-tabari      { --cite: var(--src-tabari); }
.tip-cite.cite-nassaba     { --cite: var(--src-nassaba); }
.tip-cite.cite-archeo      { --cite: var(--src-archeo); }
.tip-cite.cite-unsourced   { --cite: var(--text-faint); }
/*
 * SA MENTION, EN GRAS DANS SON VERSET.
 *
 * L'arabe du Qurʾān n'a qu'une graisse : le navigateur l'épaissit lui-même, et
 * le trait s'empâte plutôt qu'il ne s'affirme. La COULEUR de la citation —
 * celle qui borde déjà l'encadré, donc le vert du Qurʾān — porte alors ce que
 * la graisse ne porte pas. La traduction, elle, a une vraie grasse
 * (`TranslitSerif-Bold`) et n'a besoin de rien d'autre.
 */
.tip-verse b { font-weight: 700; color: var(--cite); }
.tip-trad b { font-weight: 700; }
/* Une citation en écriture LATINE (la Bible, pour les Isrāʾīliyyāt) garde la
   police de lecture et le sens gauche → droite. */
.tip-verse.latin {
  font-family: var(--font-body) !important;
  direction: ltr !important;
  text-align: left !important;
  font-size: 0.92rem !important;
  line-height: 1.6 !important;
  font-style: italic;
}
body.rtl .tip-verse.latin { text-align: right !important; }
#tag-tip .tip-verse {
  font-family: var(--font-arabic);
  direction: rtl;
  text-align: right;
  font-size: 1.15rem;
  line-height: 1.7;
  color: var(--text);
}
#tag-tip .tip-ref {
  margin-top: 0.25rem;
  font-size: var(--fs-0);
  font-style: italic;
  color: var(--text-muted);
}
/* Traduction du verset (français / anglais), sous le texte arabe */
#tag-tip .tip-trad, .concept-block .tip-trad {
  margin-top: 0.35rem;
  font-size: var(--fs-1);
  font-style: italic;
  line-height: 1.5;
  color: var(--text);
}
/* Référence seule (info-bulle d'un tag : pas de citation entière) */
#tag-tip .tip-ref-solo { margin: 0.3rem 0 0.1rem; }

/* La citation reprise sur la page « Tags » */
.concept-block .tip-cite {
  margin: 0.6rem 0 0.9rem;
  padding: 0.6rem 0.75rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--cite) 9%, transparent);
  border-inline-start: 3px solid color-mix(in srgb, var(--cite) 55%, transparent);
}
.concept-block .tip-verse {
  font-family: var(--font-arabic);
  direction: rtl;
  text-align: right;
  font-size: 1.25rem;
  line-height: 1.9;
  color: var(--text);
}
.concept-block .tip-ref {
  margin-top: 0.3rem;
  font-size: var(--fs-0);
  font-style: italic;
  color: var(--text-muted);
}

/* Zone de survol des liens (invisible, plus épaisse que le trait) */
.link-hit { fill: none; stroke: transparent; stroke-width: 14px; pointer-events: stroke; cursor: help; }

/* Paragraphes d'information sourcés */
.info-block { display: block; margin-bottom: 0.9rem; }
.info-block:last-child { margin-bottom: 0; }
/* RÉFÉRENCE ÉCRITE SOUS LE PARAGRAPHE. Elle se lit sans être lourde : plus
   petite, en retrait de ton, et colorée par sa catégorie — le vert n'y
   revient qu'au Qurʾān et à la Sunna. Le survol ou le clic ouvre la citation. */
.para-srcs {
  display: block;
  margin-top: 0.28rem;
  font-size: var(--fs-0);
  line-height: 1.45;
  cursor: help;
}
.para-ref {
  --cite: var(--text-faint);
  color: color-mix(in srgb, var(--cite) 78%, var(--text-muted));
  border-bottom: 1px dotted color-mix(in srgb, var(--cite) 55%, transparent);
  font-style: italic;
}
.para-srcs:hover .para-ref, .para-srcs:focus-visible .para-ref { color: var(--cite); }
.para-srcs:focus-visible { outline: 2px solid var(--c-select); outline-offset: 2px; border-radius: 3px; }
.para-sep { color: var(--text-faint); margin: 0 0.35rem; }
/* Les mêmes teintes que les blocs de citation (voir `.tip-cite.cite-…`). */
.para-ref.cite-quran       { --cite: var(--src-quran); }
.para-ref.cite-israiliyyat { --cite: var(--src-israiliyyat); }
.para-ref.cite-ibnkathir   { --cite: var(--src-ibnkathir); }
.para-ref.cite-tabari      { --cite: var(--src-tabari); }
.para-ref.cite-nassaba     { --cite: var(--src-nassaba); }
.para-ref.cite-archeo      { --cite: var(--src-archeo); }
.date-chip.muted { color: var(--text-faint); font-style: italic; }
/* Date seulement encadrée : « Inconnue », en italique — ce n'est pas un chiffre */
.date-chip.unknown { font-style: italic; letter-spacing: 0.01em; }
#tag-tip .tip-more {
  display: inline-block;
  color: var(--tip-c, var(--c-ululazm));
  font-weight: 700;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}

.concept-block {
  padding: 1.1rem 0 1.3rem;
  border-top: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  /* Arrivé par `/tags#cle`, le tag se pose SOUS la barre « Retour à
     l'arbre », qui suit le défilement : sans cette marge, elle en couvrait
     le nom. */
  scroll-margin-top: 3.5rem;
}
/*
 * PAS DE RUBRIQUE EN MARGE SUR LE DÉTAIL DES TAGS. Ici le titre n'est pas un
 * intitulé de section : c'est le TAG lui-même, dans sa pastille et sa couleur.
 * Il porte déjà sa marque — lui en ajouter une seconde donnait un tiret qui
 * semblait traîner devant le nom. La page est bâtie sur `.about`, elle
 * héritait donc du filet sans l'avoir demandé.
 */
.concept-block h2 { margin: 0 0 0.6rem; padding-inline-start: 0; }
.concept-block h2::before { content: none; }
.concept-block h2 .tag { font-size: 0.82rem; padding: 5px 10px; }
/* Le nom d'un tag est un lien vers sa propre adresse : il garde l'allure de
   sa pastille, sans le soulignement d'un lien. */
.tag-ancre { text-decoration: none; }
.tag-ancre:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 2px; border-radius: var(--r-sm); }
.concept-block .tag:lang(ar) { line-height: 1.9; }
.concept-block p { margin: 0 0 0.8rem; line-height: 1.6; color: var(--text-muted); }
.concept-block details { font-size: var(--fs-2); }
.concept-block summary {
  cursor: pointer;
  color: var(--text);
  font-weight: 600;
  padding: 0.3rem 0;
  user-select: none;
}
.concept-people {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
}
.concept-person {
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--card-border);
  border-radius: 4px;
  background: var(--card-bg);
  color: var(--text);
  font-family: var(--font-display);
  font-size: var(--fs-1);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, opacity;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.concept-person:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
/* CELUI QU'ON CHERCHAIT. La barre du détail des tags accepte un NOM ; les
   sections qu'il traverse s'ouvrent, et il faut le retrouver d'un coup d'œil
   au milieu de six cents autres. */
.concept-person.trouve {
  border-color: var(--c-ululazm);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--c-ululazm) 35%, transparent);
  font-weight: 700;
}
/*
 * SA BARRE, QUI SUIT LE DÉFILEMENT.
 *
 * On arrive sur cette page depuis une carte de l'arbre, et la vue se pose sur
 * le tag cherché — qui peut être à quinze écrans du haut. Le bouton du retour,
 * posé tout en haut, était alors hors de vue à l'instant même où l'on veut
 * revenir. Il reste donc collé au bord supérieur de la zone qui défile.
 *
 * TROIS CHOSES LA RENDENT SÛRE. Elle DÉBORDE des marges de la colonne
 * (`margin-inline` négatif, rendu en rembourrage) : un bouton collant large
 * de cent pixels aurait laissé le texte défiler à côté de lui. Elle porte le
 * fond de la page, sans quoi on lirait deux textes l'un sur l'autre. Et elle
 * remonte dans le rembourrage haut de `.about`, pour ne pas ouvrir un blanc
 * de plus au-dessus du titre.
 */
.page-back-bar {
  position: sticky;
  top: 0;
  z-index: 3;
  margin: -2.4rem -1.5rem 0.9rem;
  padding: 1.5rem 1.5rem 0.5rem;
  background: var(--bg);
}
/* Le blanc sous le bouton est celui de la BARRE : le sien ferait double. */
.page-back-bar .page-back { margin-bottom: 0; }
/*
 * ═══════════════════════════════════════════════════════════════════════════
 * LE SIGNET, ET SON RUBAN.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Creux, c'est un CONTOUR de signet, de la taille d'un bouton d'icône, posé
 * dans le coin haut de la fiche à côté de la croix.
 *
 * POSÉ, c'est UN VRAI RUBAN (choix de l'utilisateur) : il part du bord HAUT de
 * la fenêtre et descend PAR-DESSUS ce qui s'y trouve, la pointe échancrée en
 * V, comme le ruban d'un livre qu'on a laissé dépasser. Ce n'est plus un
 * bouton qui a changé de couleur, c'est un objet qui n'était pas là.
 *
 * IL DESCEND DEPUIS LE BORD, ET NON AU-DELÀ. Le volet est `overflow-y: auto`,
 * la fenêtre `overflow: hidden` : tout ce qui dépasserait vers le haut serait
 * coupé net, et le ruban paraîtrait tranché. Il commence donc à zéro — le haut
 * exact de la boîte — et va chercher sa longueur vers le BAS, où rien ne le
 * borne.
 *
 * DANS LA FICHE AU LARGE, IL PEND DU COIN OPPOSÉ À LA CROIX (choix de
 * l'utilisateur). Il partageait le coin droit avec elle, et il y tombait sur
 * le NOM ARABE, qui se range au bout de sa ligne : mesuré, il mordait sur
 * « محمد ». Le coin de l'ouverture est libre, et la gouttière de la fiche lui
 * garde sa colonne (voir `--fiche-px`), si bien que rien ne peut plus passer
 * dessous — pas même en défilant.
 */
.fav-btn {
  position: absolute;
  top: 0.55rem;
  /* Le retrait est celui que son HÔTE déclare : le volet le garde dans le coin
     de la croix, la fiche au large le met dans celui de l'ouverture. Écrit
     ici, il faudrait le réécrire là où on lui réserve sa colonne. */
  inset-inline-end: var(--ruban-x, 3.2rem);
  z-index: 3;
  width: var(--ruban-w, 22px);
  height: 30px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text-faint);
  cursor: pointer;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  transition: color var(--dur-teinte) var(--ease-vif);
}
.fav-btn:hover { color: var(--gold-ink); }
.fav-btn .fav-creux {
  width: 20px; height: 26px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
}
.fav-btn .fav-ruban { display: none; }
/* POSÉ. Le bouton n'occupe plus de hauteur — il est collé au bord — et le
   ruban, lui, pend en absolu par-dessus la fiche. */
.fav-btn.pose {
  top: 0;
  height: 0;
  color: var(--c-ululazm);
}
.fav-btn.pose .fav-creux { display: none; }
.fav-btn.pose .fav-ruban {
  display: block;
  position: absolute;
  top: 0;
  inset-inline-end: 0;
  width: var(--ruban-w, 22px);
  height: 58px;
  fill: currentColor;
  stroke: none;
  /* L'ombre le décolle de la page : sans elle il se lit comme une forme
     peinte dessus, non comme un ruban posé devant. */
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.35));
}
.fav-btn.pose:hover { color: color-mix(in srgb, var(--c-ululazm) 80%, #fff); }
.fav-btn:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 3px; border-radius: 3px; }
/* DANS LA FICHE AU LARGE, LE SIGNET CHANGE DE COIN : il quitte celui de la
   croix, où il tombait sur le nom arabe, pour celui de l'ouverture, qui est
   libre. Le ruban garde tout le reste — même dessin, même encre, même chute
   depuis le bord haut. */
#fiche-fav { inset-inline-start: var(--ruban-x); inset-inline-end: auto; }

/* LE SIGNET DU BANDEAU. Creux tant que rien n'est mis de côté, PLEIN dès qu'il
   y a quelque chose : c'est le seul endroit du site qui l'annonce. */
.banner-ico .ico-signet { stroke-width: 1.7; }
#fav-page-btn.plein .ico-signet { fill: currentColor; }
#fav-page-btn.plein { color: var(--gold-ink); }
#fav-page-btn.actif { border-color: var(--c-ululazm); color: var(--gold-ink); }

/* LA PAGE DES FAVORIS — une ligne par personne, son nom et la croix qui la
   retire. Le nom est un `.concept-person`, comme partout ailleurs : le même
   écouteur le ramène à sa carte. */
.fav-liste { display: flex; flex-direction: column; gap: 0.35rem; margin-top: 1.2rem; }
.fav-ligne { display: flex; align-items: center; gap: 0.5rem; }
.fav-ligne .concept-person { flex: 1; text-align: start; }
.fav-off {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border: none;
  border-radius: 999px;
  background: none;
  color: var(--text-faint);
  font-size: var(--fs-4);
  line-height: 1;
  cursor: pointer;
  transition: color var(--dur-teinte) var(--ease-vif);
}
.fav-off:hover { color: var(--c-ululazm); background: var(--bg-raised); }

/* LE RETOUR À L'ARBRE, en tête de la page. Il se lit comme un lien de
   navigation, non comme une action : pas de fond, une flèche, et il se
   souligne au survol. */
.page-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 1rem;
  padding: 0.3rem 0;
  border: 0;
  background: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
  transition: color var(--dur-teinte) var(--ease-vif);
}
.page-back:hover { color: var(--c-ululazm); text-decoration: underline; }
.page-back:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 2px; border-radius: var(--r-sm); }
/* La flèche pointe vers l'arrière, donc vers la DROITE en écriture arabe. */
body.rtl .page-back span[aria-hidden] { transform: scaleX(-1); }

/* ============================================================
   ONGLET TAGS DÉPLIANT — le bouton du bandeau ouvre deux sous-onglets.
   ============================================================ */
.nav-menu { position: relative; display: inline-block; }
.nav-menu .nav-btn { display: inline-flex; align-items: center; gap: 0.35rem; }
.nav-caret { font-size: 0.7em; opacity: 0.8; transition: transform 0.15s ease; transition-property: transform; transition-duration: var(--dur-teinte); transition-timing-function: var(--ease-entree); }
.nav-menu.open .nav-caret { transform: rotate(180deg); }
/* `fixed` et non `absolute` : sous 700 px, `.banner .nav` défile
   horizontalement (`overflow-x: auto`), et un menu positionné dans ce flux
   était COUPÉ net — sur téléphone, l'onglet se dépliait dans le vide. Posé en
   `fixed`, il échappe à tout rognage ; ses coordonnées viennent du JS. */
.nav-drop {
  position: fixed;
  z-index: 70;
  min-width: 200px;
  padding: 0.25rem;
  border-radius: 6px;
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
  display: none;
}
.nav-menu.open .nav-drop { display: block; }
.nav-drop button {
  display: block;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
  text-align: start;
  cursor: pointer;
}
.nav-drop button:hover { background: var(--bg-raised); }
.nav-drop button.active { color: var(--gold-ink); font-weight: 600; }

/* Sélecteur de catégorie, en tête du détail des tags. Les cinq libellés sont
   longs : le segment passe à la ligne au lieu de sortir de la page. */
/*
 * SÉLECTEUR DE CATÉGORIE — des pastilles franches, et non des onglets.
 * Plus grandes, écartées les unes des autres, et QUASI RONDES quand elles
 * sont retenues : le choix se voit d'un bout à l'autre de la page.
 */
/*
 * LES CINQ TIENNENT SUR UNE LIGNE. Elles passaient à la ligne, et « Autre »
 * se retrouvait seul en dessous — on croyait à une seconde rangée qui aurait
 * un sens. On les resserre plutôt que de faire défiler la rangée : un
 * défilement demanderait un repère de bord, c'est-à-dire un dégradé, et un
 * dégradé sur cinq boutons est un remède pire que le mal.
 */
/* `overflow: hidden` sert au contrôle segmenté à découper ses coins arrondis.
   Ici il n'y a plus ni cadre ni coins à découper, et comme l'encadré se
   réduit exactement à son contenu, il rabotait le bord droit du dernier
   bouton — « Autre » restait ouvert. */
.seg-wrap { flex-wrap: nowrap; gap: 0.4rem; margin-bottom: 0.6rem; border: none;
            background: none; overflow: visible; }
/* La forme ne change PAS au choix : une pastille reste une pastille, et
   seule la couleur dit laquelle est retenue. Voir un bouton changer de
   silhouette sous le curseur déroute plus que cela n'informe. */
.seg-wrap button {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.5rem 1rem;
  font-size: var(--fs-1);
  white-space: nowrap;
  /* Elles se partagent la largeur disponible sans jamais passer à la ligne :
     `min-width: 0` autorise le libellé le plus long à se resserrer avant que
     la rangée ne déborde. */
  flex: 0 1 auto;
  min-width: 0;
  /* PAS DE `transition` ICI. L'élément porte `class="seg seg-wrap"` : il est
     déjà servi par `.seg button`, plus haut, qui pose les trois longhands
     communs à tous les boutons. Un raccourci écrit ici arriverait après et les
     écraserait. */
}
/*
 * LA DERNIÈRE PASTILLE A UN BORD DROIT, elle aussi.
 *
 * `.seg` est à l'origine un contrôle SEGMENTÉ : ses boutons se touchent et
 * partagent leurs bords, si bien que le dernier n'a pas de bord droit — il
 * s'appuie sur celui de l'encadré. Ici les boutons sont détachés et l'encadré
 * a disparu : « Autre » restait donc ouvert sur sa droite.
 */
.seg-wrap button:last-child { border-right: 1px solid var(--line); }
#tag-cats { margin: 0.6rem 0 0.9rem; }
/* Le trait de séparation qui suivait n'apportait rien : les pastilles se
   distinguent déjà de la liste. */
/* Le premier bloc de la liste ne prend PAS de trait de séparation : le
   sélecteur de catégorie s'en distingue déjà, et la barre juste dessous
   coupait la page en deux sans rien séparer. */
#tags-list > .concept-block:first-child { border-top: none; padding-top: 0.2rem; }

/* ============================================================
   CROISEMENT DE TAGS
   ============================================================ */
.cross-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin: 1rem 0 0.5rem;
}
.cross-head .tool-btn { width: auto; padding: 0.35rem 0.8rem; font-size: var(--fs-1); }
/* LES SOUS-TAGS EN COLONNE SOUS LEUR PÈRE : chaque branche est une colonne,
   et le décalage à gauche dit la profondeur. La hiérarchie se lit sans avoir
   à la connaître. */
/*
 * UNE COLONNE PAR CATÉGORIE, les mêmes quatre que la page « Détail des Tags ».
 * On retrouve d'une page à l'autre le même rangement, et dans chaque colonne
 * les sous-tags se décalent d'un cran sous leur père.
 */
/*
 * DEUX VOLETS : les tags à gauche, ce qu'ils donnent à droite.
 *
 * Le résultat se lisait tout en bas, après cinquante-six tags — donc hors de
 * vue au moment même où l'on compose la formule, ce qui obligeait à faire
 * l'aller-retour à chaque ajout. Il tient maintenant à côté, et il SUIT le
 * défilement : on voit changer le nombre en cliquant.
 *
 * Cette page, seule de l'onglet, est plus large que les autres : elle porte
 * deux colonnes là où les autres n'ont qu'un fil de lecture.
 */
#sub-cross { max-width: 1140px; }
.cross-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 2rem;
  align-items: start;
}
#cross-result { position: sticky; top: 1rem; }
@media (max-width: 1000px) {
  .cross-body { grid-template-columns: minmax(0, 1fr); }
  #cross-result { position: static; }
}
#cross-search { margin-bottom: 0.9rem; max-width: 320px; }

#cross-picker {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 1.4rem 1.8rem;
  align-items: start;
}
/* Une colonne d'écran étroite ne se partage pas : tout s'empile. */
@media (max-width: 900px) {
  #cross-picker { grid-template-columns: minmax(0, 1fr); }
  .cross-col-wide { grid-template-columns: minmax(0, 1fr) !important; }
}
.cross-side { display: flex; flex-direction: column; gap: 1.4rem; min-width: 0; }
.cross-col { display: flex; flex-direction: column; align-items: flex-start; gap: 0.22rem; min-width: 0; }
/*
 * Une catégorie volumineuse range ses racines sur DEUX sous-colonnes : les
 * petites (Fondateur, Syriaque) se placent d'elles-mêmes sur la première
 * rangée, et les deux grandes — Banū Isrāʾīl et Arabe — se retrouvent côte à
 * côte sur la seconde au lieu de se suivre sur une hauteur d'écran et demie.
 */
.cross-col-wide {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.9rem 1.6rem;
  align-items: start;
}
.cross-col-wide > .cross-col-title { grid-column: 1 / -1; }
.cross-col-title {
  margin-bottom: var(--space-1);
  padding-bottom: 0.3rem;
  width: 100%;
  border-bottom: 1px solid var(--line-soft);
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.3;
  margin-top: var(--space-3);
}
.cross-branch {
  --cross-ecart: 0.22rem;
  --cross-patte: 0.52rem;          /* la moitié du cran, là où descend le trait */
  --cross-demi: 10.5px;            /* le milieu d'une pastille sous son haut */
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--cross-ecart); max-width: 100%;
}
/*
 * LES PETITS TRAITS EN L ENTRE UN TAG ET SES SOUS-TAGS.
 *
 * Le décalage seul ne suffisait pas : dans une colonne de cinquante
 * pastilles, deux crans d'indentation ne disent pas de quel père relève
 * laquelle. Le trait le dit — une descente sous le père, un pied vers le
 * fils —, et le dernier fils referme la descente au lieu de la prolonger.
 *
 * LE COUDE VISE LE MILIEU D'UNE PASTILLE, NON CELUI DE LA CASE. Une case
 * contient aussi toute la descendance du fils : visé au milieu de la case,
 * le coude serait tombé cent pixels sous la pastille qu'il désigne. Une
 * pastille fait 21 px de haut — 11 px de texte, 4 px de rembourrage de part
 * et d'autre, un filet de chaque côté —, d'où les 10,5 px.
 *
 * TOUT EST LOGIQUE (`inset-inline-start`, `border-inline-start`) : ces
 * éléments suivent la direction de la page, et l'arbre se retourne de
 * lui-même en arabe.
 */
.cross-kids {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--cross-ecart); max-width: 100%; min-width: 0;
  padding-inline-start: 0.8rem;
}
.cross-node {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start;
  gap: var(--cross-ecart); max-width: 100%; min-width: 0;
}
/* Le L : la descente depuis le père, puis le pied vers la pastille. */
.cross-node::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(-1 * var(--cross-patte));
  top: calc(-1 * var(--cross-ecart));
  width: var(--cross-patte);
  height: calc(var(--cross-ecart) + var(--cross-demi));
  border-inline-start: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  border-end-start-radius: 4px;
  pointer-events: none;
}
/* Tant qu'il reste un frère dessous, la descente continue jusqu'à lui. */
.cross-node:not(:last-child)::after {
  content: "";
  position: absolute;
  inset-inline-start: calc(-1 * var(--cross-patte));
  top: calc(-1 * var(--cross-ecart));
  bottom: 0;
  border-inline-start: 1px solid var(--line-soft);
  pointer-events: none;
}
.cross-tag { max-width: 100%; text-align: start; white-space: normal; }

/* La formule en construction. */
.cross-expr {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem;
  min-height: 2.2rem;
  margin: 0.2rem 0 0.6rem;
  padding: 0.45rem 0.6rem;
  border: 1px dashed var(--line-soft);
  border-radius: 5px;
  background: var(--card-bg);
}
.cross-empty { color: var(--text-muted); font-size: var(--fs-1); }
.xtok { font-size: var(--fs-1); border-radius: var(--r-xs); }
.xop {
  padding: 0.08rem 0.4rem;
  border-radius: 3px;
  background: color-mix(in srgb, var(--c-ululazm) 18%, transparent);
  color: var(--c-ululazm);
  font-weight: 700; letter-spacing: 0.04em;
}
.cross-ops { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.9rem; }
.cross-op {
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--card-bg);
  color: var(--text);
  font-family: var(--font-body); font-size: var(--fs-0); font-weight: 600;
  cursor: pointer;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
  min-height: 26px;
}
.cross-op:hover:not(:disabled) { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.cross-op:disabled { opacity: 0.34; cursor: not-allowed; }
.cross-paren { font-family: var(--font-display); font-size: var(--fs-3); padding-inline: 0.85rem; }
/* FOND EXPLICITE, SANS QUOI LE THÈME NE S'APPLIQUE PAS. Sur une carte, la
 * pastille est un <span> sans fond : elle laisse voir la carte, donc elle suit
 * le thème toute seule. Ici c'est un <button>, et un bouton sans `background`
 * déclaré retombe sur le gris `buttonface` du navigateur — une pastille claire
 * posée sur une page sombre. On lui donne un lavis de sa PROPRE couleur, qui
 * fonce sur fond clair et éclaircit sur fond sombre : la teinte reste celle de
 * la carte et le thème est respecté des deux côtés. */
.cross-tag {
  cursor: pointer;
  border-width: 1px;
  background: color-mix(in srgb, currentColor 8%, transparent);
  font-family: var(--font-body);
  transition: opacity 0.15s ease, box-shadow 0.15s ease;
}
/* Retenu : le tag garde sa couleur et gagne un liseré, pas une autre teinte —
   c'est la MÊME pastille que sur les cartes, et elle doit rester reconnaissable. */
.cross-tag.on { box-shadow: 0 0 0 2px var(--c-ululazm); font-weight: 700; }
/* Sans issue : personne ne le porte en même temps que ceux déjà retenus. */
.cross-tag.dead { opacity: 0.32; cursor: not-allowed; filter: grayscale(1); }
.cross-n { opacity: 0.65; font-size: 0.85em; }

/*
 * SÉLECTEUR DE TAGS DU VOLET — même pastille que partout ailleurs, dans une
 * colonne étroite : la liste défile plutôt que de repousser les filtres hors
 * de vue.
 */
/*
 * LES PRÉFÉRENCES NE SONT PAS UN OUTIL — et cela doit se voir sans crier.
 *
 * Elles portaient DEUX contours : celui de l'encadré `.tool` et celui du
 * bouton posé dedans. Deux filets l'un sur l'autre au sommet du volet, c'est
 * un cadre de brouillon. On les retire tous les deux : reste une bande
 * légèrement teintée, sans bordure, qui se distingue des outils précisément
 * par là — un outil a un contour franc, les préférences n'en ont aucun.
 */
.tool.tool-pref { border: none; background: none; border-radius: 0; overflow: visible; }
.tool.tool-pref > .tool-btn {
  border: none;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--text) 5%, transparent);
  color: var(--text-muted);
  font-weight: 600;
  transition: background 0.15s ease, color 0.15s ease;
}
.tool.tool-pref > .tool-btn:hover {
  background: color-mix(in srgb, var(--c-ululazm) 13%, transparent);
  color: var(--c-ululazm);
}
.tool.tool-pref.open > .tool-btn {
  background: color-mix(in srgb, var(--c-ululazm) 15%, transparent);
  color: var(--gold-ink);
  border-radius: var(--r-sm) var(--r-sm) 0 0;
}
/* Le corps déplié prolonge la bande, sans la refermer d'un trait.
 * Il est teinté du MÊME doré que le bouton ouvert, en plus dilué : un gris
 * neutre sous un bouton doré donnait deux familles de couleur collées l'une à
 * l'autre, et la bande se lisait comme deux morceaux rapportés au lieu d'un
 * seul bloc dépliant. */
.tool.tool-pref > .tool-body {
  border-top: none;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: color-mix(in srgb, var(--c-ululazm) 6%, transparent);
  padding-top: 0.5rem;
}
.sb-sublabel {
  margin: 0.35rem 0 0.1rem;
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.3;
  margin-top: var(--space-3);
  margin-bottom: var(--space-1);
}
.tagpick-list {
  display: flex; flex-wrap: wrap; gap: 0.35rem;
  max-height: 168px; overflow-y: auto;
  padding-bottom: 0.2rem;
  scrollbar-width: thin;
}
/* Même raison que .cross-tag : un <button> doit déclarer son fond. */
.pick-tag {
  cursor: pointer;
  border-width: 1px;
  background: color-mix(in srgb, var(--tag-c, currentColor) 8%, var(--panel));
  font-family: var(--font-body);
  font-size: var(--fs-00);
  transition: opacity 0.15s ease, box-shadow 0.15s ease;
  border-radius: var(--r-xs);
  transition-property: color, background-color, border-color, box-shadow, opacity;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
  min-height: 26px;
}
.pick-tag.on { box-shadow: 0 0 0 2px var(--c-ululazm); font-weight: 700; }
.pick-tag.dead { opacity: 0.3; cursor: not-allowed; filter: grayscale(1); }
.tagpick-count { margin-top: 0.55rem; }
/* La flèche pivote d'un quart de tour dans le sens des aiguilles. */
.tagpick-nbtn .tool-chev { transition: transform 0.2s ease; display: inline-block; }
.tagpick-nbtn .tool-chev.turned { transform: rotate(90deg); }
.tagpick-search {
  width: 100%;
  margin-bottom: 0.5rem;
  padding: 0.35rem 0.6rem;
  border-radius: var(--r-sm);
  /* Même liseré que #search-input, et pour la même raison. */
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--text) 7%, var(--bg));
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.12);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-0);
}
.tagpick-search:focus { outline: none; border-color: var(--c-ululazm); }
.tagpick-search:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 0; }
.tagpick-hint { font-size: var(--fs-0); color: var(--text-muted); }
.tagpick-nbtn {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.4rem; width: 100%;
  padding: 0.38rem 0.55rem;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--card-bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-0); font-weight: 600;
  cursor: pointer;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
  min-height: 26px;
}
.tagpick-nbtn:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.tagpick-people {
  display: flex; flex-direction: column; gap: 0.25rem;
  max-height: 210px; overflow-y: auto;
  margin-top: 0.4rem;
  scrollbar-width: thin;
}
.tagpick-people .concept-person { font-size: var(--fs-0); padding: 0.3rem 0.45rem; }
.tagpick-more { margin: 0.4rem 0 0; font-size: var(--fs-00); color: var(--text-faint); }
#tagpick-reset { margin-top: 0.55rem; width: 100%; }
.cross-msg { margin: 0.9rem 0 0.2rem; font-weight: 600; color: var(--text); }
#cross-result .concept-people { margin-top: 0.5rem; }


/* ============================================================
   AJOUTS : surnoms, événements de frise, langue, RTL
   ============================================================ */
.box .nick {
  width: 100%;
  text-align: left;
  font-style: italic;
  font-size: 11.5px;
  line-height: 1.15;
  color: var(--text-faint);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.box.muhammad .nick { color: #e8dcb8; }


#time-axis { width: var(--frise-w); }

/* Sélecteur de langue */
.banner-right { display: flex; align-items: center; gap: 0.6rem; }
.banner-right { gap: 0.6rem; margin-right: 0.4rem; }

/* Surnom dans le volet */
.panel-nick.after-wrap { margin-top: 0.55rem; }
.panel-nick {
  margin: 0.15rem 0 0;
  font-style: italic;
  font-size: var(--fs-2);
  color: var(--text-muted);
}
.untranslated { font-size: var(--fs-00); color: var(--text-faint); }

/* RTL */
body.rtl .box .fr, body.rtl .box .nick { text-align: left; direction: ltr; }
body.rtl .about, body.rtl #detail-panel { text-align: right; }
body.rtl .about ul { padding-right: 1.2rem; padding-left: 0; }
body.rtl #detail-panel { left: 0; right: auto; border-left: none; border-right: 1px solid var(--line); transform: translateX(-100%); }
/* En arabe le texte commence à droite : la croix passe dans le coin gauche,
   et c'est de ce côté que l'en-tête réserve sa place. */
body.rtl #close-panel-btn { right: auto; left: 1.1rem; }
body.rtl .panel-head {
  padding-right: 0;
  padding-left: max(2.2rem, calc(var(--ruban-place) - var(--volet-px)));
}
body.rtl #detail-panel.open { transform: translateX(0); }
body.rtl #time-axis { left: 0; right: auto; }
body.rtl .axis-tick { direction: ltr; }
body.rtl #help-btn, body.rtl #help-popover { right: auto; left: 1rem; }
/* la légende passe du côté opposé au volet (qui s'ouvre à gauche en arabe) */
body.rtl #link-legend { left: auto; right: 1rem; }
/* En arabe, la barre de réglages est à droite : rabat et languette y basculent */
body.rtl #view-tree.sidebar-collapsed #sidebar { margin-left: 0; margin-right: var(--sb-rentre); }
/* Les deux languettes sont écrites en propriétés LOGIQUES : leur place, leur
   arrondi et leur bordure basculent d'eux-mêmes. Ne reste à retourner que le
   dessin du chevron, qui pointe vers le volet. */
body.rtl #collapsed-fold { left: auto; right: 52px; }
body.rtl #sidebar-hide { transform: scaleX(-1); }

/* Tags dans le volet latéral */
.panel-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0.7rem 0 0; }
.panel-tags .tag { font-size: 12px; padding: 5px 9px; }

/* ============================================================
   RECHERCHE — suggestions
   ============================================================ */
.sb-searchrow { position: relative; }
/* `fixed`, et non `absolute` : la colonne des réglages DÉFILE
   (`#sidebar { overflow-y: auto }`) et l'outil d'ancêtre commun a ses coins
   arrondis (`.tool { overflow: hidden }`). Une liste posée dans ce flux était
   coupée net — on n'en voyait que les deux ou trois premiers noms. Les
   coordonnées viennent du JS (`placeSuggest`). */
#search-sugg {
  position: fixed;
  z-index: 40;
  max-height: 300px;
  overflow-y: auto;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.26);
  padding: 4px;
}
#search-sugg[hidden] { display: none; }
.sugg-item[disabled] {
  cursor: not-allowed;
  opacity: 0.5;
}
.sugg-item[disabled]:hover { background: none; }
/* La raison, sous le nom : une personne masquée n'a pas disparu, elle est
   simplement hors de ce que les filtres laissent voir. */
.sugg-off {
  margin-top: 2px;
  font-size: var(--fs-00);
  font-style: italic;
  color: var(--text-faint);
}
.sugg-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1px;
  width: 100%;
  padding: 6px 8px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-1);
  text-align: left;
  cursor: pointer;
}
.sugg-item:hover, .sugg-item.active { background: var(--bg); }
/*
 * LA COULEUR DE LA CASE, SUR LA LIGNE DE RÉSULTAT.
 *
 * Ce sont les fonds de l'arbre, repris aux mêmes variables : un résultat se
 * reconnaît avant d'être lu, comme la carte qu'il désigne. Rien d'autre n'est
 * repris — ni bordure, ni cartouche, ni halo : une liste n'est pas un dessin,
 * et la ligne doit rester une ligne.
 *
 * Le survol et la sélection au clavier ÉCLAIRCISSENT le fond au lieu de le
 * remplacer : posé par-dessus, `var(--bg)` effaçait justement la couleur qu'on
 * vient de mettre, et la ligne visée redevenait grise.
 */
.sugg-quran    { background: var(--card-bg-prophet); }
.sugg-ululazm  { background: var(--card-bg-ululazm); }
.sugg-sahabi   { background: var(--card-bg-sahabi); }
.sugg-muhammad { background: var(--c-muhammad-bg); color: #fdf6e3; }
.sugg-muhammad .sugg-ar, .sugg-muhammad .sugg-year { color: #f6e2ac; }
.sugg-muhammad b { color: var(--c-muhammad-gold); }
.sugg-item:not(.sugg-figure):hover, .sugg-item:not(.sugg-figure).active {
  box-shadow: inset 0 0 0 999px rgba(127, 127, 127, 0.16);
}
.sugg-item b { color: var(--gold-ink); font-weight: 700; }
.sugg-fr { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sugg-ar {
  font-family: "Amiri Quran", serif;
  font-size: 1.1em;
  color: var(--text-muted);
  direction: rtl;
  white-space: nowrap;
  /* L'interligne propre à l'écriture arabe (voir `.kicker`). */
  line-height: 1.75;
}
.sugg-main { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.sugg-year { font-size: var(--fs-00); color: var(--text-faint); direction: ltr; }
body.rtl .sugg-year { text-align: right; }
.sugg-empty { padding: 8px; font-size: var(--fs-1); color: var(--text-faint); }

/*
 * NASAB « ibn y » / « bint y » — affiché hors de la case, plus petit et plus
 * léger que le nom, comme la date des suggestions. Il ne doit jamais voler la
 * vedette au nom : c'est une précision, pas une partie du nom.
 */
.nasab {
  font-size: 0.78em;
  font-weight: 400;
  font-style: normal;
  color: var(--text-faint);
  white-space: nowrap;
  /* Pas de marge : l'espace est un vrai caractère, dans le texte. */
}
/* Le nasab arabe suit le nom arabe : même police, même sens de lecture. */
.sugg-ar .nasab, .kin-ar .nasab, #panel-arabic .nasab, #panel-name.as-arabic .nasab {
  font-family: var(--font-arabic);
}
/*
 * PÈRE ET MÈRE L'UN SOUS L'AUTRE, comme tous les autres encadrés de parenté.
 *
 * Ils étaient côte à côte, chacun sur une demi-largeur : dans une colonne de
 * 360 px, cela donnait deux cases de 160 où un nom latin et un nom arabe ne
 * tenaient plus sur la même ligne — alors que le frère juste en dessous, seul
 * dans sa largeur, les tenait. Deux mises en page pour la même chose.
 *
 * `display: contents` fait DISPARAÎTRE la boîte qui les appariait : les deux
 * encadrés deviennent des enfants directs du volet et se rangent comme les
 * autres, avec la même marge et la même largeur. Rien à écrire de plus, et
 * l'un des deux peut manquer sans laisser de vide.
 */
.kin-pair { display: contents; }
/*
 * Le nom arabe reste À CÔTÉ du nom latin, plaqué à droite, et ne passe à la
 * ligne QUE s'il n'y a pas la place — c'est `flex-wrap` qui décide, pas nous.
 * L'empiler d'office gâchait la moitié de la largeur quand les deux tenaient.
 */
/* Vaut pour TOUTE case seule dans sa colonne — le père comme le fils unique :
   dès qu'un nom latin et un nom arabe partagent une ligne, l'arabe est plaqué
   à droite. Rien ne justifie que le père l'ait et le fils non. */
.kin-cards.single .kin-card {
  flex-wrap: wrap;
  align-items: baseline;
  row-gap: 0.1rem;
  overflow: hidden;
}
/*
 * LE NOM LATIN AU BORD GAUCHE, L'ARABE AU BORD DROIT — jamais l'un à la suite
 * de l'autre.
 *
 * `justify-content: space-between` ne suffisait pas : les deux noms sont des
 * boîtes en ligne dont la somme des largeurs est plus petite que la case, et
 * une marge `auto` posée sur le seul nom arabe reste sans effet quand le nom
 * latin ne pousse pas. On donne donc au latin toute la place restante — il
 * garde son alignement à gauche —, et l'arabe ne prend que la sienne, collé au
 * bord opposé. La case s'aligne ainsi comme l'en-tête de la fiche, où le
 * français est à gauche et l'arabe à droite.
 */
.kin-cards.single .kin-card .kin-fr { flex: 1 1 auto; text-align: start; }
/*
 * ET IL RESTE AU BORD MÊME QUAND IL PASSE À LA LIGNE.
 *
 * Le nom latin, seul de sa ligne, prenait toute la place et poussait l'arabe
 * au bord opposé ; renvoyé à la ligne, l'arabe se retrouvait seul sur la
 * sienne, donc au DÉBUT — à gauche en français, sous un nom latin lui aussi à
 * gauche. La marge automatique le pousse : sans effet tant que le latin pousse
 * déjà (le `flex-grow` a mangé la place avant elle), décisive dès que plus
 * rien ne pousse.
 *
 * ELLE EST ÉCRITE EN PHYSIQUE, et c'est une exception assumée. `.kin-ar` porte
 * `direction: rtl` pour l'écriture arabe, et une propriété LOGIQUE se résout
 * sur la direction de l'élément LUI-MÊME : `margin-inline-start` y devenait
 * `margin-right`, c'est-à-dire une poussée vers la gauche — l'inverse exact de
 * ce qu'on veut. La règle miroir de l'interface arabe est donc écrite à côté.
 */
.kin-cards.single .kin-card .kin-ar { flex: 0 0 auto; text-align: end; margin-left: auto; }
body.rtl .kin-cards.single .kin-card .kin-ar { margin-left: 0; margin-right: auto; }
.kin-card .nasab { white-space: normal; }
#panel-name .nasab { font-size: 0.5em; }
#panel-arabic .nasab { font-size: 0.6em; }
.concept-person .nasab { font-size: 0.8em; }
body.rtl .sugg-item { text-align: right; }
body.rtl .sugg-main { flex-direction: row-reverse; }
body.rtl .sugg-ar { flex: 1; min-width: 0; }

/* ============================================================
   AVANCEMENT DU SOURÇAGE
   ============================================================ */
#progress-bars { display: flex; flex-direction: column; gap: 0.3rem; }
/* Un sélecteur d'ID l'emporte sur `.tool-body[hidden]` : sans cette ligne le
   bloc restait `display: flex` et le dépliant ne se refermait jamais. */
#progress-bars[hidden] { display: none; }
.prg-row { display: flex; align-items: center; gap: 0.45rem; font-size: var(--fs-00); }
.prg-lbl { flex: none; width: 5.6rem; color: var(--text-muted); }
.prg-track {
  flex: 1; min-width: 0;
  height: 5px;
  border-radius: 3px;
  background: var(--line-soft);
  overflow: hidden;
}
/* La jauge n'est plus un bloc d'une seule teinte : elle EMPILE une part par
   source, dans l'ordre des filtres. On y lit d'un coup d'œil non seulement ce
   qui est sourcé, mais PAR QUOI. Ce qui reste du fond, c'est le non sourcé. */
.prg-fill { display: flex; height: 100%; border-radius: 3px; overflow: hidden; }
.prg-seg { height: 100%; }
.prg-seg.src-quran       { background: var(--src-quran); }
.prg-seg.src-ibnkathir   { background: var(--src-ibnkathir); }
.prg-seg.src-tabari      { background: var(--src-tabari); }
.prg-seg.src-israiliyyat { background: var(--src-israiliyyat); }
.prg-seg.src-nassaba     { background: var(--src-nassaba); }
.prg-seg.src-archeo      { background: var(--src-archeo); }
.prg-num { flex: none; color: var(--text-faint); font-variant-numeric: tabular-nums; direction: ltr; }
body.rtl .prg-lbl { width: 5.2rem; }

/* ============================================================
   MOBILE (≤ 700 px)
   La barre de réglages passe en SURCOUCHE : elle ne pousse plus l'arbre, qui
   n'aurait plus la place d'exister. Elle est repliée au départ (voir app.js).
   Le volet de fiche, lui, occupe toute la largeur.
   ============================================================ */
/* Sous 700 px la fiche occupe tout l'écran : le « ? » n'a plus de place à
   côté d'elle et venait se poser dessus. On l'efface tant qu'elle est ouverte. */
@media (max-width: 700px) {
  body.panel-open #help-btn, body.panel-open #help-popover { display: none; }
}
@media (max-width: 700px) {
  /*
   * LA FRISE PREND LA PLACE DE L'ARBRE SUR UN TÉLÉPHONE. Cent trente-huit
   * pixels sur un écran de trois cent quatre-vingt-dix, c'est plus du tiers de
   * la largeur pour une colonne de dates. Elle passe à quarante-deux, et tout
   * ce qui l'habite rétrécit avec elle : le corps des dates, la longueur des
   * traits, l'écart entre le trait et le chiffre. Le voile dégradé suit de
   * lui-même, il est posé sur toute la largeur.
   */
  :root { --frise-w: 42px; }
  #time-axis { width: var(--frise-w); }
  .axis-era { font-size: 0.56rem; }
  .axis-tick { gap: 3px; }
  .axis-minor { width: 5px; }
  .tick-s .axis-line { width: 6px; }
  .tick-c .axis-line { width: 9px; }
  .tick-d .axis-line { width: 12px; }
  .tick-m .axis-line { width: 15px; }

  /* Le bandeau ne tient plus : les onglets défilent au lieu d'être coupés. */
  .banner { gap: 0.4rem; padding-left: 0.5rem; padding-right: 0.5rem; }
  .banner .nav {
    flex: 1; min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .banner .nav::-webkit-scrollbar { display: none; }
  .nav-btn { flex: none; white-space: nowrap; }
  /*
   * … ET LE DÉFILEMENT SE DIT. La barre étant masquée, rien n'annonçait qu'il
   * restait des onglets : mesuré à 390 px, « À propos » est hors cadre et
   * invisible. Un dégradé sur le bord où il en reste — la barre se termine en
   * fondu au lieu de se terminer net, ce qui est la manière habituelle de dire
   * « ça continue ». `mask-image` n'ajoute aucun élément et suit le sens de
   * lecture, l'arabe est donc servi par la seule règle miroir.
   */
  .banner .nav {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }
  body.rtl .banner .nav {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent);
  }
  /* Le fondu ne doit pas manger le dernier onglet une fois qu'on l'a atteint :
     une marge de fin égale au fondu laisse de quoi le sortir entièrement. */
  .banner .nav::after { content: ""; flex: none; width: 20px; }

  /* En surcouche, le volet s'élargit : la languette de rabat s'accroche à son
     bord, elle doit donc suivre — d'où la variable, redéclarée à la racine
     pour que les deux la lisent. */
  :root { --sb-w: min(300px, 86vw); }
  #sidebar {
    /* `fixed` (comme le volet de fiche) : `absolute` se résoudrait contre le
       bloc conteneur initial, `#view-tree` n'étant pas positionné. */
    position: fixed;
    top: var(--banner-h, 64px);
    left: 0;
    bottom: 0;
    width: var(--sb-w);
    z-index: 30;
    box-shadow: 10px 0 30px rgba(0, 0, 0, 0.32);
    transition: transform var(--dur-volet) var(--ease-entree);
  }
  /* En surcouche on translate : la marge négative laisserait un trou. */
  #view-tree.sidebar-collapsed #sidebar { margin-left: 0; transform: translateX(-102%); }
  body.rtl #sidebar { left: auto; right: 0; box-shadow: -10px 0 30px rgba(0, 0, 0, 0.32); }
  body.rtl #view-tree.sidebar-collapsed #sidebar { margin-right: 0; transform: translateX(102%); }

  /* On redéfinit les VARIABLES, jamais le raccourci : l'en-tête calcule son
     retrait en retranchant `--volet-px` du ruban, et un rembourrage écrit à
     côté de la variable le laissait court de six pixels — le nom arabe
     touchait le ruban à 620 px. */
  #detail-panel {
    width: 100vw; max-width: 100vw;
    --volet-pt: 1.3rem; --volet-px: 1.1rem; --volet-pb: 1.5rem;
  }
  body.rtl #detail-panel { border-right: none; }
  #link-legend { display: none; }
}

/* Voile de la barre en surcouche — n'existe qu'en mobile */
#sidebar-scrim { display: none; }
@media (max-width: 700px) {
  #view-tree:not(.sidebar-collapsed) #sidebar-scrim {
    display: block;
    position: fixed;
    top: var(--banner-h, 64px);
    left: 0; right: 0; bottom: 0;
    z-index: 29;
    background: rgba(0, 0, 0, 0.45);
  }
}

/* ============================================================
   RÉGLAGE DES FORMES DE NOM (page d'accueil)
   ============================================================ */
/*
 * Trois teintes, aucun cadre de plus : la page, l'encadré du réglage, et la
 * carte d'exemple. Un encadré supplémentaire autour de la carte n'ajoutait
 * rien — il suffit que chaque élément se distingue de son voisin.
 */
#name-setting {
  max-width: 700px;
  margin: 1.6rem auto 0;
  padding: 1.2rem 1.3rem 1.4rem;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  /* Un fond POSÉ sur la page, non creusé dedans : il était plus sombre que
     tout le reste et faisait un trou au milieu de l'accueil. */
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--ns-canvas) 92%, transparent),
              var(--ns-canvas));
  box-shadow: 0 1px 0 color-mix(in srgb, #fff 6%, transparent) inset,
              0 6px 18px rgba(0, 0, 0, 0.12);
  text-align: center;
}
.ns-title {
  margin: 0 0 0.3rem;
  font-family: var(--font-display);
  font-size: var(--fs-4);
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.02em;
}
.ns-help { margin: 0 0 1rem; font-size: var(--fs-1); color: var(--text-faint); font-style: italic; }
/* Les trois cases EMPILÉES, l'exemple à leur droite. */
.ns-body { display: flex; align-items: center; justify-content: center; gap: 1.4rem; }
.ns-row { display: flex; flex-direction: column; gap: 0.5rem; flex: 0 0 16rem; }
/*
 * Les trois cases sont un CADRE, pas un fond : même largeur, même hauteur,
 * bord net, et une teinte plus claire que l'encadré qui les porte — sans quoi
 * elles s'y fondaient et on ne voyait plus trois choix mais un bloc de texte.
 */
.ns-opt {
  flex: 1 1 0;
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-raised);
  box-shadow: var(--ombre-1);
  cursor: pointer;
  text-align: left;
  transition: border-color 0.15s ease, background 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, opacity;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.ns-opt:hover { border-color: var(--c-ululazm); background: var(--bg-raised-2); }
/* Une case cochée se voit : le bord prend la couleur d'accent. */
.ns-opt:has(input:checked) { border-color: color-mix(in srgb, var(--c-ululazm) 60%, var(--line)); }
.ns-opt:focus-within { outline: 2px solid var(--c-ululazm); outline-offset: 2px; }
.ns-opt input { margin-top: 0.15rem; accent-color: var(--c-ululazm); cursor: pointer; width: 16px; height: 16px; }
.ns-opt > span { display: flex; flex-direction: column; min-width: 0; }
.ns-main { font-size: var(--fs-2); color: var(--text); }
/* La précision passe à la ligne, en italique, plus petite et plus claire. */
.ns-sub { font-size: var(--fs-00); font-style: italic; color: var(--text-faint); line-height: 1.35; }
.ns-preview {
  display: flex;
  justify-content: center;
  flex: 0 1 auto;
  min-width: 0;
}
/* L'aperçu est une VRAIE carte : sans borne haute il s'étirait sur toute la
   largeur de l'encadré et paraissait anormalement allongé. */
/* Simple illustration : ni curseur, ni survol, ni clic. Taille FIXE, sinon
   l'encadré sautait à chaque case cochée ou décochée. */
#name-sample {
  cursor: default;
  text-align: left;
  pointer-events: none;
  width: 300px;
  min-width: 300px;
  max-width: 300px;
  height: 118px;
  justify-content: center;
  overflow: hidden;
}
body.rtl .ns-opt, body.rtl #name-sample { text-align: right; }
@media (max-width: 700px) {
  /* Sur téléphone, l'EXEMPLE d'abord : on voit ce que l'on règle avant de
     régler. `column-reverse` suffit, l'ordre du HTML reste celui de la
     lecture au clavier et à la synthèse vocale. */
  .ns-body { flex-direction: column-reverse; gap: 1rem; }
  .ns-row { flex: none; width: 100%; }
  .ns-preview { width: 100%; }
}

/* ============================================================
   OUTIL « ANCÊTRE COMMUN »
   ============================================================ */
.tool-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.tool-btn:hover, .tool-btn.open { border-color: var(--c-ululazm); color: var(--gold-ink); background: color-mix(in srgb, var(--c-ululazm) var(--voile-survol), transparent); }
.tool-ico { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.tool-ico circle { fill: currentColor; stroke: none; }

.mrca-field { position: relative; display: flex; flex-direction: column; gap: 0.2rem; }
.mrca-lbl { font-size: var(--fs-00); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); }
/* Même habillage que la recherche globale */
.mrca-field input {
  width: 100%;
  padding: 0.5rem 0.7rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
}
.mrca-field input::placeholder { color: var(--text-faint); }
.mrca-field input:focus {
  outline: none;
  border-color: var(--c-ululazm);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--c-ululazm) 22%, transparent);
}
/*
 * L'ANNEAU DE FOCUS D'UN CHAMP SUIT SA BORDURE, il ne l'encadre pas de noir.
 *
 * `--c-select` vaut #2a2317 en thème jour : posé à 2 px de distance autour
 * d'un champ déjà bordé d'or, il donnait un épais cadre presque noir. Le
 * champ prend donc l'or qu'il porte déjà au focus, collé à sa bordure : on le
 * voit tout autant au clavier, sans le pavé.
 */
.mrca-field input:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 0; }
.mrca-sugg {
  position: fixed;
  z-index: 60;
  max-height: 240px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-raised);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.26);
}
.mrca-sugg[hidden] { display: none; }
.mrca-sugg .sugg-item { text-align: left; }
body.rtl .mrca-sugg .sugg-item { text-align: right; }
.mrca-actions { display: flex; gap: 0.4rem; }
.mrca-go, .mrca-clear {
  flex: 1;
  padding: 0.45rem 0.5rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-ululazm);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
}
.mrca-go { background: var(--c-ululazm); color: #ffffff; transition-property: color, background-color, border-color, box-shadow, transform; transition-duration: var(--dur-teinte); transition-timing-function: var(--ease-vif); font-weight: 600; }
.mrca-clear { background: none; color: var(--text-muted); border-color: var(--line); transition-property: color, background-color, border-color, box-shadow, transform; transition-duration: var(--dur-teinte); transition-timing-function: var(--ease-vif); }
.mrca-clear:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.mrca-err { margin: 0; font-size: var(--fs-0); font-style: italic; color: var(--c-mrca); }
.mrca-err[hidden] { display: none; }

/* Bandeau de résultat, en haut de l'arbre */
#mrca-banner {
  /* Centré sur la ZONE D'ARBRE (donc jamais sous la barre latérale). Quand la
     fiche s'ouvre, le centre se décale de sa largeur : le bandeau reste
     entièrement visible au lieu de passer dessous. */
  position: absolute;
  top: 14px;
  left: 50%;
  transform: translateX(-50%);
  transition: left 0.30s ease;
  z-index: 12;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  max-width: min(660px, calc(100% - 120px));
  padding: 0.6rem 0.7rem 0.6rem 1rem;
  border: 1.5px solid var(--c-mrca);
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--ombre-2);
  font-size: var(--fs-2);
  color: var(--text);
}
#mrca-text { flex: 1; text-align: center; }
/* Le nom de l'ancêtre ne se coupe pas : s'il ne tient plus, il passe entier
   à la ligne suivante. */
#mrca-text .mrca-anc { white-space: nowrap; }
#mrca-banner[hidden] { display: none; }
body.panel-open #mrca-banner { left: calc(50% - min(360px, 88vw) / 2); }
body.rtl.panel-open #mrca-banner { left: calc(50% + min(360px, 88vw) / 2); }
#mrca-banner b { font-weight: 700; color: var(--text); }
#mrca-banner-close {
  flex: none;
  width: 24px; height: 24px;
  border: none;
  border-radius: 5px;
  background: none;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
}
#mrca-banner-close:hover { color: var(--c-mrca); }

/* Mise en évidence dans l'arbre */
/*
 * Le marquage ne doit RIEN changer à la géométrie de la carte : épaissir la
 * bordure la faisait grandir et déborder du `foreignObject`, qui la rognait —
 * la carte de ʿAliyy apparaissait coupée en bas. L'épaisseur passe donc par un
 * anneau INTERNE, et le halo tient dans la marge de 16 px.
 */
.card.mrca {
  border-color: var(--c-mrca) !important;
  box-shadow: inset 0 0 0 2px var(--c-mrca),
              0 0 0 3px color-mix(in srgb, var(--c-mrca) 50%, transparent),
              0 0 9px 1px color-mix(in srgb, var(--c-mrca) 45%, transparent) !important;
}
/*
 * Le trajet doit rester lisible de loin. `vector-effect: non-scaling-stroke`
 * fige l'épaisseur en pixels ÉCRAN : le trait garde 4 px quel que soit le
 * zoom, alors qu'un `stroke-width` ordinaire rétrécit avec la vue et
 * disparaissait dès qu'on dézoomait pour voir les deux extrémités.
 */
.link.mrca {
  stroke: var(--c-mrca);
  stroke-width: 2.8px;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--c-mrca) 55%, transparent));
}

/* ============================================================
   BOUTONS DÉPLIANTS DE LA BARRE LATÉRALE (outil, noms, avancement)
   Bouton et contenu dans UN SEUL encadré.
   ============================================================ */
/*
 * DES SECTIONS RÉGLÉES, NON DES BOÎTES EMPILÉES. Sept encadrés arrondis les
 * uns sous les autres donnaient sept cadres à lire avant d'atteindre le
 * premier réglage. Chaque outil devient une section séparée de la suivante par
 * un filet, comme les rubriques d'une même page — le cadre ne disparaît qu'au
 * REPOS : dès que l'outil est ouvert, il reprend un fond propre, parce qu'il
 * faut alors voir où il commence et où il finit.
 */
.tool {
  border: none;
  border-top: 1px solid var(--line-soft);
  border-radius: 0;
  background: transparent;
  overflow: visible;
  transition: border-color 0.15s ease;
}
.tool:first-of-type { border-top: none; }
.tool.open {
  border-top-color: var(--line-soft);
  background: color-mix(in srgb, var(--text) 4%, transparent);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
}
.tool .tool-btn {
  width: 100%;
  padding-block: 0.62rem;
  border: none;
  border-radius: 0;
  background: none;
  justify-content: flex-start;
}
.tool .tool-btn:hover { border-color: transparent; background: color-mix(in srgb, var(--c-ululazm) var(--voile-survol), transparent); }

/* UN OUTIL DÉJÀ OUVERT PREND UN VOILE PLUS DENSE AU SURVOL. Son fond porte
   déjà la teinte ; le même voile que sur un outil fermé ne s'y verrait pas. */
.tool.open .tool-btn:hover, .tool.tool-pref.open > .tool-btn:hover {
  background: color-mix(in srgb, var(--c-ululazm) var(--voile-survol-ouvert), transparent);
}

.tool.open .tool-btn { color: var(--gold-ink); }
.tool-btn > span[data-i18n] { flex: 1; text-align: left; }
body.rtl .tool-btn > span[data-i18n] { text-align: right; }
.tool-chev {
  flex: none;
  font-size: var(--fs-4);
  line-height: 1;
  color: var(--text-faint);
  transition: transform 0.18s ease;
  transition-property: transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-entree);
}
.tool.open .tool-chev { transform: rotate(90deg); color: var(--gold-ink); }
body.rtl .tool-chev { transform: rotate(180deg); }
body.rtl .tool.open .tool-chev { transform: rotate(90deg); }
.tool-body {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding: 0.2rem 0.7rem 0.75rem;
  border-top: 1px solid var(--line-soft);
}
.tool-body[hidden] { display: none; }
/* Les cases de nom en version compacte, dans la barre latérale */
.ns-opt.compact { flex: none; min-width: 0; padding: 0.3rem 0.5rem; }

/* ============================================================
   CONSEIL DE PREMIÈRE OUVERTURE
   ============================================================ */
#hint-veil {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* Un fond « un petit peu assombri » : on doit continuer de voir l'arbre
     derrière, c'est de lui qu'on parle. */
  background: rgba(0, 0, 0, 0.34);
  animation: hint-in 0.22s ease;
}
#hint-veil[hidden] { display: none; }
@keyframes hint-in { from { opacity: 0; } to { opacity: 1; } }
#hint-box {
  position: relative;
  max-width: min(460px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.5rem 1.6rem 1.3rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  box-shadow: var(--ombre-3);
  text-align: start;
}
#hint-box h2 {
  margin: 0 0 0.7rem;
  padding-inline-end: 2.6rem;      /* la croix ne recouvre pas le titre */
  font-size: var(--fs-4);
  color: var(--c-ululazm);
}
#hint-box p { margin: 0; line-height: 1.62; color: var(--text-muted); }
/* La croix est le SEUL moyen de fermer depuis l'encadré : elle se voit. */
#hint-close {
  position: absolute;
  top: 6px;
  inset-inline-end: 8px;
  width: 44px; height: 44px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
}
#hint-close:hover { color: var(--text); background: var(--bg-raised); }

/*
 * DÉSIGNÉ, OU ATTRIBUÉ — la fenêtre des deux « ? ».
 *
 * Même voile et même croix que le conseil d'ouverture : c'est le même geste,
 * elle n'a pas à s'inventer une autre manière de s'ouvrir et de se fermer. Un
 * peu plus large, parce qu'elle porte un verset.
 */
#qm-veil {
  position: fixed;
  inset: 0;
  z-index: 82;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.34);
  animation: hint-in 0.22s ease;
}
#qm-veil[hidden] { display: none; }
#qm-box {
  position: relative;
  max-width: min(560px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.5rem 1.6rem 1.3rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  box-shadow: var(--ombre-3);
  text-align: start;
}
#qm-box h2 {
  margin: 0 0 0.7rem;
  padding-inline-end: 2.6rem;      /* la croix ne recouvre pas le titre */
  font-size: var(--fs-4);
  color: var(--c-ululazm);
}
/* Le titre de chaque option reprend le libellé de sa case : on retrouve dans
   la fenêtre le mot exact qu'on vient de lire dans le volet. */
#qm-box h3 {
  margin: 1.1rem 0 0.3rem;
  font-size: var(--fs-1);
  color: var(--c-quran);
}
#qm-box p { margin: 0; line-height: 1.62; color: var(--text-muted); }
#qm-box .qm-lead { color: var(--text); }
#qm-exemple { margin: 0.7rem 0 0.6rem; }
#qm-close {
  position: absolute;
  top: 6px;
  inset-inline-end: 8px;
  width: 44px; height: 44px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
#qm-close:hover { color: var(--text); background: var(--bg-raised); }


/* ============================================================
   LES AID EGGS — ce que le site cache
   ============================================================
   Trois choses à habiller : les deux boutons sans dessin, les deux cases
   qu'ils posent, et la citation qui paraît puis s'en va.

   UN BOUTON SANS DESSIN N'EST PAS UN BOUTON TRANSPARENT POSÉ N'IMPORTE OÙ :
   il occupe exactement la place où les autres cartes portent leur +/−, à
   cheval sur le bord. C'est ce qui le rend trouvable par quelqu'un qui
   cherche, et invisible pour tous les autres. */
.aid-btn {
  position: absolute;
  left: 50%;
  width: 22px; height: 22px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  z-index: 2;
}
.aid-btn-haut { top: 0; transform: translate(-50%, -50%); }
.aid-btn-bas { bottom: 0; transform: translate(-50%, 50%); }
/* La même prise élargie que les vrais +/− : sans elle, il faut viser au pixel. */
.aid-btn::after { content: ""; position: absolute; inset: -7px; }

/*
 * LA TERRE ET LE PALMIER NE SONT PAS DES PERSONNES, et la case le dit : un
 * filet tireté, pas de cartouche, pas d'ombre portée. On ne doit pas pouvoir
 * les confondre une seconde avec une carte de l'arbre.
 */
.aid-card {
  border-style: dashed;
  border-color: var(--c-ululazm);
  box-shadow: none;
  cursor: default;
  opacity: 0.96;
}
.aid-card:hover { box-shadow: none; }
.aid-card .card-fr { color: var(--c-ululazm); }
/* Le trait qui les joint n'est ni un « fils de » ni un « descendant de » :
   il ne dit pas une filiation, il dit d'où une chose fut tirée. */
.aid-link {
  fill: none;
  stroke: var(--c-ululazm);
  stroke-width: 1.2px;
  stroke-dasharray: 2 5;
  stroke-linecap: round;
  opacity: 0.75;
}

/*
 * LA CITATION QUI PASSE. Elle se pose au-dessus du dessin, au milieu, et
 * s'efface seule au bout de dix secondes — d'où un fondu LENT (1,5 s) : une
 * disparition brusque se lit comme une fermeture, et l'on croit avoir cliqué.
 */
#aid-toast {
  position: fixed;
  z-index: 84;
  top: calc(var(--banner-h, 64px) + 1.2rem);
  left: 50%;
  transform: translateX(-50%);
  width: min(520px, calc(100vw - 2rem));
  opacity: 0;
  transition: opacity 1.5s ease, transform 1.5s ease;
  pointer-events: none;
}
#aid-toast[hidden] { display: none; }
#aid-toast.show { opacity: 1; }
.aid-toast-in {
  padding: 0.9rem 1.1rem 1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: var(--ombre-3);
  text-align: start;
}
.aid-toast-titre {
  margin-bottom: 0.5rem;
  font-family: var(--font-display);
  font-size: var(--fs-2);
  color: var(--c-ululazm);
}

/*
 * LE BOUTON SANS DESSIN DE LA PAGE « À PROPOS ». Il ouvre la liste. Il ne
 * prend ni le clavier ni la voix des lecteurs d'écran (voir `index.html`) :
 * un bouton qu'on annonce n'est plus caché.
 */
#aid-trove {
  display: inline-block;
  width: 1.1em; height: 0.9em;
  margin-inline-start: 0.2em;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  vertical-align: baseline;
}

/* La liste, sur le modèle de la fenêtre « désigné / attribué ». */
#aid-veil {
  position: fixed;
  inset: 0;
  z-index: 86;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.34);
  animation: hint-in 0.22s ease;
}
#aid-veil[hidden] { display: none; }
#aid-box {
  position: relative;
  max-width: min(560px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: 1.5rem 1.6rem 1.3rem;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  box-shadow: var(--ombre-3);
  text-align: start;
}
#aid-box h2 {
  margin: 0 0 0.7rem;
  padding-inline-end: 2.6rem;
  font-family: var(--font-display);
  font-size: var(--fs-4);
  color: var(--c-ululazm);
}
#aid-box .aid-lead { margin: 0; line-height: 1.62; color: var(--text-muted); }
#aid-close {
  position: absolute;
  top: 6px;
  inset-inline-end: 8px;
  width: 44px; height: 44px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
#aid-close:hover { color: var(--text); background: var(--bg-raised); }
.aid-compte {
  margin: 1rem 0 0.2rem;
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.aid-item { margin-top: 1.1rem; }
.aid-item h3 {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-size: var(--fs-2);
  font-weight: 500;
  color: var(--text);
}
/* Ce qui n'est pas trouvé garde sa ligne et ne dit rien : on veut savoir
   qu'il en reste, jamais lequel ni où. */
.aid-item-clos h3 {
  color: var(--text-muted);
  font-style: italic;
  opacity: 0.7;
}

/* La fourchette qui suit « Inconnue » : la même pastille, un ton en dessous —
   ce n'est pas une seconde information, c'est la précision de la première. */
.date-range {
  margin-inline-start: 0.4rem;
  font-size: 0.88em;
  opacity: 0.75;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   ANNULER ET REFAIRE
   ============================================================
   DEUX DEMI-TOURS, JUSTE AU-DESSUS DE LA LANGUETTE DES RÉGLAGES.

   Ils partagent son point d'attache — le bord du volet — et son voyage :
   quand le volet se replie, tout ce petit monde suit le bord qui recule,
   par la même translation et la même durée. Écrire une seconde fois la
   largeur du volet serait la faire vivre à deux endroits.

   Le bouton Retour a d'abord été une pastille au coin du dessin, avec le mot
   écrit. L'utilisateur les veut ici, en paire, et dessinés : deux flèches qui
   font demi-tour disent l'annulation mieux qu'un chevron, et une paire dit
   qu'il y a un aller ET un retour. */
/*
 * AU-DESSUS DU VOILE DE LA FICHE FENÊTRÉE.
 *
 * Le voile occupe tout le cadre du dessin : à `z-index: 9`, la paire Annuler /
 * Refaire passait dessous et ne se cliquait plus. Or c'est justement en lisant
 * une fiche qu'on veut défaire le dépli qui vient de la faire ouvrir. Elle
 * passe donc au-dessus (le voile est à 24), et reçoit un fond à elle pour
 * rester lisible par-dessus lui.
 */
#histo {
  position: absolute;
  /* Au-dessus de la languette, qui commence à `--fold-y - 26` : il reste
     quarante pixels sous le bandeau, la paire en prend trente. */
  top: calc(var(--banner-h, 64px) + 5px);
  inset-inline-start: var(--sb-w);
  z-index: 26;
  display: flex;
  gap: 5px;
  padding-inline-start: 6px;
  transition: transform var(--dur-volet) var(--ease-entree);
}
#view-tree.sidebar-collapsed #histo { transform: translateX(var(--sb-glisse)); }
.histo-btn {
  position: relative;
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-raised, var(--bg));
  color: var(--text-muted);
  cursor: pointer;
  box-shadow: var(--box-shadow);
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.histo-btn[hidden] { display: none; }
.histo-btn:hover { color: var(--c-ululazm); border-color: var(--c-ululazm); }
.histo-btn svg {
  width: 20px; height: 20px;
  fill: none; stroke: currentColor;
  stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}
/* En arabe, le sens de lecture s'inverse : les deux demi-tours avec lui. La
   paire, elle, se retourne d'elle-même — `direction: rtl` renverse un flex. */
body.rtl .histo-btn svg { transform: scaleX(-1); }
/* AU DOIGT, LA CIBLE FAIT QUARANTE-QUATRE PIXELS SANS QUE LE BOUTON GRANDISSE.
   Les agrandir aurait suffi à leur faire chevaucher la languette des réglages,
   qui commence quarante pixels sous le bandeau. La prise déborde donc,
   invisible — le même moyen que les boutons +/− des cartes. */
.histo-btn::after { content: ""; position: absolute; inset: -7px; }

/* ============================================================
   MENU DU BOUTON « + » (clic droit / appui long)
   ============================================================
   Un seul élément, posé en `fixed` et placé par le JS : il doit pouvoir sortir
   du cadre défilant de l'arbre sans être rogné. */
.ctx-menu {
  position: fixed;
  z-index: 60;
  min-width: 210px;
  padding: 4px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-raised, var(--bg));
  box-shadow: var(--ombre-2);
}
.ctx-menu button {
  display: block;
  width: 100%;
  padding: 0.5rem 0.7rem;
  border: none;
  border-radius: 4px;
  background: none;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  text-align: left;
  cursor: pointer;
}
body.rtl .ctx-menu button { text-align: right; }
.ctx-menu button:hover { background: color-mix(in srgb, var(--c-ululazm) 18%, transparent); color: var(--c-ululazm); }

/* Resserrement vertical : la frise s'efface, elle ne dirait plus vrai. */
body.tight-y #time-axis { display: none; }
/* MASQUÉE À LA DEMANDE — et la bande qu'elle occupait revient au dessin :
   `vueDuPlan` lit la largeur RÉELLE de la frise, et un élément retiré du flux
   n'en a plus. Rien d'autre à écrire. */
body.sans-frise #time-axis { display: none; }

/* ============================================================================
 * LA FICHE ÉTENDUE — la même fiche, au large, et la parenté proche dessinée.
 *
 * DEUX PAGES D'UN MÊME FEUILLET. Le volet latéral est une colonne étroite où
 * tout se suit ; la fenêtre est une double page — la notice à gauche, dans une
 * justification qui se lit, la parenté à droite, et l'arbre restreint en bas,
 * pleine largeur. Le filet vertical entre les deux colonnes est le pli.
 *
 * Aucune couleur nouvelle : elle emprunte tout au reste du site — le fond des
 * volets, le filet, la couleur de l'arabe, les teintes de catégorie. Une
 * fenêtre qui aurait sa propre palette n'appartiendrait plus à ce site.
 * ========================================================================= */
#fiche-veil {
  position: absolute;
  inset: 0;
  z-index: 24;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.6rem, 2.4vh, 2rem) clamp(0.6rem, 2.4vw, 2.4rem);
  background: color-mix(in srgb, var(--bg) 62%, transparent);
  cursor: default;
}
#fiche-modal {
  /* La géométrie du ruban du signet, écrite ICI parce que DEUX règles en
     dépendent et qu'elles ne se contiennent pas l'une l'autre : le ruban
     lui-même, et la gouttière du cadre de défilement qui lui garde sa
     colonne. Écrite deux fois, elle finirait par diverger. */
  --ruban-w: 22px;
  --ruban-x: 0.55rem;
  /* Ce que le ruban occupe en tout, de la paroi de la fenêtre à l'air qu'on
     lui laisse : c'est la colonne que rien d'autre ne doit prendre. */
  --ruban-place: calc(var(--ruban-x) + var(--ruban-w) + 0.3rem);
  position: relative;
  width: min(1080px, 100%);
  /* HAUTEUR PLEINE, et non `max-height` : le panneau de l'arbre demande
     « toute la hauteur de la fenêtre », ce qui n'a de sens que si la fenêtre
     en a une. Avec une hauteur seulement plafonnée, elle se réglait sur son
     contenu et le pourcentage n'avait rien à quoi se rapporter. */
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.42);
  /* `#map-container` force `direction: ltr` pour que les cartes gardent le
     nom latin à gauche : le sens d'écriture doit être remis ici. */
  direction: ltr;
  text-align: left;
  overflow: hidden;
  animation: fiche-in 0.22s ease both;
}
body.rtl #fiche-modal { direction: rtl; text-align: right; }
@keyframes fiche-in {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to   { opacity: 1; transform: none; }
}
#fiche-scroll {
  /* Les deux rembourrages verticaux sont NOMMÉS : le panneau de l'arbre doit
     les rajouter à son pourcentage de hauteur, et deux valeurs écrites à deux
     endroits finissent toujours par diverger. */
  --fiche-pt: 1.6rem;
  --fiche-pb: 2rem;
  /*
   * ET LA GOUTTIÈRE LATÉRALE DÉGAGE LE RUBAN DU SIGNET.
   *
   * Le ruban est posé sur la FENÊTRE, le texte défile DESSOUS : il ne suffit
   * pas d'écarter le titre, il faut que sa colonne reste vide quoi qu'on
   * fasse défiler. La gouttière ne descend donc jamais au-dessous de ce que
   * le ruban occupe — son retrait, sa largeur, et de quoi ne pas le frôler —,
   * et elle vaut la même des DEUX côtés : un rembourrage qui ne grandirait
   * que d'un bord ferait pencher toute la fiche.
   */
  --fiche-px: max(clamp(1rem, 3vw, 2.4rem), var(--ruban-place));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--fiche-pt) var(--fiche-px) var(--fiche-pb);
  /* Le panneau de l'arbre se règle sur la hauteur de CE cadre : il lui en faut
     donc une, ferme, d'où `flex: 1` et `min-height: 0` (sans lequel un élément
     flexible refuse de devenir plus petit que son contenu et ne défile pas). */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
#fiche-scroll > .fiche-cols { flex: 0 0 auto; }
#fiche-close {
  position: absolute;
  top: 0.55rem;
  inset-inline-end: 0.8rem;
  z-index: 2;
  background: none;
  border: none;
  color: var(--text-faint);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
}
#fiche-close:hover { color: var(--text); }

/*
 * ═══════════════════════════════════════════════════════════════════════════
 * LA LIGNÉE ENTRE DEUX PERSONNES — la fenêtre, et ce qu'elle porte.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Même logement et même mise en scène que la fiche étendue : elle se pose sur
 * le dessin, dans `#map-container`, et ne peut donc jamais recouvrir le volet
 * des réglages. Ce qui diffère, c'est la HAUTEUR — une chaîne de quarante noms
 * n'a pas besoin de tout l'écran, et une de trois encore moins : la fenêtre se
 * règle sur son contenu, plafonnée.
 */
#lign-veil {
  position: absolute;
  inset: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.6rem, 2.4vh, 2rem) clamp(0.6rem, 2.4vw, 2.4rem);
  background: color-mix(in srgb, var(--bg) 62%, transparent);
  cursor: default;
}
#lign-modal {
  position: relative;
  width: min(680px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.42);
  /* `#map-container` force `direction: ltr` pour les cartes : on la remet. */
  direction: ltr;
  text-align: left;
  padding: 1.5rem clamp(1rem, 3vw, 2rem) 1.2rem;
  animation: fiche-in 0.22s ease both;
}
body.rtl #lign-modal { direction: rtl; text-align: right; }
#lign-close {
  position: absolute;
  top: 0.55rem;
  inset-inline-end: 0.8rem;
  z-index: 2;
  background: none;
  border: none;
  color: var(--text-faint);
  font-size: var(--fs-5);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
}
#lign-close:hover { color: var(--text); }
#lign-title {
  margin: 0 2rem 0.2rem 0;
  font-family: var(--font-display);
  font-size: var(--fs-4);
  font-weight: 600;
  line-height: 1.25;
}
body.rtl #lign-title { margin: 0 0 0.2rem 2rem; }
.lign-sous {
  margin: 0 0 1rem;
  font-size: var(--fs-0);
  color: var(--text-muted);
}
.lign-reglages { margin-bottom: 1rem; }
.lign-reglages .sb-sublabel { margin-top: 0.7rem; }
/* La liste défile, le reste de la fenêtre ne bouge pas : c'est elle seule qui
   peut être longue. */
.lign-sortie {
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 0;
  flex: 1 1 auto;
  border-top: 1px solid var(--line-soft);
  padding-top: 0.9rem;
}
.lign-liste {
  margin: 0;
  padding-inline-start: 2.2rem;
  font-size: var(--fs-1);
  line-height: 1.7;
}
.lign-liste li { padding-inline-start: 0.2rem; }
/* Un maillon qui SAUTE des générations se voit : le mot le dit, et la puce
   pointillée le redit — c'est le même signe que le trait « descendant de ». */
.lign-liste li.saut { border-inline-start: 2px dotted var(--c-desc-link); margin-inline-start: -0.9rem; padding-inline-start: 0.7rem; }
.lign-mot {
  color: var(--text-muted);
  font-style: italic;
  font-size: var(--fs-0);
}
.lign-liste .lign-mot { margin-inline-end: 0.35rem; }
.lign-texte {
  margin: 0;
  font-size: var(--fs-1);
  line-height: 1.9;
}
.lign-pied { margin-top: 1rem; display: flex; justify-content: flex-end; }
.lign-copie {
  font: inherit;
  font-size: var(--fs-0);
  padding: 0.4rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  transition-property: color, background-color, border-color;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.lign-copie:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.lign-copie.copie-ok { border-color: var(--c-ululazm); color: var(--c-ululazm); }
/* L'invite d'un outil : ce qu'il faut savoir AVANT de remplir les champs. */
.tool-hint {
  margin: 0 0 0.6rem;
  font-size: var(--fs-0);
  color: var(--text-muted);
  line-height: 1.45;
}

/*
 * LE BOUTON QUI OUVRE LA FICHE AU LARGE — la seule ACTION du volet étroit.
 *
 * Il était une ligne de plus, aussi haute que les autres, dans une colonne qui
 * n'en compte que des lignes : on ne le voyait pas. Il prend donc de la
 * HAUTEUR — la marque au-dessus, l'intitulé en dessous —, ce qui lui donne la
 * silhouette d'un bouton et non celle d'une mention. Le dessin y gagne
 * l'espace d'être lu : à vingt-huit pixels et à l'encre pleine, la silhouette
 * du personnage se reconnaît, ce qui n'était pas le cas à dix-neuf.
 */
#fiche-open-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.42rem;
  width: 100%;
  margin-top: 0.9rem;
  padding: 0.85rem 0.7rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-raised);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
/* PLUS GRANDE QUE L'INTITULÉ, ET À L'ENCRE BRUNE. Le dessin porte le sens —
   c'est une PERSONNE qu'on ouvre —, il doit donc se lire avant le mot. Le noir
   du texte en faisait un caractère de plus dans une colonne qui n'en manque
   pas ; `--gold-ink` est le brun du site, celui de la marque et des liens
   ouverts, et il dit : ceci se clique. */
#fiche-open-btn svg {
  width: 28px; height: 28px;
  flex: none;
  fill: none; stroke: var(--gold-ink); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
#fiche-open-btn:hover svg { stroke: currentColor; }
#fiche-open-btn:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }

/* --- l'en-tête : le nom, le surnom, les tags, la date et la source --- */
.fiche-head { padding-inline-end: 2rem; margin-bottom: 1.3rem; }
.fiche-titles {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.2rem 1rem;
}
.fiche-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.6rem, 3.2vw, 2.2rem);
  line-height: 1.15;
}
/* L'écriture arabe est relevée d'un vingtième partout où elle porte un NOM :
   à corps égal elle se lit plus petite que la latine, sa hauteur utile se
   jouant sur la ligne médiane. Les versets, eux, ne bougent pas — ils sont
   déjà écrits au large. */
.fiche-head h2.as-arabic { font-family: var(--font-arabic); direction: rtl; font-size: clamp(1.68rem, 3.36vw, 2.31rem); }
.fiche-ar { margin: 0; font-size: clamp(1.57rem, 3.15vw, 2.1rem); }
.fiche-nick {
  margin: 0.35rem 0 0;
  color: var(--text-muted);
  font-style: italic;
  font-size: var(--fs-3);
}
/* Chaque donnée est ANNONCÉE : « Tags », « Date de naissance », « Source ».
   Une liste de définitions, parce que c'en est une. */
.fiche-meta {
  display: flex; flex-wrap: wrap;
  gap: 0.5rem 2rem;
  margin: 0.85rem 0 0;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line-soft);
}
.fiche-meta-item { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
/* La source se cale au BORD OPPOSÉ de la fenêtre : c'est la provenance de tout
   ce qui précède, elle ne se lit pas dans la même foulée que la date et les
   tags. `margin-inline-start: auto` la pousse, la gouttière la sépare. */
.fiche-meta-src { margin-inline-start: auto; }
/* La rangée des tags : la même liste de définitions, mais seule sur sa ligne,
   en tête de la colonne de gauche. Elle n'a pas de filet — c'est celui de
   l'en-tête, juste au-dessus, qui sépare déjà. */
.fiche-tagline {
  margin: 0.7rem 0 1.2rem;
  padding-top: 0;
  border-top: none;
}
.fiche-tagline .panel-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; }
/* LE NOM COMPLET S'ANNONCE COMME LES AUTRES DONNÉES. Il portait un titre de
   section, au corps et à la police des titres : dans une colonne où « Tags »
   et « Date de naissance » sont de petits libellés, il se lisait comme le
   début d'un autre chapitre. Il prend donc la même règle — la même, et non sa
   copie : deux écritures de la même chose finissent par diverger. */
.fiche-meta dt, .nc-label {
  flex: 0 0 auto;
  color: var(--text-faint);
  font-size: var(--fs-00);
  letter-spacing: 0.09em;
  text-transform: uppercase;
}
.fiche-meta dt::after, .nc-label::after { content: " :"; }
body.rtl .fiche-meta dt::after, body.rtl .nc-label::after { content: " :"; }
/* IL OUVRE LA LIGNE DU NOM au lieu de la surmonter : posé dedans, il en prend
   le sens de lecture, et la marge est PHYSIQUE — la ligne latine est forcée en
   `ltr` même quand l'interface est en arabe (voir plus bas), une marge logique
   s'y poserait donc du mauvais côté. */
.nc-label { margin: 0 0.5rem 0 0; }
.fiche-meta dd { margin: 0; min-width: 0; }
.fiche-meta .panel-tags { margin: 0; }

/* --- les deux colonnes : la notice, puis la parenté ---
 *
 * DEUX RANGÉES, ET LA PARENTÉ LES ENJAMBE. Les tags occupaient auparavant une
 * rangée en travers de toute la fenêtre, et la parenté ne commençait qu'en
 * dessous : une colonne entière restait vide à droite des tags, et le titre
 * « Parenté » se retrouvait un cran plus bas que tout le reste. Les tags
 * rentrent donc dans la colonne de GAUCHE, et la parenté couvre les deux
 * rangées — elle démarre à leur hauteur.
 *
 * Les places sont écrites explicitement : sans cela le placement automatique
 * poserait la notice à droite des tags, là où va la parenté.
 *
 * LA SECONDE RANGÉE EST SOUPLE, ET C'EST INDISPENSABLE. Avec deux rangées
 * `auto`, la hauteur de la parenté — qui les enjambe — se RÉPARTIT entre
 * elles : la rangée des tags recevait la moitié de la liste des fils
 * d'Ibrāhīm ﵇ et la notice se retrouvait quatre cents pixels plus bas que les
 * tags qu'elle suit. Une rangée `1fr` absorbe seule tout le dépassement.
 */
.fiche-cols {
  display: grid;
  grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  gap: 0 clamp(1.4rem, 3vw, 2.6rem);
  align-items: start;
}
/* LA PLACE DE CHAQUE BLOC EST ÉCRITE, ET C'EST NÉCESSAIRE : un enfant de
   grille sans rangée déclarée se pose tout seul dans le premier creux venu.
   Le nom complet s'insère entre les tags et la notice — c'est ainsi qu'un
   recueil de nasab présente quelqu'un : on le nomme en entier, puis on
   raconte —, et la colonne de parenté couvre les trois rangées. */
.fiche-cols > .fiche-tagline { grid-column: 1; grid-row: 1; }
.fiche-cols > .fiche-nomcomplet { grid-column: 1; grid-row: 2; }
/* Ses noms suivent le nom complet, et pour la même raison : on achève de
   nommer quelqu'un avant de raconter sa vie. */
.fiche-cols > .fiche-noms { grid-column: 1; grid-row: 3; }
/* LE VERSET (ou le ḥadīth) A SA RANGÉE, au-dessus du titre « Informations » :
   c'est une parole d'un autre ordre que la notice, et non sa première ligne.
   Sans rangée écrite il serait allé se loger dans le premier creux venu. */
.fiche-cols > .fiche-verset { grid-column: 1; grid-row: 4; }
.fiche-cols > .fiche-notice { grid-column: 1; grid-row: 5; }
.fiche-cols > .fiche-parente { grid-column: 2; grid-row: 1 / span 5; }

/*
 * LE NOM COMPLET — la ligne d'abord, le détail ensuite.
 *
 * La ligne assemblée se lit d'un trait, comme un nom : c'est ce qu'on vient
 * chercher. Le petit tableau qui la suit dit lequel des cinq éléments est
 * lequel, ce qu'aucune ligne continue ne peut montrer — et il n'écrit que les
 * éléments connus, sans poser de tiret là où l'on ne sait rien.
 */
.fiche-nomcomplet { margin-bottom: var(--space-5); }
/* ELLE PREND L'ÉCRITURE DE LA NOTICE, et non celle des titres. Le nom complet
   se lit dans la même colonne que la biographie, à quelques centimètres
   d'elle : deux fontes à cette distance se lisent comme deux documents.
   ET SON CORPS EST CELUI DE LA NOTICE. Écrit plus gros qu'elle, il faisait un
   second titre sous le premier, alors que c'est une donnée parmi les autres —
   longue, certes, mais qui se lit comme la biographie qui la suit. */
.nc-ligne {
  margin: 0 0 0.3rem;
  font-family: var(--font-body);
  font-size: var(--fs-3);
  line-height: 1.5;
  color: var(--text);
  text-wrap: pretty;
}
/* Voir `.kicker` : une écriture arabe posée au corps d'une latine demande son
   propre interligne, ses hampes ayant besoin d'air. */
.nc-ligne.nc-ar {
  font-family: var(--font-arabic);
  direction: rtl;
  /* Un cran sous la ligne latine, comme elle : l'arabe garde sa marge propre
     (l'œil d'Amiri Quran est plus petit à corps égal). */
  font-size: 1.07rem;
  line-height: 1.9;
  color: var(--c-arabic);
  margin-bottom: 0.7rem;
}
.nc-parts {
  margin: 0;
  display: grid;
  /* Le libellé prend la largeur du plus long des cinq — « Nisbah » —, et les
     cinq valeurs s'alignent donc sur une seule colonne. */
  grid-template-columns: auto 1fr;
  gap: 0.28rem 0.9rem;
  font-size: var(--fs-1);
  line-height: 1.5;
}
.nc-item { display: contents; }
.nc-parts dt {
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.72rem;
  padding-top: 0.12em;
  white-space: nowrap;
}
.nc-parts dd { margin: 0; color: var(--text-muted); text-wrap: pretty; }
/* Le nasab est la matière même du site : chacun de ses maillons a sa fiche. */
.nc-lien { color: var(--text); text-decoration: none; border-bottom: 1px solid var(--line); }
.nc-lien:hover { color: var(--gold-ink); border-bottom-color: currentColor; }

/*
 * SES NOMS — UNE LIGNE PAR NOM, ET L'ARABE EN FACE.
 *
 * Trente et un noms : c'est le nombre qui commande la forme. Une grille de
 * trois colonnes — le nom, son arabe, ce qu'il veut dire — les aligne les uns
 * sous les autres, et l'œil descend la colonne de gauche sans lire le reste.
 * En prose on n'en retenait aucun.
 *
 * PAS DE PUCES. Ce sont des noms, pas des arguments : la puce ajoute un signe
 * par ligne et trente et un signes font un motif qu'on voit avant les noms.
 *
 * LES GROUPES SONT SÉPARÉS PAR LEUR RÉFÉRENCE, non par un filet : la ligne de
 * source dit déjà où l'un finit et où l'autre commence, et un trait de plus
 * découperait la liste en treize morceaux.
 */
.fiche-noms { margin-bottom: var(--space-5); }
.noms-groupe { margin-bottom: 0.85rem; }
/* LA GRILLE EST SUR LA LISTE, PAS SUR LA LIGNE. Une grille par ligne donne à
   chacune ses propres largeurs de colonne, et les arabes ne tombent plus les
   uns sous les autres : « محمد » commençait quinze pixels avant « الحاشر ».
   Portée par la liste, la colonne se règle sur le plus long du groupe et tout
   s'aligne — c'est ce que fait déjà `.nc-item` pour le nom complet. */
.noms-liste {
  margin: 0 0 0.2rem;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: auto auto 1fr;
  gap: 0.24rem 0.85rem;
  align-items: baseline;
  font-size: var(--fs-1);
  line-height: 1.5;
}
.nom-porte { display: contents; }
.nom-lat { color: var(--text); font-weight: 500; white-space: nowrap; }
/* Voir `.nc-ligne.nc-ar` : l'arabe posé au corps d'une latine garde son propre
   interligne et sa propre teinte, l'œil d'Amiri Quran étant plus petit. */
.nom-ar {
  font-family: var(--font-arabic);
  direction: rtl;
  font-size: 1.02rem;
  line-height: 1.85;
  color: var(--c-arabic);
  white-space: nowrap;
}
.nom-sens { color: var(--text-muted); text-wrap: pretty; }
/* Étroit, les trois colonnes ne tiennent plus : le sens passe sous le nom. */
@media (max-width: 560px) {
  .noms-liste { grid-template-columns: auto 1fr; }
  .nom-sens { grid-column: 1 / -1; }
}
/*
 * LE « + » REMONTE D'UNE GÉNÉRATION. Il se tient au BOUT de la chaîne, à la
 * place où le prochain aïeul viendra s'écrire : c'est ce qui dit ce qu'il fait
 * sans qu'on ait à l'expliquer. Il disparaît quand la chaîne s'arrête — au
 * premier « descendant de », où « ibn » deviendrait faux.
 */
.nc-plus {
  width: 17px; height: 17px;
  padding: 0;
  margin-inline-start: 0.2rem;
  vertical-align: baseline;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-faint);
  font-family: var(--font-body);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}
.nc-plus:hover { color: var(--gold-ink); border-color: var(--c-ululazm); }
/*
 * UN BOUTON COPIER PAR LIGNE, AU BOUT DE CELLE QU'IL COPIE.
 *
 * Réduit à son dessin : au bout d'un nom, le mot « Copier » se lisait comme un
 * morceau du nom. Le cadre a disparu avec lui — un bouton encadré posé dans le
 * fil d'une ligne de texte y fait une pastille, et l'on croit lire un tag.
 * L'intitulé reste dans l'infobulle et pour le lecteur d'écran, où il dit
 * laquelle des deux écritures ce bouton-ci prend.
 */
.nc-copie {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: baseline;
  width: 20px; height: 20px;
  margin-inline-start: 0.4rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: color var(--dur-teinte) var(--ease-vif);
}
.nc-copie svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round; }
.nc-copie:hover { color: var(--c-ululazm); }
/* Le bouton DIT ce qu'il a fait : sans réponse, on croit qu'il n'a pas marché
   et l'on clique trois fois. Sans mot à changer, c'est le dessin qui répond —
   le feuillet devient un crochet, et la couleur passe au vert. */
.nc-copie-fait { display: none; }
.nc-copie.copie-ok { color: var(--green-ink); }
.nc-copie.copie-ok .nc-copie-signe { display: none; }
.nc-copie.copie-ok .nc-copie-fait { display: inline; }
body.rtl .nc-ligne:not(.nc-ar) { direction: ltr; text-align: right; }
/* Le pli : un filet, posé sur le bord de la page de droite. La gouttière du
   `grid` le sépare de la notice — le filet ne doit PAS être ramené dedans par
   une marge négative, il viendrait alors buter contre le texte. */
.fiche-parente {
  padding-inline-start: clamp(1.2rem, 2.4vw, 2rem);
  border-inline-start: 1px solid var(--line-soft);
}
.fiche-notice .info-block { display: block; margin-bottom: 1rem; }
.fiche-notice { font-size: var(--fs-3); line-height: 1.62; }
/*
 * LE VERSET QUI OUVRE LA NOTICE.
 *
 * Même bloc que sur la page « Tags » — l'arabe, sa traduction, sa référence —,
 * et la même encre : celle de la catégorie, donc le vert du Qurʾān. Il se lit
 * comme une épigraphe et non comme un paragraphe de plus, d'où le filet sur le
 * bord et le fond à peine teinté.
 */
/* CE QU'ON LIT AU-DESSUS DE L'ENCADRÉ : « Le verset », « Le ḥadīth ». Les deux
   portent la même couleur — le vert du Qurʾān et de la Sunna —, et seule la
   ligne de référence, en bas et en petit, dirait lequel on lit. */
.fiche-verset-lbl {
  margin: 0 0 0.35rem;
  font-family: var(--font-display);
  font-size: var(--fs-0);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.fiche-verset .tip-cite {
  margin: 0 0 1.1rem;
  padding: 0.7rem 0.9rem;
  border-radius: 6px;
  background: color-mix(in srgb, var(--cite) 9%, transparent);
  border-inline-start: 3px solid color-mix(in srgb, var(--cite) 55%, transparent);
}
.fiche-verset .tip-verse {
  font-family: var(--font-arabic);
  direction: rtl;
  text-align: right;
  font-size: 1.3rem;
  line-height: 1.95;
  color: var(--text);
}
/* La traduction se lit dans le sens de la page, et non dans celui du verset. */
.fiche-verset .tip-trad {
  margin-top: 0.45rem;
  font-size: var(--fs-2);
  line-height: 1.55;
  color: var(--text);
}
.fiche-verset .tip-ref {
  margin-top: 0.35rem;
  font-size: var(--fs-0);
  font-style: italic;
  color: var(--text-muted);
}
/*
 * UNE CASE PAR RANGÉE, LES UNES SOUS LES AUTRES.
 *
 * Elles étaient deux par rangée, comme dans le volet étroit, pour que la
 * parenté d'un prophète à quinze enfants ne descende pas bien plus bas que sa
 * notice. Mais deux colonnes de cases dans une colonne de fiche donnent une
 * grille dans une grille, et le nom arabe n'y a plus la place de se ranger au
 * bord. Une seule colonne : chaque case tient sa ligne, le nom latin à gauche
 * et l'arabe à droite, comme dans le volet quand la case est seule. La classe
 * `single` dit exactement cela — c'est la même règle qui sert.
 */
.fiche-parente .kin { margin-bottom: 1rem; }

/* Les deux titres de colonne : de vrais titres, sans le tiret des étiquettes. */
.fiche-sec-title {
  margin: 0 0 0.7rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-4);
  letter-spacing: 0.01em;
  color: var(--text);
}

/* --- L'ARBRE RESTREINT : un panneau à part, sous la fiche ---
 *
 * On quitte la fiche et l'on entre dans l'arbre : le panneau prend TOUTE la
 * hauteur de la fenêtre, avec son propre cadre et son propre fond. C'est ce
 * qui en fait une interface distincte alors qu'elle suit immédiatement la
 * notice — sans cela, un dessin posé au fil du texte se serait lu comme une
 * illustration de plus.
 *
 * `height: 100%` et non `min-height` : le panneau doit valoir EXACTEMENT la
 * hauteur visible, ni moins (il resterait un bout de notice au-dessus) ni plus
 * (on défilerait encore après l'avoir atteint). Les marges négatives lui
 * rendent la largeur pleine que le rembourrage de la fenêtre lui prenait, et
 * la hauteur perdue leur est reprise par `calc`.
 */
.fiche-tree {
  /* Ce que le cadre de défilement prend sur les côtés : la marge négative doit
     lui rendre EXACTEMENT cela, sans quoi le panneau ne vaut pas la pleine
     largeur de la fenêtre. Ce n'est donc pas une valeur d'aspect, et c'est
     pourquoi elle se LIT sur le cadre plutôt que de s'écrire une seconde
     fois — la gouttière grandit avec le ruban du signet. */
  --rt-marge: var(--fiche-px);
  /*
   * LA MARGE AUTOUR DU CADRE, LA MÊME DES TROIS CÔTÉS.
   *
   * Elle valait `--rt-marge` sur les côtés (jusqu'à 38 px) et 1,2 rem en bas :
   * le dessin semblait poussé vers le bas d'un cadre aux bords inégaux. Elle
   * est désormais unique, et c'est la PLUS PETITE des deux qui l'emporte —
   * égaliser vers le haut aurait coûté vingt pixels de dessin, quand la
   * demande est justement d'en gagner.
   */
  --rt-bord: 1.2rem;
  /* Les marges négatives lui rendent la largeur ET la hauteur que le
     rembourrage de la fenêtre lui prenait : le panneau vaut alors PILE la
     hauteur visible, et non 93 % d'elle. Le filet du haut suffit à le séparer
     de la notice, aucune marge n'est nécessaire au-dessus. */
  margin: 1.8rem calc(-1 * var(--rt-marge)) calc(-1 * var(--fiche-pb));
  padding: 1.1rem var(--rt-bord) var(--rt-bord);
  /* SAUF DU CÔTÉ DU RUBAN. Ce panneau reprend la pleine largeur de la
     fenêtre, donc il repasse SOUS le signet : en défilant jusqu'à l'arbre,
     son titre se retrouvait derrière le ruban. C'est le seul endroit de la
     fiche qui sorte de la gouttière, et il est le seul à devoir la retrouver
     ici. Seize pixels sur mille : le dessin ne s'en aperçoit pas. */
  padding-inline-start: max(var(--rt-bord), var(--ruban-place));
  border-top: 1px solid var(--line);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  /* `flex-shrink: 0` avec la hauteur : un élément flexible se laisse comprimer
     par défaut dès que le contenu du cadre dépasse, et le panneau tombait à
     321 px sur 837. Il vaut EXACTEMENT la hauteur visible, ni plus ni moins. */
  flex: 0 0 auto;
  /* Les deux rembourrages du cadre de défilement sont NOMMÉS chez lui et
     relus ici : le pourcentage se rapporte à sa boîte de contenu, il faut donc
     les rajouter pour retomber sur la hauteur visible. Écrits en clair, ils
     mentaient dès qu'on touchait au rembourrage — d'où « il reste quelques
     pixels ». */
  height: calc(100% + var(--fiche-pt) + var(--fiche-pb));
  box-sizing: border-box;
}
/*
 * Le titre et l'outil sur une seule ligne, AU-DESSUS du cadre.
 *
 * ET L'OUTIL S'ÉCARTE DE LA CROIX DE FERMETURE. Le panneau de l'arbre vaut
 * exactement la hauteur visible : dès qu'on l'atteint en défilant, sa ligne de
 * titre se range sous le haut de la fenêtre — c'est-à-dire sous la croix, qui
 * est posée là en absolu et ne défile pas. Elle tombait sur le bouton de
 * téléchargement. Le retrait vaut ce que la croix occupe (32 px depuis
 * 0,8 rem du bord) plus un intervalle.
 */
.rt-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.7rem;
  padding-inline-end: 2.2rem;
}
.rt-title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-4);
  letter-spacing: 0.01em;
}
.rt-tool-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.36rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-raised);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-1);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.15s ease, color 0.15s ease;
  transition-property: color, background-color, border-color, box-shadow, transform;
  transition-duration: var(--dur-teinte);
  transition-timing-function: var(--ease-vif);
}
.rt-tool-btn svg {
  width: 15px; height: 15px;
  fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.rt-tool-btn:hover { border-color: var(--c-ululazm); color: var(--c-ululazm); }
.rt-frame {
  position: relative;
  flex: 1 1 auto;
  min-height: 12rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel);
  overflow: hidden;
}
.rt-svg {
  display: block;
  width: 100%;
  height: 100%;
  cursor: grab;
  /* Le dessin garde le sens de l'arbre complet : nom latin à gauche, arabe à
     droite, quelle que soit la langue de l'interface. */
  direction: ltr;
}
.rt-svg:active { cursor: grabbing; }
/* Les cases sont celles de l'arbre (`.card`) : rien à redéclarer, sinon
   qu'elles mènent quelque part et que le curseur le dit. */
.rt-node .card { cursor: pointer; }
.rt-node .card:hover { border-color: var(--c-ululazm); }
/*
 * CELLE DONT ON LIT LA FICHE NE PORTE AUCUNE MARQUE.
 *
 * Elle avait l'anneau doré de la carte sélectionnée, plus une ombre portée :
 * un halo de trois pixels autour d'une carte déjà au centre du dessin, dans un
 * arbre qui n'existe QUE pour elle. Le soulignement ne disait donc rien qu'on
 * ne sût déjà, et il alourdissait la seule carte qu'on regarde.
 *
 * Ne restent que les deux choses qui sont vraies : elle ne mène nulle part —
 * on y est —, et elle ne s'allume pas au survol.
 */
.rt-node .card.rt-moi { cursor: default; }
.rt-node .card.rt-moi:hover { border-color: var(--card-border); }
/* Le trait d'alliance : ROSE et SIMPLE pour une épouse, comme dans l'arbre.
   Une servante n'est pas une épouse — le même trait, mais en pointillé. */
.rt-frame .spouse-link, .at-stage .spouse-link { stroke-width: 1.6px; }
.rt-frame .spouse-link.servante { stroke-dasharray: 7 5; }
/*
 * L'ENCADRÉ DES LIENS — dans le coin du CADRE, non dans le dessin.
 *
 * Posé dans le SVG, le zoom l'emporterait avec l'arbre et il grandirait avec
 * lui. Le cadre est déjà `position: relative` et `overflow: hidden` : il n'a
 * rien à recevoir de plus. Le dessin garde le sens de l'arbre complet quelle
 * que soit la langue lue, l'encadré reste donc à gauche.
 */
.rt-legend {
  position: absolute;
  left: 0.7rem;
  bottom: 0.7rem;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.5rem 0.7rem;
  border-radius: 3px;
  border: 1px solid var(--line);
  background: var(--legend-bg);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
  font-size: var(--fs-1);
  color: var(--text);
  pointer-events: none;
}
.rt-legend .legend-item { gap: 0.5rem; }
.rt-none { color: var(--text-faint); font-style: italic; font-size: 0.9rem; }


/* ============================================================
   L'ATELIER — monter son propre arbre (onglet Outils)
   ============================================================ */
/*
 * IL PREND LA PAGE ENTIÈRE, et c'est pour cela qu'il a son onglet : on y
 * compose un dessin, et un dessin qu'on compose a besoin de place. La barre
 * reste en haut, le plateau prend tout ce qui reste.
 */
#view-tools { overflow: hidden; }
#view-tools.active { display: flex; }
/*
 * LE CONTENEUR QUI DÉFILE PREND TOUTE LA LARGEUR — et c'est ce qui permet de
 * défiler DEPUIS LES BORDS de l'écran.
 *
 * Le plateau avale la molette (c'est lui qui zoome), et la colonne de contenu
 * ne fait que 1 400 px : sur un grand écran, tout ce qui reste de chaque côté
 * n'appartenait à rien et la molette n'y faisait rien. La colonne est donc
 * portée par les ENFANTS, et le conteneur qui défile va d'un bord à l'autre.
 */
.at-inner {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: var(--space-6) 0 var(--space-5);
  min-height: 0;      /* sans quoi le plateau déborde au lieu de se contenir */
}
/*
 * CE QUI DÉFILE, ET CE QUI RESTE.
 *
 * Le titre et l'introduction se rangent quand on descend ; la barre, elle,
 * se colle en haut et ne part jamais — on ajoute une personne à tout moment.
 *
 * LE PLATEAU FAIT EXACTEMENT UN ÉCRAN MOINS LA BARRE. C'est ce qui rend le
 * défilement possible ET utile : le contenu dépasse d'exactement la hauteur du
 * fronton, et une fois descendu, le dessin occupe tout ce qui reste sous la
 * barre — sans un pixel de trop, qui l'aurait fait dépasser par le bas.
 * `--at-bar-h` est mesurée en JS : la barre se replie sur deux rangs en
 * fenêtre étroite, et une hauteur écrite en dur mentirait là.
 */
.at-defile {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  /* La barre collante doit pouvoir se coller AU BORD du conteneur : sans cela
     elle glisserait sous le fronton en gardant l'écart de la grille. */
  scrollbar-gutter: stable;
}
/* La colonne de lecture est portée par les enfants ; le fond de la barre
   collante, lui, doit couvrir toute la largeur pour masquer le dessin qui
   passe dessous — d'où un rembourrage calculé plutôt qu'une largeur. */
.at-head {
  width: min(1400px, 100%);
  margin-inline: auto;
  padding-inline: var(--space-5);
}
/* Le plateau est un CADRE : sa marge le rentre dans la colonne, un rembourrage
   l'aurait creusé et le dessin n'aurait plus touché son bord — l'encadré des
   liens, posé dans le coin, sortait à moitié du cadre. La formule est celle
   du rembourrage de la barre : les deux bords tombent au même endroit. */
.at-stage {
  margin-inline: max(var(--space-5), calc((100% - 1400px) / 2 + var(--space-5)));
}
/* Les mots à gauche, les préférences à droite : le fronton avait la moitié
   droite vide, et les réglages n'avaient nulle part où se montrer en entier. */
.at-head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-5); }
.at-head-mots { flex: 1 1 26rem; min-width: 0; }
.at-head h1 {
  margin: 0 0 var(--space-2);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: var(--fs-6);
  color: var(--text);
}
.at-help {
  margin: 0;
  max-width: 62ch;
  color: var(--text-muted);
  font-size: var(--fs-2);
  line-height: 1.6;
  text-wrap: pretty;
}
.at-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  position: sticky;
  top: 0;
  z-index: 7;
  /* Elle passe DEVANT le plateau quand on descend : sans fond, on verrait le
     dessin à travers les mots. Le fond va d'un bord à l'autre, le contenu
     reste dans la colonne de 1 400 px. */
  background: var(--bg);
  padding-block: var(--space-2);
  padding-inline: max(var(--space-5), (100% - 1400px) / 2 + var(--space-5));
}
/* Le bouton qui EMPORTE le dessin se range au bord opposé de ceux qui le
   composent : la marge automatique suit le sens d'écriture, l'arabe le met
   donc à gauche sans qu'on ait à l'écrire. */
#at-dl { margin-inline-start: auto; }
/* La liste de suggestions se pose SUR le plateau : sa boîte est donc le seul
   élément positionné du voisinage, et le plateau vient après elle dans le fil. */
.at-search { position: relative; flex: 1 1 18rem; max-width: 26rem; }
.at-search input {
  width: 100%;
  padding: 0.55rem 0.85rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
}
.at-search input:focus-visible { outline: 2px solid var(--c-ululazm); outline-offset: 1px; }
#at-sugg {
  position: absolute;
  z-index: 5;
  inset-inline: 0;
  top: calc(100% + 4px);
  max-height: 17rem;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: var(--ombre-2);
}
#at-sugg button {
  display: block;
  width: 100%;
  padding: 0.45rem 0.8rem;
  border: none;
  background: transparent;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
  text-align: start;
  cursor: pointer;
}
#at-sugg button:hover { background: var(--bg-raised); }
/* Ce qui est DÉJÀ dans l'arbre reste proposé — on peut le chercher pour
   vérifier qu'il y est — mais il s'annonce comme tel plutôt que de disparaître. */
#at-sugg button.deja { color: var(--text-faint); }
.at-count { color: var(--text-muted); font-size: var(--fs-1); }
.at-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  border-radius: 2px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-2);
  cursor: pointer;
  transition: color var(--dur-teinte) var(--ease-vif), border-color var(--dur-teinte) var(--ease-vif);
}
.at-btn:hover { color: var(--text); border-color: var(--c-ululazm); }
/* Le bouton d'action porte l'or au TRAIT, comme le sceau de l'accueil : le
   plein est gardé pour le survol, c'est-à-dire pour le moment où il agit. */
.at-btn-fort { color: var(--c-ululazm); border-color: var(--c-ululazm); font-weight: 600; }
.at-btn-fort:hover { background: var(--c-ululazm); color: var(--bg); }
.at-btn[disabled] { opacity: 0.45; cursor: default; }
.at-btn[disabled]:hover { color: var(--text-muted); border-color: var(--line); background: transparent; }
.at-ico { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

/*
 * LES PRÉFÉRENCES DE L'ATELIER — TOUTES VISIBLES, dans le fronton.
 *
 * Elles étaient dans un bouton dépliant : un geste de plus pour atteindre un
 * réglage qu'on vient justement régler, et rien ne disait ce qu'il contenait.
 * Le fronton avait la moitié droite vide ; elles s'y posent à plat, en deux
 * colonnes, et défilent avec lui quand on veut toute la place pour le dessin.
 */
.at-pref {
  flex: 1 1 22rem;
  min-width: 0;
  max-width: 34rem;
  padding: var(--space-3) var(--space-4) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-raised);
}
/*
 * LE TITRE DE L'ENCADRÉ EST UN FRONTON, pas une ligne de plus.
 *
 * Il portait la même petite capitale que les quatre rubriques : cinq titres
 * du même corps, et rien ne disait lequel commandait les autres. Un filet le
 * sépare de ce qu'il annonce, et les rubriques descendent d'un cran.
 */
.at-pref-titre {
  margin: 0 0 var(--space-3);
  padding-bottom: 0.4rem;
  border-bottom: 1px solid var(--line-soft, var(--line));
  font-family: var(--font-display);
  font-size: var(--fs-2);
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.01em;
}
/*
 * QUATRE RUBRIQUES, QUATRE BLOCS — jamais coupés.
 *
 * La grille remplace un écoulement en deux colonnes de texte, qui découpait
 * les rubriques n'importe où : « Nom arabe » se retrouvait seul dans la
 * colonne de droite, sous le titre du voisin, et l'on ne savait plus à quoi
 * il appartenait. Une case de grille par rubrique, et le compte de colonnes
 * suit la largeur disponible sans qu'aucune coupe soit possible.
 */
.at-pref-grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-3) var(--space-4);
  align-items: start;
}
.at-rub { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.at-rub-titre {
  margin-bottom: 0.15rem;
  font-size: var(--fs-00, 0.72rem);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
  line-height: 1.3;
}
/*
 * LES CASES SE FONT LÉGÈRES ICI, ET SEULEMENT ICI.
 *
 * `.ns-opt` est un CADRE : bord net, fond surélevé, ombre portée. Trois de
 * ces cadres empilés dans une rubrique, quatre rubriques côte à côte, et
 * l'encadré des préférences n'était plus qu'une grille de boîtes dont aucune
 * ne ressortait. Dans le volet de l'arbre le cadre garde son rôle — les cases
 * y sont seules de leur espèce ; dans l'atelier elles sont douze, et ce qui
 * les sépare suffit à les distinguer. Restent une teinte au survol et un
 * liseré à gauche quand la case est cochée : on lit d'un coup d'œil ce qui
 * est armé, sans compter douze bordures.
 */
.at-pref .ns-opt {
  padding: 0.3rem 0.45rem;
  border: none;
  border-inline-start: 2px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  box-shadow: none;
}
.at-pref .ns-opt:hover { background: var(--bg-raised-2); border-inline-start-color: transparent; }
.at-pref .ns-opt:has(input:checked) { border-inline-start-color: var(--c-ululazm); }
.at-pref .ns-opt:has(input:checked):hover { border-inline-start-color: var(--c-ululazm); }
/* Le segmenté et les pastilles respirent comme les cases qui les suivent. */
.at-pref .seg-full { margin-bottom: 0.15rem; }
.at-pref .bg-pills { margin-bottom: 0; }

/*
 * L'AXE DU TEMPS DE L'ATELIER — une colonne de dates, à gauche du plateau.
 *
 * Les rangées gardent l'écart qu'elles ont : une génération, une rangée. L'axe
 * n'échelonne donc rien, il NOMME — il écrit devant chaque rangée l'année où
 * elle se tient. Les repères sont posés par le code, en pixels d'écran, et
 * suivent le zoom comme les cases.
 */
.at-frise {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 92px;
  z-index: 4;
  pointer-events: none;
  overflow: hidden;
}
body.rtl .at-frise { left: auto; right: 0; }
.at-frise::before {
  content: "";
  position: absolute;
  inset: 0;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  background: linear-gradient(to right, var(--panel) 58%, transparent);
}
body.rtl .at-frise::before { background: linear-gradient(to left, var(--panel) 58%, transparent); }
.at-tick {
  position: absolute;
  inset-inline-start: 0;
  width: 100%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-00);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.at-tick span.at-tick-trait {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line);
}
body.rtl .at-tick { flex-direction: row-reverse; }
/* Le fond du plateau suit le réglage PROPRE À L'ATELIER, non celui de l'arbre :
   c'est tout l'objet de ces préférences séparées. */
.at-stage[data-fond="dots"] {
  background-image: radial-gradient(circle at 1px 1px, var(--fond-trait) 1px, transparent 0);
  background-size: var(--fond-pas) var(--fond-pas);
}
.at-stage[data-fond="papier"] {
  background-image: var(--fond-papier-tuile);
  background-size: 24px 24px;
}

/* LE PLATEAU. Mêmes réglages que le cadre de l'arbre restreint — c'est le même
   dessin, à la même structure, et l'export ne connaît que celle-là. */
.at-stage {
  position: relative;
  flex: 0 0 auto;
  height: calc(100% - var(--at-bar-h, 3.4rem) - var(--space-4));
  min-height: 22rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--panel);
  overflow: hidden;
}
.at-vide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  color: var(--text-faint);
  font-style: italic;
}
/*
 * LES BOUTONS SONT SOUS LA CASE, DANS SON `foreignObject`.
 *
 * Un `foreignObject` DÉCOUPE ce qui déborde : des boutons posés à cheval sur
 * le bord de la case auraient été rognés. La boîte est donc plus haute que la
 * carte de la rangée de boutons (`AT.outils`), et le placement en tient compte
 * — c'est la même hauteur qui entre dans le calcul des rangées.
 */
.at-wrap { display: flex; flex-direction: column; }
/* RANGÉS AU BORD, ET NON AU MILIEU : le trait qui descend d'un père part du
   bas de sa CARTE et traverse cette bande en son milieu. Centrés, les quatre
   boutons se trouvaient exactement sur son passage. */
.at-outils {
  display: flex;
  justify-content: flex-end;
  gap: 4px;
  padding-top: 5px;
}
.at-b {
  width: 21px; height: 21px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}
.at-b:hover { color: var(--c-ululazm); border-color: var(--c-ululazm); }
.at-b-off:hover { color: var(--c-mrca); border-color: var(--c-mrca); }
/* Un bouton qui n'a plus rien à faire s'éteint — Adam n'a pas de père, et le
   presser sans effet se lit comme un bouton cassé. */
.at-b[disabled] { opacity: 0.3; cursor: default; }
.at-b[disabled]:hover { color: var(--text-muted); border-color: var(--line); }
.at-stage .rt-legend { pointer-events: none; }

@media (max-width: 700px) {
  .at-inner { padding: var(--space-4) var(--space-3); }
  .at-search { flex: 1 1 100%; max-width: none; }
}


/* ============================================================
   CE QUI RESTE À SOURCER — la fenêtre de la liste
   ============================================================
 *
 * Elle est posée en `fixed` sur toute la page, et non dans le cadre de
 * l'arbre comme la fiche étendue : elle s'ouvre depuis le volet des réglages,
 * et doit pouvoir le recouvrir — sans quoi on lirait la liste par un hublot de
 * la largeur du dessin.
 *
 * C'est une LISTE DE TRAVAIL : quatre onglets, un compte par onglet, et des
 * lignes qui mènent quelque part. Elle n'emprunte pas la mise en page de la
 * fiche, qui est une lecture.
 */
#unsourced-veil {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(0.6rem, 3vh, 2.4rem) clamp(0.6rem, 3vw, 2.4rem);
  background: color-mix(in srgb, var(--bg) 62%, transparent);
}
#unsourced-veil[hidden] { display: none; }
#unsourced-modal {
  position: relative;
  /* LA FENÊTRE S'EST ÉLARGIE avec la vue d'ensemble : un beignet et son
     tableau côte à côte demandent plus que la largeur d'une liste de noms. */
  width: min(760px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  padding: 1.1rem 1.2rem 1.2rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.42);
  animation: fiche-in 0.22s ease both;
}
.uns-head { margin-bottom: 0.7rem; padding-inline-end: 2rem; }
.uns-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-5);
  color: var(--text);
}
.uns-sub { margin: 0.25rem 0 0; font-size: var(--fs-0); color: var(--text-muted); line-height: 1.45; }
#unsourced-close {
  position: absolute;
  top: 0.5rem;
  inset-inline-end: 0.7rem;
  min-width: 32px; min-height: 32px;
  display: flex; align-items: center; justify-content: center;
  border: none; background: none;
  color: var(--text-faint);
  font-size: var(--fs-5); line-height: 1;
  cursor: pointer;
}
#unsourced-close:hover { color: var(--text); }
/* Le compte de chaque rubrique est écrit DANS son onglet : c'est lui qui dit
   où le travail se trouve, et l'onglet vide se signale tout seul. */
#unsourced-tabs { flex: none; }
#unsourced-tabs button { padding: 0.34rem 0.3rem; font-size: var(--fs-0); }
.uns-cpt { opacity: 0.65; font-variant-numeric: tabular-nums; }
#unsourced-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-top: 0.6rem;
  scrollbar-width: thin;
}
/* Une ligne pleine largeur : le nom d'un côté, ce qui manque de l'autre. Elle
   se lit comme une entrée de registre et se clique comme un bouton — ce
   qu'elle est. */
.uns-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.8rem;
  width: 100%;
  padding: 0.4rem 0.5rem;
  border: none;
  border-bottom: 1px solid var(--line-soft);
  border-radius: var(--r-xs);
  background: none;
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-2);
  text-align: start;
  cursor: pointer;
}
.uns-row:hover { background: var(--bg-raised-2); }
/* Le nom prend la place qui reste : sans quoi, la pastille de source ajoutée
   à sa gauche le repoussait au bord opposé et la colonne des noms se lisait
   à droite. */
.uns-nom { flex: 1 1 auto; min-width: 0; }
/*
 * L'INTERTITRE DES GROUPES DE DATES.
 *
 * Il COLLE au premier nom de son groupe (aucune marge basse) et respire
 * au-dessus : c'est ce qui fait lire les cinq blocs comme cinq blocs, sans
 * qu'aucun filet ne soit nécessaire. `sticky` le garde à vue pendant qu'on fait
 * défiler une liste longue — l'intérêt d'un groupe est de savoir dans lequel on
 * se trouve.
 */
.uns-groupe {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  margin: 0.9rem 0 0;
  padding: 0.28rem 0.5rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--fs-00);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.uns-groupe:first-child { margin-top: 0; }
.uns-quoi { flex: none; color: var(--text-muted); font-size: var(--fs-0); }
/* Le bouton qui l'ouvre, au pied des jauges. */
/* ============================================================
   LA VUE D'ENSEMBLE — le premier onglet de la fenêtre de sourçage
   ============================================================
 *
 * Cinq blocs, chacun un titre et un dessin. Les jauges sont CELLES DU VOLET
 * (`.prg-*`), pas leur copie : elles gagnent seulement le pourcentage que la
 * largeur du volet ne permettait pas d'écrire.
 */
.av { display: flex; flex-direction: column; gap: 1.5rem; padding-bottom: 0.4rem; }
.av-bloc > h3 {
  margin: 0 0 0.7rem;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-2);
  color: var(--text);
}
.av-note {
  margin: 0.55rem 0 0;
  font-size: var(--fs-00);
  line-height: 1.5;
  color: var(--text-faint);
  text-wrap: pretty;
}
/* Le beignet à gauche, le détail chiffré à droite ; l'un sous l'autre quand la
   fenêtre n'a plus la largeur des deux. */
.av-duo {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 3vw, 1.8rem);
  flex-wrap: wrap;
}
.av-duo .av-table { flex: 1 1 300px; min-width: 0; }

/*
 * LE BEIGNET — un cercle dont on découpe le trait, et rien de plus.
 *
 * Le premier secteur doit commencer EN HAUT : sans la rotation d'un quart de
 * tour, un cercle SVG démarre à trois heures, et l'on lit le graphique en
 * partant du côté au lieu du sommet. Le trait est plat aux deux bouts — un
 * bout arrondi déborderait sur le secteur voisin et fausserait sa part.
 */
.av-beignet { position: relative; flex: none; width: 132px; height: 132px; }
.av-beignet svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.av-arc { fill: none; stroke-width: 17; }
.av-arc-fond { stroke: var(--line-soft); }
.av-beignet-mot {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1rem;
  pointer-events: none;
}
.av-beignet-mot b {
  font-family: var(--font-display);
  font-size: var(--fs-4);
  font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.av-beignet-mot i {
  font-style: normal;
  font-size: var(--fs-00);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Une ligne de détail : pastille, libellé, barre, compte. La barre part
   toujours du bord du texte, jamais du milieu de la ligne : c'est l'alignement
   de leurs départs qui rend deux longueurs comparables. */
.av-table { display: flex; flex-direction: column; gap: 0.34rem; }
.av-ligne {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: var(--fs-00);
  color: var(--text-muted);
}
.av-pastille { flex: none; width: 9px; height: 9px; border-radius: 50%; }
/* Assez large pour « Compte des générations », qui est le plus long des cinq
   libellés de date dans les trois langues — tronqué, il ne disait plus lequel
   des deux comptes on lit. */
.av-nom { flex: 0 0 9.2rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.av-track {
  flex: 1 1 auto; min-width: 40px;
  height: 6px;
  border-radius: 3px;
  background: var(--line-soft);
  overflow: hidden;
}
.av-fill { display: block; height: 100%; background: var(--gold-ink); border-radius: 3px; }
.av-num {
  flex: none;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  direction: ltr;
}
body.rtl .av-num { direction: rtl; }
.av-num i { font-style: normal; opacity: 0.85; }
/*
 * CHAQUE LIGNE MÈNE À SA LISTE. Un tableau qui donne un nombre sans donner les
 * noms s'arrête à mi-chemin. Au repos la ligne reste nue — c'est un tableau,
 * pas une rangée de boutons ; c'est le survol qui dit qu'elle mène quelque
 * part, comme les lignes de parenté du volet.
 */
.av-saut {
  width: 100%;
  padding: 0.12rem 0.3rem;
  margin-inline: -0.3rem;
  border: none;
  border-radius: var(--r-xs);
  background: none;
  font: inherit;
  text-align: start;
  cursor: pointer;
}
.av-saut:hover { background: var(--bg-raised-2); }
.av-saut:hover .av-nom { color: var(--gold-ink); }
.av-saut-jauge {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: start;
  cursor: pointer;
  border-radius: var(--r-xs);
}
.av-saut-jauge:hover { background: var(--bg-raised-2); }

/*
 * LA BARRE DE TRIS — une rangée de pastilles par question posée, et chacune
 * porte le NOMBRE qu'elle donnerait. On choisit en sachant ce qu'on va
 * trouver, au lieu de cliquer pour découvrir une liste vide ; une pastille
 * qui ne rendrait rien s'éteint sans disparaître, ce qui est déjà une réponse.
 * Elle reste EN VUE pendant qu'on fait défiler : le tri courant fait partie de
 * ce qu'on lit.
 */
.uns-tris {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.1rem 0 0.5rem;
  margin-bottom: 0.3rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line-soft);
}
.uns-tri { display: flex; flex-wrap: wrap; align-items: center; gap: 0.28rem; }
.uns-tri-lbl {
  flex: 0 0 auto;
  min-width: 6.5rem;
  color: var(--text-faint);
  font-size: var(--fs-00);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.uns-tri button {
  display: inline-flex; align-items: center; gap: 0.3rem;
  padding: 0.16rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: var(--fs-00);
  cursor: pointer;
}
.uns-tri button:hover { color: var(--text); border-color: var(--c-ululazm); }
.uns-tri button.active {
  color: var(--gold-ink);
  border-color: var(--c-ululazm);
  background: color-mix(in srgb, var(--c-ululazm) 12%, transparent);
}
.uns-tri button.vide { opacity: 0.42; }
/* La pastille de source de chaque ligne : la même que dans la colonne des
   filtres, pour qu'on retrouve l'une dans l'autre sans légende à apprendre. */
.uns-row .sm-dot { flex: none; align-self: center; }

@media (max-width: 560px) {
  .av-nom { flex-basis: 5.6rem; }
  .av-beignet { width: 108px; height: 108px; }
}

/* Le bouton du volet est SEUL — il n'ouvre plus un dépliant, il ouvre la
   fenêtre. Le chevron pointe donc vers la droite sans jamais tourner, et le
   nombre de ce qui reste se lit avant qu'on ait cliqué. */
.tool-seul { width: 100%; }
.tool-seul .uns-cpt {
  margin-inline-start: auto;
  padding-inline: 0.4rem;
  color: var(--gold-ink);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
  /* Une seule colonne : les places posées plus haut n'ont plus de sens, et
     laisseraient la parenté enjamber une rangée qui n'existe pas. On rend la
     grille à son placement automatique, et l'ordre du document décide. */
  .fiche-cols { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .fiche-cols > .fiche-tagline,
  .fiche-cols > .fiche-noms,
  .fiche-cols > .fiche-verset,
  .fiche-cols > .fiche-notice,
  .fiche-cols > .fiche-parente { grid-column: auto; grid-row: auto; }
  .fiche-parente {
    padding-inline-start: 0; margin-inline-start: 0;
    border-inline-start: none;
    margin-top: 1.4rem; padding-top: 1.2rem;
    border-top: 1px solid var(--line-soft);
  }
}

/* ============================================================================
 * PLANCHER DE QUALITÉ : LE CLAVIER ET LE MOUVEMENT.
 *
 * Ce n'est pas un choix esthétique, c'est ce qu'un site doit à qui ne se sert
 * pas d'une souris, ou à qui les animations donnent le vertige. Un anneau de
 * focus unique et visible sur les deux thèmes ; et, si le système demande
 * moins de mouvement, plus aucune transition ni animation nulle part.
 *
 * Ces deux règles restent EN FIN DE FEUILLE, et c'est leur place : la seconde
 * doit l'emporter sur toute transition déclarée plus haut, quelle qu'elle soit.
 *
 * L'ANNEAU EST UN SEUL OBJET. `:where()` ne pèse rien dans le calcul de
 * spécificité : cette règle ne fait que poser le défaut, et les trois champs
 * de saisie qui l'éteignaient par `outline: none` — la recherche, l'ancêtre
 * commun, la recherche de tags — le rallument chacun chez lui, juste après la
 * ligne qui l'éteint. Une bordure de 1 px qui change de couleur ne se voit pas
 * au clavier, et disparaît pour qui distingue mal les teintes ; le halo teinté
 * d'origine est conservé, il n'est simplement plus seul à porter l'indication.
 * ========================================================================= */
/* 9. La branche nue `:focus-visible` a été ajoutée : la feuille portait un
   SECOND anneau, en or, en tête de feuille, qui couvrait tout ce que la liste
   ci-dessous ne nomme pas. Il est retiré, et cette règle couvre désormais les
   deux cas — un seul anneau, une seule couleur, un seul endroit. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
:focus-visible {
  outline: 2px solid var(--c-select);
  outline-offset: 2px;
  border-radius: 3px;
}

/* CES DEUX BOUTONS GARDENT LEUR RAYON QUAND ILS SONT AU CLAVIER.
 *
 * L'anneau ci-dessus pose `border-radius: 3px` comme défaut, à la spécificité
 * de `:focus-visible` — (0,1,0). Un élément dont le rayon est écrit avec UNE
 * SEULE CLASSE pèse pareil, et perd l'égalité parce que l'anneau vient plus bas
 * dans la feuille. C'est le cas de ces deux-là, et d'eux seuls : tous les autres
 * boutons tiennent leur rayon d'un sélecteur plus lourd. */
.fold-btn:focus-visible, .nav-btn:focus-visible { border-radius: var(--r-sm); }


.sb-title:first-child, .tool-body > .sb-sublabel:first-child { margin-top: 0; }

/* ============================================================================
 * 11. LES MICRO-INTERACTIONS : L'APPUI SE VOIT.
 *
 * Un bouton qui change de couleur au survol ne dit rien à qui touche l'écran —
 * il n'y a pas de survol au doigt. L'ENFONCEMENT, lui, se voit partout. Le
 * dépôt a déjà ce geste sur les cartes (`--card-pressed`, une ombre interne
 * tombant du haut) ; on l'étend aux boutons de l'interface, sous une forme
 * plus légère : 1 px vers le bas, et rien d'autre.
 *
 * 100 ms. Un geste qui se répète mille fois par jour doit être court : au-delà,
 * il se met à retarder l'action au lieu de l'accompagner.
 * ========================================================================= */
.tool-btn, .fold-btn, .cross-op, .tagpick-nbtn, .mrca-go,
.mrca-clear, .rt-tool-btn, #fiche-open-btn, .cf-btn, .cta, .seg button,
.theme-toggle, .histo-btn, .nav-btn {
  transition-property: color, background-color, border-color, box-shadow, transform;
}
.tool-btn:active, .fold-btn:active, .cross-op:active,
.tagpick-nbtn:active, .mrca-go:active, .mrca-clear:active, .rt-tool-btn:active,
#fiche-open-btn:active, .cf-btn:active, .cta:active, .seg button:active,
.theme-toggle:active, .histo-btn:active {
  transform: translateY(1px);
  transition-duration: 0.09s;
}

/* ============================================================================
 * 14. LA SÉLECTION DE TEXTE : VERT ROYAL, ÉCRITURE BLANCHE.
 *
 * Le bleu système au milieu d'une page crème et or est la seule couleur de
 * l'écran que le site n'ait pas choisie. Un vert profond s'y substitue, plein
 * et non transparent : la même surbrillance sur les deux thèmes, et du blanc
 * dessus dans les deux cas — 8,4:1, donc parfaitement lisible pendant qu'on
 * fait glisser la souris.
 * ========================================================================= */
::selection { background: #14603a; color: #ffffff; }

/*
 * MOUVEMENT RÉDUIT — UN SEUL BLOC, ET LE DERNIER.
 *
 * La feuille en portait deux, à sept cent cinquante lignes d'écart et aux
 * effets différents : l'un coupait les animations, l'autre les ramenait à une
 * itération. Un seul les remplace, en dernier pour qu'il l'emporte, et il
 * laisse passer ce qui doit rester — le défilement devient instantané, il
 * n'est pas supprimé.
 */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  #skip-link { transition: none; }
}
