/* Style commun à toutes les pages : couleurs, typographie, boutons, formulaires. */

/* Polices servies par EasyShelter, plus par Google : voir polices/polices.css. */
@import url('/polices/polices.css');

/* Palette "Sauge" (défaut) — vert sombre et or, éditorial. */
:root {
  --stone: #E7E4DD;
  --stone-deep: #D8D4C9;
  --ink: #17251F;
  --ink-soft: #4A5A52;
  --plate: #D9A227;
  --plate-deep: #A87813;
  --paper: #FBFAF7;
  --line: rgba(23, 37, 31, .14);
  --rouille: #A13E1F;
  --rouille-fond: #F5E4DD;
  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;

  /* Arrondis et ombres partagés par toutes les palettes (2026-08-27,
     embellissement général demandé par l'utilisateur) — coins nets (2-3px)
     et fond plat remplacés par des coins doux et un léger relief, plus
     "logiciel moderne" que l'aspect très éditorial/imprimé d'avant. Pas de
     couleur de --ink dans les ombres : ça resterait cohérent visuellement
     avec les 12 palettes sans devoir en définir une par palette. */
  --radius: 12px;
  --radius-sm: 8px;
  --ombre-carte: 0 1px 2px rgba(0, 0, 0, .04), 0 4px 14px rgba(0, 0, 0, .06);
  --ombre-survol: 0 10px 26px rgba(0, 0, 0, .12);
  /* Les étiquettes en forme de pilule (tags, filtres) : rondes, ou nettes
     avec les coins droits. */
  --pastille: 999px;
}

:root, [data-polices-apercu="affiche"] {
  /* LES POLICES (2026-09-18) : trois rôles, que chaque ensemble remplit.
     « Affiche », ci-dessous, est celui d'origine : titres serrés en
     capitales, texte de livre. Les rôles :
       --police-titres      titres, nom du refuge, grands chiffres ;
       --police-etiquettes  étiquettes, boutons, en-têtes de tableau, menus ;
       --police-texte       le texte courant du site et de l'éditeur.
     Les réglages qui les accompagnent : capitales ou non, espacement des
     lettres (multiplicateur), graisse, et un facteur de taille — les
     polices non condensées sont plus larges, elles s'écrivent un peu plus
     petit pour tenir dans les mêmes colonnes. --titres-interligne-min
     laisse la place aux jambages des minuscules (p, q, g). */
  --police-titres: "Barlow Condensed", "Arial Narrow", sans-serif;
  --police-etiquettes: "Barlow Condensed", "Arial Narrow", sans-serif;
  --police-texte: "Newsreader", Georgia, serif;
  --titres-graisse: 700;
  --titres-graisse-moyenne: 600;
  --titres-casse: uppercase;
  --titres-taille: 1;
  --titres-interligne-min: 0;
  --titres-espacement: 1;
  --etiquettes-casse: uppercase;
  --etiquettes-espacement: 1;
  --etiquettes-taille: 1;
}

/* Tendre : tout en rondeurs, chaleureux. */
:root[data-polices="tendre"], [data-polices-apercu="tendre"] {
  --police-titres: "Nunito", "Trebuchet MS", sans-serif;
  --police-etiquettes: "Nunito", "Trebuchet MS", sans-serif;
  --police-texte: "Nunito", "Trebuchet MS", sans-serif;
  --titres-graisse: 800;
  --titres-graisse-moyenne: 700;
  --titres-casse: none;
  --titres-taille: .88;
  --titres-interligne-min: 1.1;
  --titres-espacement: 0;
  --etiquettes-casse: none;
  --etiquettes-espacement: 0;
  --etiquettes-taille: 1;
}
/* Élégant : titres à empattements, texte très lisible. */
:root[data-polices="elegant"], [data-polices-apercu="elegant"] {
  --police-titres: "Fraunces", Georgia, serif;
  --police-etiquettes: "Source Sans 3", "Segoe UI", sans-serif;
  --police-texte: "Source Sans 3", "Segoe UI", sans-serif;
  --titres-graisse: 700;
  --titres-graisse-moyenne: 600;
  --titres-casse: none;
  --titres-taille: .9;
  --titres-interligne-min: 1.1;
  --titres-espacement: 0;
  --etiquettes-casse: uppercase;
  --etiquettes-espacement: .6;
  --etiquettes-taille: .88;
}
/* Magazine : titres de couverture, texte simple. DM Serif Display n'existe
   qu'en une graisse : jamais de faux gras. */
:root[data-polices="magazine"], [data-polices-apercu="magazine"] {
  --police-titres: "DM Serif Display", Georgia, serif;
  --police-etiquettes: "DM Sans", "Segoe UI", sans-serif;
  --police-texte: "DM Sans", "Segoe UI", sans-serif;
  --titres-graisse: 400;
  --titres-graisse-moyenne: 400;
  --titres-casse: none;
  --titres-taille: .95;
  --titres-interligne-min: 1.1;
  --titres-espacement: 0;
  --etiquettes-casse: uppercase;
  --etiquettes-espacement: .6;
  --etiquettes-taille: .85;
}

/* Épuré : une seule police géométrique partout, sans aucun ornement — le
   jeu le plus neutre des six, celui qui fait « logiciel » plutôt que
   « papier ». Manrope est variable : ses graisses 400 à 800 tiennent dans
   un fichier. */
:root[data-polices="epure"], [data-polices-apercu="epure"] {
  --police-titres: "Manrope", "Helvetica Neue", sans-serif;
  --police-etiquettes: "Manrope", "Helvetica Neue", sans-serif;
  --police-texte: "Manrope", "Helvetica Neue", sans-serif;
  --titres-graisse: 800;
  --titres-graisse-moyenne: 700;
  --titres-casse: none;
  --titres-taille: .9;
  --titres-interligne-min: 1.1;
  --titres-espacement: -.3;
  --etiquettes-casse: uppercase;
  --etiquettes-espacement: .8;
  --etiquettes-taille: .85;
}
/* Classique : tout en empattements, titres à fort contraste et texte de
   livre. Le plus habillé des six ; à l'opposé exact d'Épuré. */
:root[data-polices="classique"], [data-polices-apercu="classique"] {
  --police-titres: "Playfair Display", Georgia, serif;
  --police-etiquettes: "Lora", Georgia, serif;
  --police-texte: "Lora", Georgia, serif;
  --titres-graisse: 700;
  --titres-graisse-moyenne: 600;
  --titres-casse: none;
  --titres-taille: .92;
  --titres-interligne-min: 1.1;
  --titres-espacement: 0;
  --etiquettes-casse: uppercase;
  --etiquettes-espacement: .5;
  --etiquettes-taille: .82;
}

/* LE RELIEF (2026-09-20, demande de l'utilisateur, qui cherchait un
   troisième réglage : « je me disais qu'on pourrait peut-être choisir le
   niveau d'ombre portée, donc soit des aplats, soit de l'ombre portée »).
   Un axe à part entière, et non un troisième niveau de coins : il change le
   caractère du site — aplats pour un rendu imprimé/éditorial, ombre
   marquée pour un rendu « application ».
   Tout passe par les deux variables que les seize palettes partagent, et
   chaque élément concerné porte déjà un filet (border: 1px solid
   var(--line)) : en aplats, une carte reste donc dessinée, elle ne se
   dissout pas dans le fond. « douce » est la valeur par défaut, celle de
   :root — il n'y a donc pas de bloc pour elle. */
:root[data-relief="aplats"] {
  --ombre-carte: none;
  --ombre-survol: none;
}
:root[data-relief="marquee"] {
  --ombre-carte: 0 2px 4px rgba(0, 0, 0, .06), 0 10px 28px rgba(0, 0, 0, .13);
  --ombre-survol: 0 18px 44px rgba(0, 0, 0, .2);
}

/* LES COINS (2026-09-18) : arrondis (par défaut) ou droits. Tout ce qui
   s'arrondit passe par ces trois variables. */
:root[data-coins="droits"] {
  --radius: 2px;
  --radius-sm: 2px;
  --pastille: 2px;
}

/* Palette "Noisette" — marron chaleureux, accent bleu franc et lumineux
   (complémentaires marron/bleu, l'accent doit rester clair pour bien
   ressortir sur l'encre sombre). */
:root[data-palette="noisette"] {
  --stone: #EFE6DA;
  --stone-deep: #E0D2BF;
  --ink: #3B2A20;
  --ink-soft: #6B5646;
  --plate: #4F97C7;
  --plate-deep: #35719D;
  --paper: #FFFDF9;
  --line: rgba(59, 42, 32, .14);
}

/* Palette "Marine" — bleu marine franc et saturé, accent ambre chaud. */
:root[data-palette="marine"] {
  --stone: #DCE6F0;
  --stone-deep: #C3D5E6;
  --ink: #0F3057;
  --ink-soft: #3D6A94;
  --plate: #D98E3F;
  --plate-deep: #B06F26;
  --paper: #FFFFFF;
  --line: rgba(15, 48, 87, .16);
}

/* Palette "Lin" — clair et aéré, encre neutre presque noire, accent
   terracotta rosé bien saturé pour un vrai contraste (l'ancienne version
   mariait deux tons trop proches en teinte et en clarté, peu lisible). */
:root[data-palette="lin"] {
  --stone: #F6F3ED;
  --stone-deep: #EAE4D8;
  --ink: #2E2B26;
  --ink-soft: #6B665C;
  --plate: #C1728A;
  --plate-deep: #9A5468;
  --paper: #FFFFFF;
  --line: rgba(46, 43, 38, .12);
}

/* Palette "Prairie" — vert frais et lumineux, accent terracotta. */
:root[data-palette="prairie"] {
  --stone: #E9EFE4;
  --stone-deep: #D6E1CC;
  --ink: #2E4A34;
  --ink-soft: #5C7A63;
  --plate: #C97B4A;
  --plate-deep: #A25F35;
  --paper: #FCFBF7;
  --line: rgba(46, 74, 52, .14);
}

/* Palette "Azur" — bleu ciel clair et lumineux, accent ambre doré. */
:root[data-palette="azur"] {
  --stone: #E4F0F5;
  --stone-deep: #CFE3EB;
  --ink: #1F5C73;
  --ink-soft: #4C8299;
  --plate: #E2A33E;
  --plate-deep: #BC831F;
  --paper: #FFFFFF;
  --line: rgba(31, 92, 115, .14);
}

/* Palette "Ardoise" — gris-bleu froid et sobre, accent ocre chaud. */
:root[data-palette="ardoise"] {
  --stone: #E4E9EB;
  --stone-deep: #CFD8DB;
  --ink: #2B3A42;
  --ink-soft: #57707B;
  --plate: #D9A441;
  --plate-deep: #B3812A;
  --paper: #FAFCFD;
  --line: rgba(43, 58, 66, .14);
}

/* Palette "Aubergine" — violet profond, accent corail chaud. */
:root[data-palette="aubergine"] {
  --stone: #EFE6EC;
  --stone-deep: #E1D0DB;
  --ink: #3D1F3A;
  --ink-soft: #7A5875;
  --plate: #E2825A;
  --plate-deep: #BD6540;
  --paper: #FFFBFA;
  --line: rgba(61, 31, 58, .14);
}

/* Palette "Cerise" — rouge bordeaux profond, accent vert sauge doux
   (complémentaires rouge/vert, à l'inverse de Sauge qui part du vert). */
:root[data-palette="cerise"] {
  --stone: #F2E6E9;
  --stone-deep: #E3CFD3;
  --ink: #5C2331;
  --ink-soft: #8C5A66;
  --plate: #6FA287;
  --plate-deep: #4F7D65;
  --paper: #FFFAFB;
  --line: rgba(92, 35, 49, .14);
}

/* Palette "Mousse" — vert olive monochrome, à partir de 3 couleurs
   fournies par l'utilisateur (2026-08-26) : #658158 (accent), #b2c1aa
   (fond clair), #fdfdfb (papier). Contrairement aux autres palettes, pas
   d'accent d'une teinte différente — tout reste dans le vert, volontaire.
   --ink dérivé (version plus sombre de #658158) car la couleur fournie,
   utilisée seule sur fond blanc, n'a pas assez de contraste pour du texte
   de lecture (~4.3:1, sous le seuil AA de 4.5:1) — #658158 reste utilisé
   tel quel pour --ink-soft, où ce contraste plus faible est acceptable
   (texte secondaire, jamais le texte principal).
   Retouché le 2026-08-26 (retour utilisateur : "trop vert sur vert",
   illisible sur la plaque nom d'adoptions.html et le menu actif de
   l'admin) : --plate était fixé à #658158, la même couleur que --ink-soft
   — or --plate sert aussi de FOND avec du texte --ink foncé par-dessus
   (voir .plaque et .lien-nav.actif dans style.css), et #658158 sur
   #3A4A30 ne donnait que ~2.2:1, illisible. --plate éclairci en
   conséquence (désormais un vert clair distinct de --stone, pas dérivé
   de #658158) ; --stone éclairci aussi (demande explicite, "le fond vert
   du site devrait être plus clair"). --ink et --ink-soft inchangés. */
:root[data-palette="mousse"] {
  --stone: #DCE6D3;
  --stone-deep: #C7D5BB;
  --ink: #3A4A30;
  --ink-soft: #658158;
  --plate: #C9D9C0;
  --plate-deep: #4B6142;
  --paper: #FDFDFB;
  --line: rgba(58, 74, 48, .14);
}

/* Palette "Iris" — indigo bleu-violet profond, accent turquoise clair.
   Ajoutée le 2026-09-10 (demande : passer à 12 palettes, "dans un autre
   style", harmonieuses). Choisie dans une famille de teintes encore
   inoccupée : aucune palette n'existait entre "Marine" (bleu 213°) et
   "Aubergine" (violet 306°), et aucun accent n'était turquoise — les
   accents existants sont presque tous or ou terre cuite. Indigo +
   turquoise reste une paire froide, donc harmonieuse, mais l'écart de
   clarté fait franchement ressortir l'accent.
   --plate volontairement clair : il sert AUSSI de fond avec du texte
   --ink par-dessus (plaque du nom sur adoptions.html, lien de menu actif
   de l'admin) — 5,75:1 ici. C'est exactement ce contraste-là qui avait
   obligé à retoucher "Mousse", voir juste au-dessus. */
:root[data-palette="iris"] {
  --stone: #E6E6F1;
  --stone-deep: #D4D4E6;
  --ink: #2A2C66;
  --ink-soft: #5B5D8E;
  --plate: #5FBEB2;
  --plate-deep: #2C7F76;
  --paper: #FCFCFF;
  --line: rgba(42, 44, 102, .14);
}

/* Palette "Brume" — gris perle à peine mauve, accent parme lumineux.
   Ajoutée le 2026-09-10 en même temps qu'"Iris". Seule palette quasi
   neutre du lot : "Lin" est un beige chaud et "Ardoise" un gris nettement
   bleu ; ici la saturation tombe à 9% côté encre, ce qui donne l'allure
   de logiciel sobre recherchée (voir [[architecture_app_web]]), et tout
   le caractère passe par l'accent parme — le seul violet en accent des
   12 palettes.
   --plate assez clair pour porter du texte --ink (4,31:1, voir .plaque
   et .lien-nav.actif) et --plate-deep assez sombre pour les liens sur
   --paper (6,52:1). */
:root[data-palette="brume"] {
  --stone: #ECEAF1;
  --stone-deep: #DBD8E4;
  --ink: #2C2B33;
  --ink-soft: #63616E;
  --plate: #A67ECB;
  --plate-deep: #71499E;
  --paper: #FDFCFF;
  --line: rgba(44, 43, 51, .14);
}

/* TROIS PALETTES DE PLUS (2026-09-19), pour arriver à quinze.
   Familles de teintes encore inutilisées par les douze autres : une base
   brique (aucune n'était terre cuite), une base olive (aucune n'était
   vert-jaune) et une base bleu-nuit avec un accent rose (les bases sombres
   existantes vont vers le vert, le brun ou l'indigo).
   Le contraste a été MESURÉ, pas jugé à l'œil : --plate sert de fond au
   lien de menu actif avec --ink par-dessus, donc le rapport encre/accent
   compte autant que encre/papier. Les trois sont au-dessus de 4,5 (seuil
   AA du texte courant) — l'accent d'« argile » a d'ailleurs été éclairci
   de #9CB8A6 à #A6C0AE pour passer de 4,34 à 4,76. */
:root[data-palette="argile"] {
  --stone: #F1E7E0;
  --stone-deep: #E2D3C9;
  --ink: #6B3A2A;
  --ink-soft: #8F6553;
  --plate: #A6C0AE;
  --plate-deep: #6E8F7B;
  --paper: #FFFCFA;
  --line: rgba(107, 58, 42, .16);
}

:root[data-palette="olivier"] {
  --stone: #EDEDDF;
  --stone-deep: #DCDCC8;
  --ink: #3A3D22;
  --ink-soft: #6A6D4C;
  --plate: #D4BC79;
  --plate-deep: #A08A4B;
  --paper: #FEFEF7;
  --line: rgba(58, 61, 34, .15);
}

:root[data-palette="nuit"] {
  --stone: #E6E9EC;
  --stone-deep: #D2D7DC;
  --ink: #1C2833;
  --ink-soft: #55616C;
  --plate: #E39AA4;
  --plate-deep: #B56A75;
  --paper: #FBFCFD;
  --line: rgba(28, 40, 51, .14);
}

/* Palette "Lagon" (2026-09-18, la seizième : quatre rangées de quatre dans
   la page Design) — sarcelle profond et corail, un accord que les quinze
   autres n'avaient pas. Encre sur papier 11,9 ; encre sur accent 4,9. */
:root[data-palette="lagon"] {
  --stone: #E2EFEC;
  --stone-deep: #CCE1DC;
  --ink: #0E3B43;
  --ink-soft: #3E6A70;
  --plate: #F08A5D;
  --plate-deep: #B85A30;
  --paper: #FBFDFD;
  --line: rgba(14, 59, 67, .14);
}

* { box-sizing: border-box; }

body {
  margin: 0 auto;
  background: var(--stone);
  color: var(--ink);
  font-family: var(--police-texte);
  font-size: 17px;
  line-height: 1.55;
  padding: 32px 20px 60px;
}

/* Les pages du site public (avec bandeau + en-tête pleine largeur) annulent
   le centrage par défaut de body, et le reportent sur .page-contenu à
   l'intérieur — sinon le bandeau et l'en-tête resteraient coincés dans la
   colonne centrée au lieu de s'étendre sur toute la largeur de l'écran. */
body.site-public { margin: 0; padding: 0; }

.page-contenu {
  max-width: 720px;
  margin: 0 auto;
  padding: 32px 20px 60px;
}

h1 {
  font-family: var(--police-titres);
  font-weight: var(--titres-graisse);
  text-transform: var(--titres-casse);
  letter-spacing: -.01em;
  font-size: calc(clamp(28px, 5vw, 40px) * var(--titres-taille));
  line-height: max(.95, var(--titres-interligne-min));
  margin: 0 0 6px;
}

h2 {
  font-family: var(--police-etiquettes);
  font-weight: 600;
  font-size: calc(15px * var(--etiquettes-taille));
  letter-spacing: calc(.1em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  color: var(--ink-soft);
  margin: 32px 0 12px;
}

a { color: var(--plate-deep); }

/* Lien de retour en haut de page */
.retour {
  display: inline-block;
  font-family: var(--police-etiquettes);
  font-size: calc(15px * var(--etiquettes-taille));
  letter-spacing: calc(.1em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  color: var(--ink-soft);
  text-decoration: none;
}
.retour:hover { color: var(--ink); }

/* Boutons */
button, .bouton {
  display: inline-block;
  font-family: var(--police-etiquettes);
  font-size: calc(15px * var(--etiquettes-taille));
  font-weight: 600;
  letter-spacing: calc(.08em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  padding: 10px 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
  transition: border-color .15s, color .15s, background .15s, box-shadow .15s, transform .15s;
}
button:hover, .bouton:hover { border-color: var(--ink); color: var(--ink); }

.bouton-principal, button[type="submit"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--stone);
  box-shadow: var(--ombre-carte);
}
.bouton-principal:hover, button[type="submit"]:hover {
  background: var(--plate-deep);
  border-color: var(--plate-deep);
  color: var(--paper);
  box-shadow: var(--ombre-survol);
  transform: translateY(-1px);
}

/* CARTES DE PALETTES (pages Design des refuges et de l'administration
   d'EasyShelter). Le nom au-dessus de la bande de couleurs, et centré
   (demande du 2026-09-11) : il sert de titre à l'échantillon, donc il se
   lit avant lui. */
/* Quatre par rangée, petites (2026-09-18, demande de l'utilisateur : la
   page Design s'est remplie, les cartes n'ont pas besoin d'être grandes
   pour se comprendre — le nom et les trois couleurs suffisent). */
.palettes { display: grid; gap: 10px; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 560px) { .palettes { grid-template-columns: repeat(2, 1fr); } }
.carte-palette {
  display: block; border: 2px solid var(--line); background: var(--paper);
  padding: 16px; cursor: pointer; text-align: center;
}
.carte-palette.choisie { border-color: var(--ink); }
.palettes .carte-palette { padding: 9px 10px 10px; }
.palettes .nom-palette { font-size: calc(13px * var(--etiquettes-taille)); }
.apercu { display: flex; height: 22px; margin-top: 7px; border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.apercu span { flex: 1; }
/* LES POLICES ET LES COINS, dans les pages Design (2026-09-18). Chaque
   carte montre un aperçu dans SES polices ([data-polices-apercu]), quel
   que soit l'ensemble de la page. Les coins : deux tuiles, chacune avec le
   petit dessin d'une carte et de son bouton. */
/* TROIS PAR LIGNE, donc six ensembles sur deux lignes (demande de
   l'utilisateur, 2026-09-20 : « fais en sorte que les six tiennent sur
   seulement deux lignes […] pour ne pas que ça prenne trop de place »).
   Deux colonnes sous 900 px, une seule sous 560 px : à trois, les aperçus
   deviendraient illisibles sur un écran étroit. */
.choix-polices { display: grid; gap: 14px; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .choix-polices { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .choix-polices { grid-template-columns: 1fr; } }
.carte-polices {
  /* En colonne, calée en haut : un bouton centre son contenu verticalement,
     et les cartes de hauteurs différentes ne s'alignaient plus. */
  display: flex; flex-direction: column; justify-content: flex-start; width: 100%; text-align: left;
  border: 2px solid var(--line); background: var(--paper);
  border-radius: var(--radius); padding: 16px; cursor: pointer; text-transform: none; letter-spacing: normal;
  font-family: var(--sans); font-weight: normal; color: var(--ink);
}
.carte-polices.choisie { border-color: var(--ink); }
.carte-polices:hover { border-color: var(--ink-soft); }
.carte-polices .nom-palette { display: block; margin-bottom: 10px; }
.apercu-polices { display: block; border-top: 1px solid var(--line); padding-top: 12px; }
.apercu-polices .apercu-titre {
  display: block; font-family: var(--police-titres); font-weight: var(--titres-graisse); text-transform: var(--titres-casse);
  font-size: calc(24px * var(--titres-taille)); line-height: max(1, var(--titres-interligne-min)); margin-bottom: 6px; color: var(--ink);
}
.apercu-polices .apercu-texte { display: block; font-family: var(--police-texte); font-size: 15px; line-height: 1.45; color: var(--ink-soft); margin-bottom: 10px; }
.apercu-polices .apercu-etiquette {
  display: inline-block; font-family: var(--police-etiquettes); font-weight: 600; font-size: calc(12px * var(--etiquettes-taille));
  letter-spacing: calc(.08em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse);
  border: 1px solid var(--line); border-radius: var(--pastille); padding: 2px 10px; color: var(--ink-soft);
}
.choix-coins { display: flex; gap: 12px; flex-wrap: wrap; }
.tuile-coins {
  display: flex; align-items: center; gap: 10px; border: 2px solid var(--line); background: var(--paper); border-radius: 10px;
  padding: 10px 14px; cursor: pointer; font-family: var(--sans); font-size: 14px; font-weight: 600; text-transform: none;
  letter-spacing: normal; color: var(--ink);
}
.tuile-coins.choisie { border-color: var(--ink); }
.mini-coins { flex: none; width: 38px; height: 28px; border: 2px solid currentColor; position: relative; color: var(--ink-soft); }
.mini-coins::after { content: ""; position: absolute; left: 6px; right: 14px; bottom: 5px; height: 6px; background: currentColor; }
.mini-coins.arrondis { border-radius: 10px; }
.mini-coins.arrondis::after { border-radius: 4px; }
.tuile-coins.choisie .mini-coins { color: var(--ink); }
/* Coins et relief sur la MÊME ligne (2026-09-20) : deux réglages de la même
   famille, et zéro hauteur de page en plus. Ils se replient l'un sous
   l'autre quand la place manque. */
.ligne-coins-relief { display: flex; flex-wrap: wrap; gap: 8px 36px; align-items: flex-start; }
.ligne-coins-relief > div { min-width: 0; }
/* Le dessin d'un niveau de relief : une carte en réduction, portant
   l'ombre qu'elle annonce. */
.mini-relief {
  flex: none; width: 38px; height: 28px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 8px;
}
/* Les ombres des dessins sont RESSERRÉES par rapport aux vraies : à 38 px
   de large, l'ombre douce du site ne se verrait pas du tout, et les trois
   tuiles se ressembleraient. Elles disent la différence, pas la mesure. */
.mini-relief.douce { box-shadow: 0 1px 2px rgba(0, 0, 0, .10), 0 3px 6px rgba(0, 0, 0, .12); }
.mini-relief.marquee { box-shadow: 0 2px 3px rgba(0, 0, 0, .14), 0 6px 12px rgba(0, 0, 0, .24); }
.design-section { margin-top: 36px; }

.nom-palette { font-family: var(--police-etiquettes); font-weight: 600; letter-spacing: calc(.04em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); font-size: calc(15px * var(--etiquettes-taille)); }

/* ADMINISTRATION D'EASYSHELTER (2026-09-18) : ce qu'elle fait voir dans
   le panneau des refuges. Le bandeau de consultation en lecture seule,
   tout en haut, impossible à manquer ; le message à tous les refuges, en
   tête du contenu, qu'on peut fermer. */
.bandeau-consultation {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px 14px;
  padding: 10px 16px; background: var(--plate); color: var(--ink);
  font-family: var(--sans); font-size: 14px; font-weight: 600;
}
.bandeau-consultation form { margin: 0; }
.bandeau-consultation button { padding: 6px 12px; font-size: 13px; }
.message-plateforme {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  background: var(--paper); border: 1px solid var(--line); border-left: 4px solid var(--plate-deep);
  border-radius: var(--radius-sm); padding: 12px 14px; margin-bottom: 16px;
  font-family: var(--sans); font-size: 14px; line-height: 1.5; white-space: pre-line;
}
.message-plateforme .fermer-message {
  flex-shrink: 0; border: none; background: none; box-shadow: none; padding: 0 4px;
  font-size: 20px; line-height: 1; color: var(--ink-soft); cursor: pointer;
}
.message-plateforme .fermer-message:hover { color: var(--ink); }
@media print { .bandeau-consultation, .message-plateforme { display: none !important; } }

/* Tableaux de l'administration d'EasyShelter (refuges, comptes, journal). */
.table-admin { width: 100%; border-collapse: collapse; font-family: var(--sans); font-size: 14px; background: var(--paper); border: 1px solid var(--line); margin-top: 16px; }
.table-admin td.quand { white-space: nowrap; }
.table-admin th, .table-admin td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.table-admin th { font-family: var(--police-etiquettes); font-weight: 600; font-size: calc(13px * var(--etiquettes-taille)); letter-spacing: calc(.06em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); color: var(--ink-soft); }
.table-admin tr:last-child td { border-bottom: none; }
.table-admin .petit { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.table-admin .vide-liste { font-style: italic; color: var(--ink-soft); }

/* JAMAIS DE TEXTE COLLÉ À UN ENCART (2026-09-18, demande de l'utilisateur,
   vérifiée page par page en mesurant les écarts dans le navigateur). Un
   encart posé à même la page a au moins 16 px au-dessus de lui : sous un
   sous-titre il n'en avait aucun, sous un titre de page 6. Après un titre
   de section (12 px), les marges se confondent et l'écart passe à 16.
   Même chose pour un message d'erreur qui apparaît sous le titre. */
.contenu .limite > .carte, .contenu .limite > [data-permission] > .carte { margin-top: 16px; }
.contenu h1 + #erreur:not(:empty), .contenu h1 + #message:not(:empty), #message-refuge:not(:empty) { margin-top: 16px; }

/* L'ŒIL DES CHAMPS DE MOT DE PASSE (2026-09-18, voir mot-de-passe.js).
   Le bouton se pose dans le champ, à droite ; le champ lui laisse la
   place. Les styles des boutons ordinaires sont annulés : c'est une icône,
   pas un bouton de formulaire. L'œil propre à Edge est masqué, sinon il y
   en aurait deux. */
.champ-mot-de-passe { position: relative; display: block; }
.champ-mot-de-passe input { padding-right: 44px; }
.champ-mot-de-passe .oeil {
  position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
  padding: 6px 8px; margin: 0; border: none; background: none; box-shadow: none;
  color: var(--ink-soft); line-height: 0; cursor: pointer;
}
.champ-mot-de-passe .oeil:hover { color: var(--ink); background: none; }
.champ-mot-de-passe .oeil svg { display: block; width: 18px; height: 18px; }
input::-ms-reveal { display: none; }

/* LE BOUTON QUI TERMINE UN FORMULAIRE EST CENTRÉ (2026-09-18, demande de
   l'utilisateur pour tout le site : « Enregistrer », « Ajouter », « Créer
   le rôle », « Changer le mot de passe », « Se connecter »…). Une seule
   règle plutôt qu'une par page : un formulaire ajouté demain en hérite,
   pourvu que le bouton le FERME (test/31 y veille).
   Limitée au contenu des pages et aux cartes des pages publiques : le
   « Déconnexion » de la barre latérale est lui aussi le dernier bouton de
   son formulaire, et doit rester à sa place. Un bouton enveloppé dans
   .actions-formulaire est centré par l'enveloppe. */
.contenu form > button[type="submit"]:last-child,
.carte form > button[type="submit"]:last-child { display: block; margin-left: auto; margin-right: auto; }
.actions-formulaire { text-align: center; margin-top: 20px; }

/* Formulaires */
input, select, textarea {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  font-family: var(--sans);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink);
  transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--plate-deep);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, .06);
}
/* L'attribut « hidden » doit l'emporter, et sans lui c'est faux (2026-09-16).
   La feuille du navigateur pose « [hidden] { display: none } », mais toute
   règle d'AUTEUR la bat, y compris « label { display: block } » juste en
   dessous : un <label hidden> restait donc parfaitement visible. Le piège
   avait déjà été rencontré sur les pastilles de filtre de la page Animaux,
   corrigé là-bas au cas par cas (.filtre-etiquette[hidden]) ; on le règle
   ici une fois pour toutes.
   « !important » est ici à sa place : « hidden » signifie « cet élément
   n'est pas pertinent », ce n'est pas une préférence de mise en page. */
[hidden] { display: none !important; }

/* AUCUN champ numérique n'a de flèches (2026-09-17).
   Elles ne gênaient pas, mais elles ne servaient à rien : personne ne
   compose le coût d'une facture de vétérinaire à 0,01 € par clic, ni ne
   monte une température à 24 en vingt-quatre clics. Du superflu, donc.
   Sur le registre météo elles étaient carrément nuisibles : cliquer sur la
   flèche du haut fait apparaître les badges de code d'action, la cellule
   s'élargit, et comme la rangée est centrée tout glisse vers la gauche — le
   clic suivant tombait à côté.
   Les champs restent en type="number" et ne deviennent PAS des champs
   texte : c'est le type qui fait apparaître le pavé numérique sur un
   téléphone, et les bénévoles saisissent beaucoup au téléphone. Seuls les
   boutons partent.
   Trois syntaxes, et il en faut bien trois : WebKit passe par des
   pseudo-éléments, Firefox veut « textfield ». Il en manque une et les
   flèches reviennent sur un navigateur sans qu'on s'en aperçoive. */
/* ONGLETS (2026-09-19).
   Deux blocs qui parlent de la même chose, dont un seul sert au quotidien :
   la liste des rôles s'utilise tous les jours, « créer un rôle » deux ou
   trois fois dans la vie du refuge. Les afficher tous les deux en
   permanence allongeait la page pour rien — remarque de l'utilisateur.
   L'état vit dans aria-selected, et la CSS s'accroche au MÊME attribut :
   une classe de plus à tenir d'accord avec lui finirait par mentir sur
   l'onglet réellement ouvert. Même principe que les pastilles de filtre de
   la page Animaux (aria-pressed).
   Le trait sous la barre et l'onglet ouvert qui l'interrompt : c'est ce qui
   fait lire les deux boutons comme deux faces d'un même bloc, et non comme
   deux actions indépendantes. */
.onglets {
  display: flex; gap: 4px; flex-wrap: wrap;
  margin: 26px 0 0;
  border-bottom: 1px solid var(--line);
}
.onglet {
  font-family: var(--police-etiquettes);
  font-size: calc(15px * var(--etiquettes-taille)); font-weight: 600; letter-spacing: calc(.06em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse);
  padding: 9px 14px; margin-bottom: -1px;
  border: 1px solid transparent; border-bottom-color: var(--line);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: none; color: var(--ink-soft); cursor: pointer; width: auto;
}
.onglet:hover { color: var(--ink); background: rgba(0, 0, 0, .03); }
.onglet[aria-selected="true"] {
  color: var(--ink);
  border-color: var(--line);
  border-bottom-color: var(--paper);
  background: var(--paper);
}
/* Le panneau prolonge l'onglet ouvert : pas de marge haute, sinon le trait
   et le contenu se décollent et l'ensemble ne se lit plus comme un bloc. */
.panneau-onglet { margin-top: 18px; }

/* Bouton de SUPPRESSION (2026-09-19, remonté ici depuis roles.html).
   La même déclaration était recopiée dans cinq pages — modifier,
   soin-modifier, evenement-modifier, gestion (sous le nom .danger) et
   roles — et manquait justement là où l'utilisateur l'a réclamée : sur les
   deux pages d'événements, où « Supprimer » avait l'air d'un bouton
   ordinaire.
   Contour rouille au repos, rempli au survol : un bouton destructeur se
   signale sans hurler. */
.bouton-supprimer { border-color: var(--rouille); color: var(--rouille); font-size: 12px; padding: 4px 9px; }
.bouton-supprimer:hover { background: var(--rouille); border-color: var(--rouille); color: #fff; }

/* CHAMPS GROUPÉS PAR RANGÉE (2026-09-18, remonté ici depuis les pages).
   Les formulaires du logiciel posaient un champ par ligne sur toute la
   largeur, pour des mots de cinq lettres : « Sexe », « Espèce », une date.
   Les pages devenaient interminables, surtout au téléphone où l'on fait
   déjà beaucoup défiler.
   La règle vit ici et non dans chaque page : cinq formulaires s'en servent
   (ajout et fiche d'un animal, mouvement, soin, événement), et une sixième
   page qui la recopierait finirait par en diverger.
   L'écart vertical vient de la marge propre à chaque <label>, d'où un
   row-gap nul : les doubler creuserait un trou entre les rangées. */
.rangee { display: grid; column-gap: 16px; row-gap: 0; }
.rangee-2 { grid-template-columns: repeat(2, 1fr); }
.rangee-3 { grid-template-columns: repeat(3, 1fr); }

/* UNE colonne sur téléphone. Trois champs côte à côte dans les 328 px
   utiles d'un écran de 360 seraient illisibles, et un champ de date réclame
   à lui seul près de 130 px. « screen and » comme partout ici : les
   registres s'impriment. */
@media screen and (max-width: 560px) {
  .rangee-2, .rangee-3 { grid-template-columns: 1fr; }
}

input[type="number"] {
  appearance: textfield;
  -moz-appearance: textfield;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

label {
  display: block;
  margin-bottom: 16px;
  font-family: var(--police-etiquettes);
  font-size: calc(14px * var(--etiquettes-taille));
  letter-spacing: calc(.06em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  font-weight: 600;
  color: var(--ink-soft);
}
label input, label select, label textarea {
  margin-top: 6px;
  font-family: var(--sans);
  text-transform: none;
  letter-spacing: normal;
  font-weight: normal;
  color: var(--ink);
}

/* Case à cocher : la règle générale input{width:100%} l'étirerait sinon
   sur toute la largeur du formulaire. */
label.case {
  display: flex;
  align-items: center;
  gap: 8px;
  text-transform: none;
  letter-spacing: normal;
  font-weight: normal;
  font-family: var(--sans);
  font-size: 15px;
  color: var(--ink);
}
label.case input[type="checkbox"] {
  width: auto;
  margin: 0;
  padding: 0;
}
/* Pages légales d'EasyShelter (2026-09-18) : confidentialité, conditions
   d'utilisation, mentions légales. Palette par défaut : ce sont des pages
   de la plateforme, pas du site d'un refuge. */
.page-legale { max-width: 760px; margin: 0 auto; padding: 40px 20px 60px; font-family: var(--sans); color: var(--ink); line-height: 1.6; }
.page-legale .marque-legale { font-family: var(--police-titres); font-weight: var(--titres-graisse); letter-spacing: calc(.08em * var(--titres-espacement)); text-transform: var(--titres-casse); text-decoration: none; color: var(--ink); }
.page-legale h1 { margin: 18px 0 6px; }
.page-legale .mise-a-jour { color: var(--ink-soft); font-size: 14px; margin: 0 0 24px; }
.page-legale h2 { margin-top: 34px; }
.page-legale table { width: 100%; border-collapse: collapse; font-size: 14px; margin: 12px 0; }
.page-legale th, .page-legale td { text-align: left; vertical-align: top; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.page-legale th { font-family: var(--police-etiquettes); letter-spacing: calc(.06em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); font-size: calc(13px * var(--etiquettes-taille)); color: var(--ink-soft); }
/* Dans le site d'un refuge (2026-09-18), la page légale est déjà dans son
   cadre : pas de seconde marge autour. */
.page-legale.page-legale-refuge { padding: 0 0 20px; max-width: none; }

/* La ligne des liens légaux, en bas de toutes les pages publiques, des
   pages d'accès et des pages légales elles-mêmes. Centrée, comme tout le
   pied de page du site public (2026-09-18). */
.liens-legaux { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; margin: 16px 0 0; font-family: var(--sans); font-size: 13px; }
.liens-legaux a { color: var(--ink-soft); text-decoration: none; }
/* Sous l'encart des pages de connexion, d'inscription, de mot de passe…
   (2026-09-18, demande de l'utilisateur) : les liens légaux sortent de la
   carte, centrés dessous sur une seule ligne. Ils peuvent dépasser la
   colonne étroite de la page (380 px), jamais l'écran : au-delà, ils vont
   à la ligne. */
body > nav.liens-legaux {
  width: max-content; max-width: calc(100vw - 32px);
  position: relative; left: 50%; transform: translateX(-50%);
  margin-top: 20px; gap: 6px 18px;
}
@media (max-width: 420px) { body > nav.liens-legaux { font-size: 12px; gap: 6px 10px; } }
.liens-legaux a:hover { color: var(--ink); text-decoration: underline; }

/* Champ piège des formulaires publics (voir inscription.html) : hors de
   l'écran plutôt que display:none, que certains robots savent repérer. */
.piege { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }

/* Carte : conteneur utilisé pour les formulaires */
.carte {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--ombre-carte);
  padding: 28px;
}

/* Autocomplete générique (ex. commune d'origine, voir ajouter.html) : un
   champ texte + une liste de suggestions positionnée juste dessous. */
.autocomplete { position: relative; }
.autocomplete-suggestions {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 20;
  background: #fff; border: 1px solid var(--line); border-top: none;
  max-height: 220px; overflow-y: auto;
}
.autocomplete-suggestions button {
  display: block; width: 100%; text-align: left; padding: 8px 12px;
  border: none; border-radius: 0; background: none; font-family: var(--sans);
  font-size: 14px; letter-spacing: normal; text-transform: none; font-weight: normal;
  color: var(--ink); cursor: pointer;
}
.autocomplete-suggestions button:hover { background: var(--stone); }

/* Étiquette courte (ex : sexe, statut) */
.tag {
  display: inline-block;
  font-family: var(--police-etiquettes);
  font-size: calc(13px * var(--etiquettes-taille));
  letter-spacing: calc(.08em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  border: 1px solid var(--line);
  border-radius: var(--pastille);
  padding: 3px 11px;
  color: var(--ink-soft);
}

/* En-tête des pages de gestion */
.entete {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  flex-wrap: wrap;
  gap: 12px;
}

.erreur {
  background: var(--rouille-fond);
  color: var(--rouille);
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  font-family: var(--sans);
  font-size: 14px;
}

/* Confirmation positive (ex. mot de passe changé) — couleur fixe, comme
   .erreur, plutôt que dépendante de la palette choisie par le refuge. */
.succes {
  background: #E1F0E5;
  color: #2C6B3F;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  font-family: var(--sans);
  font-size: 14px;
}

/* Information neutre (ex. fin d'essai proche) — même gabarit que .erreur
   et .succes, sans l'alarme de la couleur. */
.info {
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--line);
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  font-family: var(--sans);
  font-size: 14px;
}
.bandeau-abonnement a { text-decoration: underline; white-space: nowrap; }
/* Jamais sur une feuille imprimée : un registre présenté lors d'un
   contrôle n'a pas à parler de l'abonnement du refuge. */
@media print { .bandeau-abonnement { display: none !important; } }

/* TITRE DE PAGE ET SON BOUTON PRINCIPAL SUR UNE MÊME LIGNE (2026-09-18,
   demande de l'utilisateur pour la page Animaux, reprise sur Pages du
   site) : « + Ajouter… » est l'action la plus importante de la page, elle
   se place à droite du titre plutôt qu'en tête de la barre d'outils. Le
   titre garde sa marge du bas d'origine (6 px). Sur un téléphone, le
   bouton passe sous le titre s'il n'a plus la place. */
.entete-page { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px 16px; }
.entete-page h1 { margin: 0; }
.entete-page .actions-entete { display: inline-flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.lien-import { font-family: var(--sans); font-size: 14px; color: var(--ink-soft); }
.lien-import:hover { color: var(--ink); }
/* L'ICÔNE DE RECADRAGE sur la vignette de couverture (2026-09-20, demande
   de l'utilisateur). En haut à GAUCHE, là où les autres vignettes portent
   leur ★ : deux boutons au même coin se recouvriraient. Elle est neutre —
   elle ne détruit rien, contrairement au ✕ rouille de la suppression — et
   se pose sur une pastille claire, sinon un trait sombre sur une photo
   sombre serait invisible. `.galerie button` la cadre déjà en position
   absolue ; on ne redit ici que ce qui change. */
.galerie button.bouton-cadrage {
  left: 4px; right: auto; padding: 4px; line-height: 0;
  border-color: var(--line); color: var(--ink-soft); background: rgba(255, 255, 255, .92);
}
.galerie button.bouton-cadrage svg { display: block; width: 14px; height: 14px; }
.galerie button.bouton-cadrage:hover,
.galerie button.bouton-cadrage.ouvert {
  background: var(--ink); border-color: var(--ink); color: #fff;
}

/* BOUTON « MODIFIER » EN CRAYON (2026-09-18, voir boutonModifier dans
   admin-commun.js). Seules les marges latérales sont fixées ici, avec un
   sélecteur assez précis pour l'emporter sur les « .xxx .bouton » des pages :
   la marge verticale reste celle des boutons voisins, si bien que le crayon
   (14 px, la hauteur d'une ligne de texte à 12 px) a exactement leur
   hauteur, dans une liste compacte comme sur la page Animaux. */
a.bouton.bouton-icone { padding-left: 8px; padding-right: 8px; line-height: 0; }
.bouton-icone svg { display: block; width: 14px; height: 14px; }

/* BULLES AU SURVOL (2026-09-18). .bulle : celle de la vignette de la page
   Animaux, placée par gestion.html ; .bulle-flottante : toutes les autres,
   placées par brancherBulles (admin-commun.js). Même apparence. */
.bulle, .bulle-flottante {
  width: max-content; max-width: 300px;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--ombre-survol);
  padding: 10px 12px;
  font-family: var(--sans); font-size: 13px; line-height: 1.45;
  font-weight: normal; letter-spacing: normal; text-transform: none; text-align: left; white-space: normal;
}
.bulle-flottante { position: fixed; z-index: 1000; pointer-events: none; }
/* LE CADRE À FAIRE GLISSER (2026-09-20) : la fenêtre 4/3 de la carte
   d'adoption, dans laquelle on déplace la photo pour choisir ce qui reste
   visible. Voir brancherCadrage (admin-commun.js).
   touch-action: none — sans lui, glisser au doigt ferait défiler la page
   au lieu de déplacer la photo. */
/* Le cadre est SEUL sous la galerie : la marge du bas était portée par la
   rangée de commandes qui l'accompagnait, retirée le 2026-09-20. */
.cadreur {
  position: relative; aspect-ratio: 4 / 3; max-width: 420px; overflow: hidden;
  background: var(--stone-deep); border: 1px solid var(--line); border-radius: var(--radius);
  cursor: grab; touch-action: none; user-select: none; margin: 0 0 14px;
}
.cadreur.en-glissement { cursor: grabbing; }
.cadreur:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.cadreur img { width: 100%; height: 100%; object-fit: cover; object-position: center top; display: block; pointer-events: none; }
/* L'aide s'effface pendant le geste : elle a dit ce qu'elle avait à dire. */
.cadreur-aide {
  position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%);
  background: rgba(0, 0, 0, .55); color: #fff; font-family: var(--sans); font-size: 12px;
  padding: 4px 10px; border-radius: var(--pastille); pointer-events: none; transition: opacity .15s ease;
}
.cadreur.en-glissement .cadreur-aide { opacity: 0; }

/* Ancrée en haut (2026-09-20) : voir .vue img dans adoptions.html. */
.bulle-flottante img { display: block; width: 180px; height: 135px; object-fit: cover; object-position: center top; border-radius: 6px; margin-bottom: 8px; }
.bulle-flottante .bulle-titre { font-weight: 600; }
/* Un logo n'est pas une photo : il tient entier dans sa boîte, sans rognure. */
.bulle-flottante img.logo-bulle { width: auto; height: auto; max-width: 180px; max-height: 110px; object-fit: contain; border-radius: 0; }
.bulle-flottante .bulle-note { margin-top: 4px; color: var(--ink-soft); }
.bulle-flottante .bulle-liste { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.bulle .non-renseigne, .bulle-flottante .non-renseigne { font-weight: normal; font-style: italic; color: var(--ink-soft); }
[data-bulle] { cursor: help; }
@media print { .bulle-flottante { display: none !important; } }

/* Bandeau tout en haut du site (appel aux dons, message important...).
   Élément direct de <body>, donc déjà pleine largeur : pas de trucage
   nécessaire, seul son contenu intérieur est recentré. */
.bandeau-haut { background: var(--ink); display: none; }
.bandeau-haut:has(a, span) { display: block; }
.bandeau-interieur {
  max-width: 1080px; margin: 0 auto; padding: 10px 20px;
  display: flex; justify-content: center; align-items: center;
}
.bandeau-haut a, .bandeau-haut span {
  font-family: var(--police-etiquettes);
  font-size: calc(14px * var(--etiquettes-taille)); letter-spacing: calc(.06em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); text-decoration: none;
}
.bandeau-haut span { color: var(--stone); }
.bandeau-haut a { color: var(--plate); }
.bandeau-haut a:hover { color: #fff; }

/* En-tête du site public : pleine largeur, collée en haut. Trois zones :
   nom/sous-titre à gauche, logo au centre, menu à droite. */
.entete-site { background: var(--stone); border-bottom: 1px solid var(--line); }
.entete-interieur {
  max-width: 1080px; margin: 0 auto; padding: 18px 20px;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 20px;
}
.marque-texte { display: flex; flex-direction: column; text-decoration: none; color: var(--ink); }
.nom-refuge {
  font-family: var(--police-titres); font-weight: var(--titres-graisse); font-size: calc(19px * var(--titres-taille));
  letter-spacing: calc(.1em * var(--titres-espacement)); text-transform: var(--titres-casse);
}
.sous-titre-refuge {
  font-family: var(--police-etiquettes); font-size: calc(12px * var(--etiquettes-taille)); letter-spacing: calc(.12em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse); color: var(--ink-soft);
}
.marque-logo { justify-self: center; }
.marque-logo img { height: 96px; width: auto; display: none; }
.nav-site { display: flex; gap: 22px; flex-wrap: wrap; justify-self: end; }
.nav-site a {
  font-family: var(--police-etiquettes); font-size: calc(14px * var(--etiquettes-taille)); letter-spacing: calc(.08em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse); color: var(--ink-soft); text-decoration: none;
}
.nav-site a:hover, .nav-site a.actif { color: var(--ink); }

@media (max-width: 640px) {
  .entete-interieur { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .marque-texte { align-items: center; }
}

.pied-site { border-top: 1px solid var(--line); margin-top: 60px; padding-top: 28px; text-align: center; }
/* Tout le pied de page centré (2026-09-18) : les liens des pages créées par
   le refuge, les logos des soutiens, puis la ligne des liens légaux. */
.pied-nav { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; margin-bottom: 20px; }
.pied-nav a { font-family: var(--sans); font-size: 14px; color: var(--ink-soft); text-decoration: none; }
.pied-nav a:hover { color: var(--ink); }

.bandeau-soutiens { margin: 24px 0; }
.bandeau-soutiens .titre {
  font-family: var(--police-etiquettes); font-size: calc(13px * var(--etiquettes-taille)); letter-spacing: calc(.1em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse); color: var(--ink-soft); margin-bottom: 12px;
}
.logos-soutiens { display: flex; gap: 24px; flex-wrap: wrap; align-items: center; justify-content: center; }
.logos-soutiens img { height: 40px; width: auto; filter: grayscale(1); opacity: .7; transition: opacity .15s, filter .15s; }
.logos-soutiens a:hover img { filter: grayscale(0); opacity: 1; }

/* Plus aucun lien dans cette ligne depuis le 2026-09-16 : le lien
   « Administration » a été retiré du site public (voir test/04). */
.copyright { font-family: var(--sans); font-size: 13px; color: var(--ink-soft); margin-top: 20px; }

/* Image flottante, utilisée dans le contenu riche (pages, annonces) et
   dans l'éditeur lui-même — classes génériques, pas limitées à un bloc.
   Largeur fixe et standardisée (280px) plutôt qu'un pourcentage : une
   photo envoyée en taille réelle (parfois énorme, depuis un téléphone)
   ne doit jamais pouvoir déborder ni dominer la mise en page.
   max-width:100% + height:auto en filet de sécurité sur petit écran, pour
   qu'elle rétrécisse plutôt que déborder si 280px est trop large. */
img.flottant-gauche, img.flottant-droite {
  width: 280px; max-width: 100%; height: auto; display: block; border-radius: var(--radius-sm);
}
img.flottant-gauche { float: left; margin: 6px 24px 18px 0; }
img.flottant-droite { float: right; margin: 6px 0 18px 24px; }

@media (max-width: 480px) {
  img.flottant-gauche, img.flottant-droite { float: none; width: 100%; margin: 0 0 16px; }
}

/* Contenu HTML d'une page éditoriale ou d'une annonce, produit par
   l'éditeur de texte (voir editeur.js). overflow:auto pour que les images
   flottantes ne débordent pas du bloc. */
.texte-page { margin-top: 20px; overflow: auto; }
/* LES MISES EN FORME COLLÉES D'AILLEURS (2026-09-18, demande de
   l'utilisateur) : un texte copié d'un ancien site garde sa police, sa
   taille, sa couleur et ses marges, écrites en dur sur chaque paragraphe
   — il ignorait le design choisi par le refuge. Le site et l'éditeur les
   ignorent désormais : gras, italique, souligné, liens et alignement
   restent. (L'éditeur les retire aussi du contenu, à l'enregistrement.) */
:is(.texte-page, .zone-editable) :is([style], font):not(h1, h2, h3, h4) {
  font-family: inherit !important; font-size: inherit !important; line-height: inherit !important;
  color: inherit !important; background-color: transparent !important; letter-spacing: inherit !important;
}
:is(.texte-page, .zone-editable) :is(h1, h2, h3, h4)[style] { font-family: var(--police-titres) !important; color: inherit !important; background-color: transparent !important; }
:is(.texte-page, .zone-editable) p[style] { margin: 0 0 16px !important; }
:is(.texte-page, .zone-editable) a[style] { color: var(--plate-deep) !important; }
.texte-page p { margin: 0 0 16px; }
.texte-page h2 {
  font-family: var(--police-titres); font-weight: var(--titres-graisse); text-transform: none;
  letter-spacing: normal; color: var(--ink); font-size: calc(26px * var(--titres-taille)); margin: 28px 0 12px;
}
.texte-page h3 {
  font-family: var(--police-titres); font-weight: var(--titres-graisse-moyenne); text-transform: none;
  letter-spacing: normal; color: var(--ink); font-size: calc(20px * var(--titres-taille)); margin: 22px 0 10px;
}
/* :not() ici est essentiel, pas décoratif : sans ça, cette règle a la
   même spécificité que "img.flottant-gauche" et gagne parce qu'elle est
   déclarée après dans la feuille de style — ce qui annulait purement et
   simplement la marge (20px) autour d'une image flottante, la collant au
   texte. Bug réel, vu le 2026-08-26. */
.texte-page img:not(.flottant-gauche):not(.flottant-droite) { max-width: 100%; display: block; margin: 0 auto 16px; border-radius: var(--radius-sm); }

/* L'encadré qui tient la place d'une carte tant que le visiteur ne l'a pas
   demandée (voir differerContenusExternes dans site-public.js). */
.contenu-externe {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  min-height: 160px; margin: 0 0 16px; padding: 20px; text-align: center;
  border: 1px dashed var(--line); border-radius: var(--radius-sm); background: var(--stone);
  font-family: var(--sans); font-size: 14px; color: var(--ink-soft);
}
.contenu-externe p { margin: 0; }
.carte-integree { width: 100%; height: 300px; border: 1px solid var(--line); border-radius: var(--radius-sm); display: block; margin: 0 0 16px; overflow: hidden; }
.texte-page a { text-decoration: underline; }

/* Barre d'outils de l'éditeur de texte enrichi */
.barre-editeur {
  display: flex; flex-wrap: wrap; gap: 4px;
  background: var(--stone-deep); border: 1px solid var(--line); border-bottom: none;
  padding: 8px; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.barre-editeur button {
  padding: 6px 10px; font-size: 13px; letter-spacing: normal; text-transform: none;
  font-family: var(--sans); font-weight: normal;
}
.zone-editable {
  background: #fff; border: 1px solid var(--line); border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  padding: 16px; min-height: 260px; font-family: var(--police-texte); font-size: 17px;
  /* L'écart d'un champ (celui des <label>) : sans lui, le bouton
     « Enregistrer » d'une annonce touchait le bas de l'éditeur. */
  margin-bottom: 16px;
  overflow: auto; /* sans ça, une image flottante plus haute que le texte
    déborde de la boîte au lieu de l'agrandir — c'est ce qui débordait */
}
.zone-editable:focus { outline: none; border-color: var(--plate-deep); }
/* Le rouge du texte du contrat d'adoption, seul éditeur où il est gardé
   (data-rouge, voir editeur.js) ; plus fort que la neutralisation des
   couleurs collées ci-dessus. */
.zone-editable .rouge, .zone-editable .rouge[style] { color: #d40000 !important; }

/* LA VISITE GUIDÉE (2026-09-18, variante « projecteur » choisie sur
   maquette) : un voile transparent retient les clics, le « trou » éclaire
   l'élément et assombrit tout le reste par son ombre, la bulle se place à
   côté (dessous, sinon dessus, sinon en bas de l'écran). Voir visite.js. */
.visite-voile { position: fixed; inset: 0; z-index: 9997; }
.visite-trou {
  position: fixed; z-index: 9998; pointer-events: none; border-radius: var(--radius-sm);
  box-shadow: 0 0 0 4px var(--paper), 0 0 0 9999px rgba(0, 0, 0, .45);
}
.visite-bulle {
  position: fixed; z-index: 9999; width: 340px; max-width: calc(100vw - 24px); box-sizing: border-box;
  background: var(--paper); color: var(--ink); border-radius: var(--radius); padding: 18px 20px 14px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, .25), 0 0 0 1px var(--line);
}
.visite-bulle::before {
  content: ''; position: absolute; left: calc(var(--fleche-x, 50%) - 7px); width: 14px; height: 14px;
  background: var(--paper); transform: rotate(45deg);
}
.visite-bulle[data-cote="dessous"]::before { top: -7px; box-shadow: -1px -1px 0 var(--line); }
.visite-bulle[data-cote="dessus"]::before { bottom: -7px; box-shadow: 1px 1px 0 var(--line); }
.visite-bulle[data-cote="sans-fleche"]::before { display: none; }
.visite-titre {
  font-family: var(--police-titres); font-weight: var(--titres-graisse); text-transform: var(--titres-casse);
  font-size: calc(20px * var(--titres-taille)); line-height: 1.15; margin: 0 0 8px;
}
.visite-texte { font-family: var(--sans); font-size: 14.5px; line-height: 1.5; margin: 0 0 14px; }
.visite-pied { display: flex; align-items: center; gap: 10px; }
.visite-points { display: flex; gap: 5px; margin-right: auto; }
.visite-points span { width: 7px; height: 7px; border-radius: 50%; background: var(--stone-deep); }
.visite-points span.actif { background: var(--plate-deep); }
.visite-bulle .visite-passer {
  background: none; border: none; box-shadow: none; padding: 6px 4px; font-family: var(--sans); font-size: 13px; font-weight: normal;
  color: var(--ink-soft); text-decoration: underline; text-transform: none; letter-spacing: normal;
}
.visite-bulle .visite-suivant { padding: 7px 16px; font-size: calc(13px * var(--etiquettes-taille)); }
/* Le bouton reçoit le focus à chaque bulle (clavier) : un contour aux
   couleurs du design plutôt que le bleu du navigateur. */
.visite-bulle button:focus-visible { outline: 2px solid var(--plate-deep); outline-offset: 2px; }
@media (max-width: 560px) { .visite-bulle { width: auto; left: 12px !important; right: 12px; } }
@media print { .visite-voile, .visite-trou, .visite-bulle { display: none !important; } }

/* LES FENÊTRES (2026-09-18) : <dialog> natif, ouvert par showModal(). La
   première : le contrat d'adoption, sur la page Entrées et sorties. */
dialog.dialogue {
  border: none; border-radius: var(--radius); padding: 24px 26px 20px; width: calc(100% - 32px); max-width: 460px;
  background: var(--paper); color: var(--ink); box-shadow: 0 24px 60px rgba(0, 0, 0, .28);
}
dialog.dialogue::backdrop { background: rgba(0, 0, 0, .38); }
.dialogue .titre-dialogue {
  font-family: var(--police-titres); font-weight: var(--titres-graisse); text-transform: var(--titres-casse);
  font-size: calc(24px * var(--titres-taille)); line-height: 1.15; margin: 0 0 12px;
}
.dialogue p { font-family: var(--sans); font-size: 15px; line-height: 1.5; margin: 0 0 12px; }
.dialogue .a-rediger { font-size: 14px; color: var(--rouille); background: var(--rouille-fond); border-radius: var(--radius-sm); padding: 10px 12px; }
.actions-dialogue { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 18px; }
/* Le récapitulatif d'une fenêtre de confirmation (2026-09-22) : libellé à
   gauche, valeur à droite, comme la fiche d'un refuge dans
   l'administration. Dans style.css et non dans une page : la fenêtre est
   fabriquée par confirmerAvantEnvoi (admin-commun.js) pour trois écrans —
   les soins, l'ajout d'un animal et les entrées/sorties. */
.recapitulatif {
  display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px;
  font-family: var(--sans); font-size: 15px; margin: 0 0 14px;
}
.recapitulatif dt { color: var(--ink-soft); }
.recapitulatif dd { margin: 0; }
/* Une image tout juste insérée, sans flottement choisi : bloc centré,
   propre par défaut, en attendant que la personne clique dessus pour
   choisir un côté (voir la barre-image-flottante ci-dessous). */
.zone-editable img:not(.flottant-gauche):not(.flottant-droite) { max-width: 100%; display: block; margin: 14px auto; border-radius: var(--radius-sm); }
.zone-editable img { cursor: grab; }
.zone-editable img.image-selectionnee { outline: 2px solid var(--plate-deep); outline-offset: 2px; }
.champ-cache { display: none; }

/* Petit outil contextuel qui apparaît au-dessus d'une image cliquée dans
   l'éditeur, pour choisir son flottement — voir editeur.js. */
.barre-image-flottante {
  position: absolute;
  display: none;
  gap: 2px;
  background: var(--ink);
  padding: 4px;
  border-radius: var(--radius-sm);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .28);
  z-index: 50;
}
.barre-image-flottante button {
  padding: 6px 11px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  background: none;
  border: none;
  color: var(--stone);
  border-radius: 2px;
  cursor: pointer;
}
.barre-image-flottante button:hover { background: rgba(255, 255, 255, .12); color: #fff; }
.barre-image-flottante button.actif { background: var(--plate); color: var(--ink); }

/* Coquille "logiciel" des pages de gestion : menu latéral + contenu.
   Annule le centrage/padding par défaut de body, comme .site-public le
   fait pour les pages publiques, sinon la barre latérale ne serait pas
   collée au bord de l'écran. */
body.app-body { margin: 0; padding: 0; }

.app { display: flex; min-height: 100vh; }

.barre-laterale {
  width: 220px;
  flex-shrink: 0;
  background: var(--ink);
  color: var(--stone);
  padding: 28px 20px;
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}
.barre-laterale .marque {
  font-family: var(--police-etiquettes);
  font-weight: 700;
  text-transform: var(--etiquettes-casse);
  letter-spacing: calc(.08em * var(--etiquettes-espacement));
  font-size: calc(15px * var(--etiquettes-taille));
  color: #fff;
  margin-bottom: 28px;
}
.barre-laterale .marque .nom-refuge-menu {
  display: block;
  font-weight: 500;
  text-transform: none;
  letter-spacing: normal;
  color: var(--stone);
  opacity: .7;
  font-size: 13px;
  margin-top: 4px;
}
/* « Voir le site public » sous le nom du refuge (2026-09-16) : il était
   en bas, contre « Déconnexion », qui reste seul dans le bas du menu. */
.barre-laterale .marque .retour {
  display: block;
  margin-top: 10px;
  font-size: calc(13px * var(--etiquettes-taille));
  font-weight: 500;
  letter-spacing: calc(.06em * var(--etiquettes-espacement));
  color: var(--stone);
  opacity: .7;
}
.barre-laterale .marque .retour:hover { opacity: 1; color: #fff; }
.barre-laterale nav { flex: 1; display: flex; flex-direction: column; gap: 4px; }

.lien-nav {
  font-family: var(--police-etiquettes);
  font-size: calc(15px * var(--etiquettes-taille));
  letter-spacing: calc(.06em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  color: var(--stone);
  opacity: .75;
  text-decoration: none;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
}
.lien-nav:hover { opacity: 1; background: rgba(255, 255, 255, .08); }
.lien-nav.actif { opacity: 1; background: var(--plate); color: var(--ink); }

/* display:block partout, plutôt que flex sur le <details> lui-même :
   certains navigateurs traitent <summary> comme une boîte spéciale qui ne
   se comporte pas bien en enfant flex, ce qui faisait apparaître deux liens
   sur la même ligne. Le flux bloc normal, avec chaque lien explicitement
   en display:block, ne laisse aucune ambiguïté. */
.groupe-nav { display: block; margin: 2px 0; }
.groupe-nav summary {
  display: block;
  font-family: var(--police-etiquettes);
  font-size: calc(15px * var(--etiquettes-taille));
  letter-spacing: calc(.06em * var(--etiquettes-espacement));
  text-transform: var(--etiquettes-casse);
  color: var(--stone);
  opacity: .75;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  list-style: none;
}
.groupe-nav summary::-webkit-details-marker { display: none; }
.groupe-nav summary:hover { opacity: 1; background: rgba(255, 255, 255, .08); }
.groupe-nav summary::after { content: '▸'; float: right; font-size: 12px; }
.groupe-nav[open] summary::after { content: '▾'; }
/* Deux niveaux dans le menu (2026-09-16) : les pages rangées dans un
   groupe sont un peu plus petites et plus serrées que les entrées de
   premier niveau. Le gras a été essayé d'abord, et refusé sur capture le
   même jour. La règle vise la STRUCTURE (lien dans un groupe), si bien
   qu'un lien injecté par admin-commun.js prend le niveau de sa place. */
.groupe-nav .lien-nav {
  display: block;
  padding: 6px 10px 6px 22px;
  font-size: calc(13px * var(--etiquettes-taille));
  letter-spacing: calc(.03em * var(--etiquettes-espacement));
  margin-top: 2px;
}

/* Le bouton qui déplie le menu n'existe que sur téléphone. */
.bouton-menu { display: none; }

/* Réaction immédiate au toucher : sans touch-action, un téléphone attend
   de savoir si c'est un double appui (zoom) avant de réagir. */
.barre-laterale a, .barre-laterale summary, .barre-laterale button {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.barre-laterale .bas {
  padding-top: 20px;
  margin-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, .14);
}
.barre-laterale .bas button {
  width: 100%;
  background: none;
  border-color: rgba(255, 255, 255, .3);
  color: var(--stone);
}
.barre-laterale .bas button:hover { border-color: var(--stone); color: #fff; }
/* Très discrets (2026-09-18) : ils doivent exister, pas se faire remarquer. */
.barre-laterale .bas .liens-legaux { justify-content: flex-start; gap: 2px 10px; margin-top: 12px; font-size: 10px; letter-spacing: .02em; }
.barre-laterale .bas .liens-legaux a { color: var(--stone); opacity: .35; }
.barre-laterale .bas .liens-legaux a:hover { opacity: 1; color: #fff; }

.contenu { flex: 1; padding: 36px 44px 60px; }
.contenu .limite { max-width: 760px; margin: 0 auto; }

/* Cartes de statistiques (tableau de bord)
   Rangée SOUPLE et non grille (2026-09-16) : chaque ligne de cartes remplit
   toute la largeur, y compris la dernière quand elle est incomplète — sept
   issues donnent quatre cartes puis trois cartes plus larges, et non trois
   cartes suivies d'une case vide. Une grille en auto-fit ne le fait que
   pour un conteneur d'UNE ligne : elle replie les colonnes vides de tout
   le conteneur, jamais celles de sa dernière ligne.
   Base de 160 px, bordure et marges internes comprises (box-sizing) :
   quatre cartes par ligne sur les 760 px de .contenu .limite, deux sur
   téléphone. */
.cartes-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 22px;
}
.cartes-stats .stat { flex: 1 1 160px; }
.stat {
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--ombre-carte);
  padding: 18px 20px;
}
.stat .nombre {
  font-family: var(--police-titres);
  font-weight: var(--titres-graisse);
  font-size: calc(40px * var(--titres-taille));
  color: var(--ink);
  line-height: max(1, var(--titres-interligne-min));
}
.stat .libelle { font-family: var(--sans); font-size: 13px; color: var(--ink-soft); margin-top: 6px; }

/* Colonne « N° » des registres (2026-09-16) : aussi étroite que possible.
   Elle prenait une largeur variable selon le registre (la fourrière et le
   refuge ne l'avaient pas pareille), parce que le tableau répartit sa
   largeur entre les colonnes. Une largeur de 4 chiffres, et nowrap : un
   numéro jusqu'à 9999 tient, et la colonne s'élargit d'elle-même au-delà
   au lieu de couper le numéro. */
.col-numero { width: 4ch; white-space: nowrap; }

/* La date d'un soin, d'un événement ou d'un relevé météo, en demi-gras
   (2026-09-16, météo le 2026-09-18) : c'est la notion qui compte le plus
   dans ces registres, même depuis que l'animal est passé devant. */
.col-date { font-weight: 600; }

/* Registres de la fourrière et du refuge : les MÊMES largeurs de colonnes,
   et TOUT SUR UNE LIGNE (2026-09-16).
   Laissées au contenu, les largeurs tombaient différemment d'un registre à
   l'autre, alors que ces deux registres sont des jumeaux qu'on compare et
   qu'on imprime côte à côte. Chaque page les fixe (table-layout: fixed) :
   ce qui dépasse finit par « … » au lieu de passer à la ligne, le texte
   complet restant au survol, dans l'export CSV et à l'impression.
   Calibrées en MESURANT les textes réels dans la police du site (SF, 14 px ;
   en-têtes Barlow Condensed 13 px) pour un tableau de 1 132 px — écran de
   1 440 px moins le menu et les marges — avec 6 px de marge de chaque côté
   des cellules. Le plus long à loger, par colonne : « 9999 » ; « Black
   Princesse » (nom le plus long d'ARA) ; l'en-tête « Espèce » ; l'en-tête
   « Sexe » (une lettre en dessous) ; un I-CAD écrit avec espaces ; la
   commune rognée à 12ch ; une date ; « Transfert depuis un autre refuge » ;
   « En famille d'accueil » ; « Transfert vers un autre refuge ».
   test/23 refait ce calcul. Total : 100 %. Sur téléphone, ces largeurs
   s'effacent devant la largeur naturelle du tableau, qui défile. */
.colonnes-jumelles col:nth-child(1) { width: 4.3%; }   /* N° */
.colonnes-jumelles col:nth-child(2) { width: 9.6%; }   /* Animal */
.colonnes-jumelles col:nth-child(3) { width: 4.6%; }   /* Espèce */
.colonnes-jumelles col:nth-child(4) { width: 3.5%; }   /* Sexe */
.colonnes-jumelles col:nth-child(5) { width: 13.7%; }  /* N° identification */
.colonnes-jumelles col:nth-child(6) { width: 10.2%; }  /* Commune d'origine */
.colonnes-jumelles col:nth-child(7) { width: 7.8%; }   /* Entrée : date */
.colonnes-jumelles col:nth-child(8) { width: 17.8%; }  /* Motif ou provenance */
.colonnes-jumelles col:nth-child(9) { width: 11.3%; }  /* Sortie : date */
.colonnes-jumelles col:nth-child(10) { width: 17.2%; } /* Destination / cause */

/* Pagination des longs registres (voir initPagination dans admin-commun.js) */
.pageur { display: flex; align-items: center; gap: 14px; margin-top: 16px; font-family: var(--sans); font-size: 13px; }
.pageur .bouton-page { padding: 6px 12px; font-size: 13px; }
.pageur .page-info { color: var(--ink-soft); }
.pageur .page-numero { width: 48px; padding: 3px 4px; text-align: center; }

/* À l'impression, la pagination ne s'applique pas : le registre doit
   pouvoir sortir en entier, pas seulement la page affichée à l'écran
   (demande explicite du 2026-08-25). */
@media print {
  .pageur { display: none !important; }
  tr[data-page] { display: table-row !important; }
}

/* LES REGISTRES S'IMPRIMENT EN NOIR SUR BLANC (2026-09-22, demande de
   l'utilisateur) : « pour ces impressions de registres, tous registres
   confondus, il n'est pas nécessaire de mettre le design avec la couleur
   et tout, parce qu'après, ça coûte cher en encre d'imprimerie. Donc il
   vaut mieux que ce soit une impression simple en noir sur papier blanc. »
   Il avait raison au-delà du détail : la feuille sortait avec le fond de la
   palette (« sauge » = un beige soutenu) sur TOUTE la page, plus les
   zébrures et les bandeaux gris du registre de suivi sanitaire. De quoi
   vider une cartouche sur un registre mensuel.
   La règle ne vaut QUE pour les pages de registre (body.registre-imprimable) :
   le rapport PDF du tableau de bord est fait pour sortir aux couleurs et au
   logo du refuge, la fiche de box porte une photo et un QR code, et le
   contrat d'adoption a son propre gabarit. Rien de tout ça ne doit devenir
   noir et blanc.
   Aucune couleur ne porte de sens dans un registre : les trois pages qui en
   utilisaient ne s'en servaient que pour griser un tiret d'absence. */
@media print {
  body.registre-imprimable, body.registre-imprimable * {
    background: transparent !important;
    background-image: none !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  body.registre-imprimable { background: #fff !important; }
  body.registre-imprimable th, body.registre-imprimable td { border-color: #000 !important; }
}

/* Filtre d'impression par date (voir imprimerEntreDates dans
   admin-commun.js) : bornes optionnelles au-dessus du bouton Imprimer.
   Le sélecteur combiné (tr[data-page].hors-plage-impression) l'emporte
   toujours sur tr[data-page] ci-dessus, quel que soit l'ordre des règles
   dans la feuille de style — spécificité plus élevée (deux sélecteurs
   au lieu d'un seul). */
.filtre-impression { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.filtre-impression input[type="date"] { width: auto; }
@media print {
  tr[data-page].hors-plage-impression, tr.hors-plage-impression { display: none !important; }
}
/* Les champs « Du … au … » filtrent aussi l'AFFICHAGE depuis le
   2026-09-18 (voir initPagination) : une ligne hors période est masquée à
   l'écran comme à l'impression, et n'est pas comptée dans la pagination.
   Même spécificité renforcée que ci-dessus. */
tr[data-page].hors-periode, tr.hors-periode { display: none !important; }

/* En-tête d'impression, partagé par tous les registres imprimables
   (demande explicite du 2026-08-28) : nom du refuge + SIRET, et la
   période couverte — invisibles à l'écran, affichés uniquement à
   l'impression. Texte posé par admin-commun.js : `.titre-impression`
   lit son intitulé de base dans `data-registre` (ex. "Registre de la
   fourrière") et y ajoute " — Nom du refuge (SIRET)" ; le "N°..."
   d'imprimerEntreDates calcule la période même quand aucune borne n'a
   été choisie ("tout" imprimé), pour qu'un exemplaire papier reste
   toujours daté. Remplace le h1 normal de chaque page à l'impression :
   chaque page doit cacher le sien (voir leurs @media print respectifs),
   sinon le titre du registre apparaîtrait deux fois. */
.titre-impression, .sous-titre-impression { display: none; }
@media print {
  .titre-impression {
    display: block; font-family: var(--police-titres);
    font-weight: var(--titres-graisse); text-transform: var(--titres-casse); font-size: calc(22px * var(--titres-taille)); margin: 0 0 4px;
  }
  .sous-titre-impression {
    display: block; font-family: var(--sans); font-size: 13px; color: var(--ink-soft); margin: 0 0 14px;
  }
}

/* LE RAPPORT EN PDF (2026-09-18, demande de l'utilisateur) : les
   chiffres de la période choisie, mis en page au nom du refuge (logo,
   couleurs, polices), pour les financeurs. Le bouton ouvre la fenêtre
   d'impression, où l'on choisit « Enregistrer au format PDF ». Le
   document n'existe qu'à l'impression ; à l'écran, rien ne change. */
#generer-rapport { padding: 7px 14px; font-size: calc(14px * var(--etiquettes-taille)); }
#rapport { display: none; }
@media print {
  @page { size: A4; margin: 14mm 14mm 16mm; }
  body.impression-rapport { background: #fff !important; padding: 0 !important; max-width: none !important; }
  body.impression-rapport .app, body.impression-rapport .bandeau-abonnement,
  body.impression-rapport .bandeau-consultation, body.impression-rapport .message-plateforme { display: none !important; }
  body.impression-rapport #rapport { display: block; }
}
#rapport { font-family: var(--sans); color: var(--ink); font-size: 12.5px; line-height: 1.45; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
#rapport .r-entete { display: flex; justify-content: space-between; align-items: flex-end; gap: 20px; padding-bottom: 14px; border-bottom: 3px solid var(--plate); }
#rapport .r-identite { display: flex; align-items: center; gap: 14px; }
#rapport .r-identite img { width: 64px; height: 64px; object-fit: contain; }
#rapport .r-nom { font-family: var(--police-titres); font-weight: var(--titres-graisse); text-transform: var(--titres-casse); font-size: calc(26px * var(--titres-taille)); line-height: 1.05; }
#rapport .r-sous-titre { color: var(--ink-soft); font-size: 12px; margin-top: 2px; }
#rapport .r-titre { text-align: right; }
#rapport .r-titre strong { display: block; font-family: var(--police-etiquettes); font-size: calc(13px * var(--etiquettes-taille)); letter-spacing: calc(.12em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); color: var(--plate-deep); }
#rapport .r-titre span { display: block; font-family: var(--police-titres); font-weight: var(--titres-graisse); font-size: calc(18px * var(--titres-taille)); margin-top: 2px; }
#rapport .r-section {
  font-family: var(--police-etiquettes); font-weight: 600; font-size: calc(12px * var(--etiquettes-taille));
  letter-spacing: calc(.12em * var(--etiquettes-espacement)); text-transform: var(--etiquettes-casse); color: var(--ink-soft);
  margin: 20px 0 8px; break-after: avoid;
}
#rapport .r-chiffres { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
#rapport .r-chiffre { background: var(--stone); border-radius: var(--radius-sm); padding: 10px 12px; break-inside: avoid; }
#rapport .r-chiffre b { display: block; font-family: var(--police-titres); font-weight: var(--titres-graisse); font-size: calc(24px * var(--titres-taille)); line-height: 1.1; }
#rapport .r-chiffre small { display: block; font-size: 11px; color: var(--ink-soft); line-height: 1.3; margin-top: 2px; }
#rapport .r-colonnes { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; }
#rapport table { width: 100%; border-collapse: collapse; }
#rapport td { padding: 6px 2px; border-bottom: 1px solid var(--line); }
#rapport td:last-child { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
#rapport .r-note { font-size: 11px; color: var(--ink-soft); margin-top: 8px; }
#rapport .r-pied { margin-top: 26px; padding-top: 10px; border-top: 1px solid var(--line); font-size: 10.5px; color: var(--ink-soft); display: flex; justify-content: space-between; gap: 12px; }

/* ===================================================================
   L'ADMINISTRATION SUR PETIT ÉCRAN (2026-09-14)

   Constat : les bénévoles d'ARA se servent beaucoup du logiciel au
   téléphone, notamment dans le train. Or l'administration n'avait AUCUN
   traitement mobile — les deux seules media queries de cette feuille
   concernaient le site public. Sur un écran de 360 px, la barre latérale
   de 220 px plus les 88 px de marges du contenu ne laissaient que ~52 px
   utiles : la grille des lignes débordait et les étiquettes venaient se
   superposer aux boutons.

   Le principe retenu : sous 820 px, la barre latérale cesse d'être une
   colonne et devient un bandeau en tête de page. Le contenu récupère
   alors toute la largeur. 820 px et pas 640 : à 768 px (tablette en
   portrait) il ne restait que 460 px de contenu, déjà trop peu pour la
   liste des animaux.

   « screen and » est délibéré : les registres s'impriment, et ces règles
   ne doivent jamais s'appliquer au papier. Un @media print existe plus
   bas, mais l'impression depuis un téléphone déclencherait aussi la
   largeur — d'où la restriction explicite au média écran.
   =================================================================== */
@media screen and (max-width: 820px) {
  .app { display: block; }

  /* Les tableaux de l'administration d'EasyShelter défilent de côté. */
  .table-admin { display: block; overflow-x: auto; }

  /* Ni collante ni haute comme l'écran : sur une longue liste d'animaux,
     un bandeau collant mangerait le tiers de la hauteur utile. On le
     remonte en tête, on le dépasse, on n'y pense plus. */
  /* MENU REPLIABLE (2026-09-16). Il était une rangée de pastilles : ouvrir
     « Registres » faisait passer le groupe sur sa propre ligne, et son
     titre sautait d'une ligne sous le doigt (constaté sur iPhone 15 Pro).
     Désormais, fermé : une ligne (marque à gauche, Déconnexion à droite)
     et un bouton « Menu ». Ouvert : la même colonne que sur ordinateur,
     où un groupe se déplie VERS LE BAS sans que rien au-dessus ne bouge. */
  .barre-laterale {
    position: static;
    width: auto;
    height: auto;
    padding: 14px 16px 16px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "marque bas"
      "bouton bouton"
      "menu menu";
    column-gap: 12px;
  }
  .barre-laterale .marque { grid-area: marque; margin-bottom: 0; }
  .barre-laterale .bas {
    grid-area: bas;
    align-self: start;
    margin: 0; padding: 0; border: 0;
  }
  .barre-laterale .bas form { margin: 0; }
  .barre-laterale .bas button { width: auto; padding: 8px 12px; font-size: 13px; }
  .barre-laterale .bas .liens-legaux { display: none; }

  .bouton-menu {
    grid-area: bouton;
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    min-height: 44px;
    margin-top: 12px;
    background: none;
    border-color: rgba(255, 255, 255, .3);
    color: var(--stone);
  }
  /* Le survol général des boutons (style.css, « Boutons ») passe texte et
     bordure en couleur --ink : la couleur du FOND de ce menu. Sur un
     téléphone, cet état reste accroché après l'appui, et le bouton
     disparaissait quelques secondes (constaté sur iPhone le 2026-09-16).
     Son apparence ne change donc pas au survol ; l'appui a son propre
     retour, plus bas. */
  .bouton-menu:hover { border-color: rgba(255, 255, 255, .3); color: var(--stone); }
  .bouton-menu::after { content: '▾'; font-size: 13px; }
  .bouton-menu[aria-expanded="true"]::after { content: '▴'; }

  .barre-laterale nav { grid-area: menu; display: none; gap: 2px; margin-top: 8px; }
  .barre-laterale.menu-ouvert nav { display: flex; }

  /* Des zones de toucher d'au moins 44 px pour le premier niveau. */
  .lien-nav, .groupe-nav summary { padding: 13px 10px; }
  .groupe-nav .lien-nav { padding: 11px 10px 11px 22px; }

  /* Sur un écran tactile, :hover reste « collé » après l'appui : le fond
     de survol ne se retirait qu'en touchant ailleurs. On le remplace par
     un retour pendant l'appui seulement. */
  .lien-nav:hover, .groupe-nav summary:hover { background: none; opacity: .75; }
  .lien-nav.actif:hover { background: var(--plate); opacity: 1; }
  .lien-nav:active, .groupe-nav summary:active, .bouton-menu:active { background: rgba(255, 255, 255, .12); }

  .contenu { padding: 20px 16px 40px; }

  /* Les registres comptent de 10 à 16 colonnes : aucun repli ne les rend
     lisibles, et les écraser est pire que tout. On les fait donc DÉFILER
     horizontalement, ce qui est le geste naturel au doigt.
     « .contenu table » et pas « table » : chaque page de registre déclare
     son propre « table { width: 100% } » dans sa balise <style>, qui
     l'emporterait sur un sélecteur d'un seul élément. Deux niveaux
     suffisent à reprendre la main — même piège que .contenu .limite.
     width:max-content laisse le tableau prendre sa largeur naturelle,
     max-width:100% borne la boîte à l'écran, et c'est l'écart entre les
     deux qui crée le défilement. */
  .contenu table {
    display: block;
    width: max-content;
    max-width: 100%;
    overflow-x: auto;
  }
}
