/* ==========================================================================
   dns.oxmo.org — feuille de style unique
   ==========================================================================

   AUCUNE RESSOURCE EXTERNE. Pas de CDN, pas de police distante, pas d'image
   hebergee ailleurs. C'est ce qui permet la CSP stricte du vhost
   (default-src 'self') : la moindre @import vers un tiers la ferait echouer,
   et le symptome serait une page nue sans erreur visible cote serveur.

   ---------------------------------------------------------------------------
   MEME CHARTE QUE ip.oxmo.org, ELLE-MEME TIREE DE www.forum.oxmo.org
   ---------------------------------------------------------------------------
   Refonte du 2026-08-19. Les deux sites voisins se citent l'un l'autre dans
   leur barre et leur pied de page ; ils avaient pourtant deux directions
   artistiques opposees. ip.oxmo.org portait le style « 2010 - gris » du forum
   -- plat, carre, bandeau de titre plein, filet de 1 px, aucune ombre, aucun
   degrade -- tandis que ce site-ci etait doux et ombre : coins a 18 px, ombres
   portees, halos en degrade radial, police system-ui a 16 px, accent bleu.
   Passer d'un site a l'autre donnait l'impression de changer d'auteur.

   C'est desormais la charte du forum, dans les valeurs exactes relevees pour
   ip.oxmo.org :

     #cbcbcb  fond de page        #444444  bordures franches
     #efefef  bloc                #646464  bandeau de titre, texte #ffffff
     #d6d6d6  alternance, filets  #767676  texte attenue
     #000000  texte, liens        #636363  survol et contour de focus
     #b4b4b4  filets fins         #f0b9a8  page courante dans la barre

   LES NOMS DE JETONS N'ONT PAS CHANGE. ip.oxmo.org nomme les siens en
   francais (--fond, --bloc, --alt) ; ici ils restent --bg, --surface,
   --surface-2. Seules les VALEURS et la mise en forme des composants ont
   bouge. Renommer aurait touche les gabarits qui citent var(--line) ou
   var(--ok) dans un attribut style, ainsi que Findings::scoreColor(), pour un
   gain nul a l'ecran. La correspondance :

     --bg          --fond        --line         --bord-fin
     --surface     --bloc        --line-strong  --bord
     --surface-2   --alt         --accent       --tete
     --text        --texte       --accent-on    --tete-txt
     --text-dim    --attenue     --accent-soft  --actif
     --accent-text --lien        --accent-hover --survol

   TROIS TOKENS ONT DISPARU, ET C'EST LE POINT DE LA REFONTE : --shadow*,
   --glow* et --bg-tint. La charte du forum n'a ni ombre portee ni degrade ; un
   seul de ces jetons remis en service ferait ressortir ce site de la famille.

   ---------------------------------------------------------------------------
   LES DEUX THEMES SONT COMPLETS
   ---------------------------------------------------------------------------
   Le theme clair est defini sur :root nu, le sombre est redefini a DEUX
   endroits :
     - @media (prefers-color-scheme: dark) garde par :not([data-theme="light"])
     - :root[data-theme="dark"]
   Les deux sont necessaires. Sans le premier, un visiteur qui n'a jamais
   touche a la bascule reste en clair alors que son systeme est en sombre.
   Sans le second, la bascule ne peut pas forcer le sombre chez quelqu'un dont
   le systeme est en clair. La garde :not([data-theme="light"]) est ce qui
   permet a la bascule de forcer le CLAIR chez quelqu'un dont le systeme est en
   sombre -- sans elle, le media query l'emporterait.

   Le sombre n'existe pas dans le forum : il est derive, ici comme sur
   ip.oxmo.org, avec les memes valeurs. Chaque jeton defini d'un cote DOIT
   l'etre de l'autre ; verifier.sh compare les deux listes et echoue si elles
   different.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Jetons — theme clair
   -------------------------------------------------------------------------- */
:root {
	color-scheme: light;

	/* Fonds, du plus profond au plus proche */
	--bg:            #cbcbcb;
	--surface:       #efefef;
	--surface-2:     #d6d6d6;
	--surface-hover: #e7e7e7;

	/* Texte. --text-soft n'existe pas dans le forum : il est interpole entre
	   le noir et le gris attenue, pour le corps des paragraphes secondaires
	   que ce site a et que le forum n'a pas. */
	--text:      #000000;
	--text-soft: #333333;
	--text-dim:  #767676;

	/* DEUX EPAISSEURS DE TRAIT, ET ELLES NE SONT PAS INTERCHANGEABLES.
	   --line-strong est la bordure FRANCHE du forum : contour des blocs, des
	   champs et des boutons. --line est le filet fin : lignes de tableau,
	   separateurs internes, encarts. Poser la bordure franche sur les filets
	   d'un tableau de vingt lignes le rendrait illisible ; poser le filet fin
	   sur un bloc lui ferait perdre le trait net qui fait toute la charte. */
	--line:        #b4b4b4;
	--line-strong: #444444;

	/* « Accent » est ici le gris de bandeau du forum, pas une couleur vive :
	   la chrome de ce site est desormais entierement grise. Le seul point
	   chaud est --accent-soft, l'orange pale qui marque la page courante dans
	   la barre -- exactement l'usage qu'en fait ip.oxmo.org. */
	--accent:       #646464;
	--accent-soft:  #f0b9a8;
	--accent-text:  #000000;
	--accent-on:    #ffffff;
	--accent-hover: #636363;

	/* Severites — les seules couleurs qui portent du sens.
	   Les trois du forum, plus un bleu pour le niveau « info » que ce site a
	   en propre. Ce bleu est le #003399 des liens du forum : il reste dans la
	   famille tout en se distinguant des trois autres. */
	--ok:          #116600;
	--ok-bg:       #e3ecdf;
	--ok-line:     #b3ccab;
	--info:        #003399;
	--info-bg:     #e0e6f2;
	--info-line:   #b6c2de;
	--warn:        #8a5200;
	--warn-bg:     #f3ead9;
	--warn-line:   #dcc79e;
	--problem:     #a8121f;
	--problem-bg:  #f2e0e1;
	--problem-line:#e0b4b8;

	/* Geometrie. Les trois rayons du forum : 3 px pour les boutons et les
	   pastilles, 4 px pour les encarts, 6 px pour les blocs. Ils valaient
	   8/12/18 px avant la refonte. */
	--r-sm: 3px;
	--r:    4px;
	--r-lg: 6px;

	--fs-mono: ui-monospace, "SF Mono", "Cascadia Mono", "DejaVu Sans Mono",
	           menlo, consolas, monospace;
	--fs-ui:   verdana, tahoma, arial, helvetica, sans-serif;

	--wrap: 1180px;
}

/* --------------------------------------------------------------------------
   2. Jetons — theme sombre
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		color-scheme: dark;

		--bg:            #1c1c1c;
		--surface:       #262626;
		--surface-2:     #333333;
		--surface-hover: #2f2f2f;

		--text:      #e8e8e8;
		--text-soft: #c4c4c4;
		--text-dim:  #9d9d9d;

		--line:        #414141;
		--line-strong: #565656;

		--accent:       #3a3a3a;
		--accent-soft:  #7a4030;
		--accent-text:  #e8e8e8;
		--accent-on:    #eaeaea;
		--accent-hover: #b5b5b5;

		--ok:          #7fc16a;
		--ok-bg:       #22301e;
		--ok-line:     #35521f;
		--info:        #8fb0f0;
		--info-bg:     #1a2136;
		--info-line:   #364a70;
		--warn:        #d8a441;
		--warn-bg:     #33291a;
		--warn-line:   #574320;
		--problem:     #e8797f;
		--problem-bg:  #331e20;
		--problem-line:#5f2a2f;
	}
}

:root[data-theme="dark"] {
	color-scheme: dark;

	--bg:            #1c1c1c;
	--surface:       #262626;
	--surface-2:     #333333;
	--surface-hover: #2f2f2f;

	--text:      #e8e8e8;
	--text-soft: #c4c4c4;
	--text-dim:  #9d9d9d;

	--line:        #414141;
	--line-strong: #565656;

	--accent:       #3a3a3a;
	--accent-soft:  #7a4030;
	--accent-text:  #e8e8e8;
	--accent-on:    #eaeaea;
	--accent-hover: #b5b5b5;

	--ok:          #7fc16a;
	--ok-bg:       #22301e;
	--ok-line:     #35521f;
	--info:        #8fb0f0;
	--info-bg:     #1a2136;
	--info-line:   #364a70;
	--warn:        #d8a441;
	--warn-bg:     #33291a;
	--warn-line:   #574320;
	--problem:     #e8797f;
	--problem-bg:  #331e20;
	--problem-line:#5f2a2f;
}

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
	}
}

body {
	margin: 0;

	/* 10 px sur les quatre cotes, comme ip.oxmo.org : c'est cette marge qui
	   detache les blocs du bord de l'ecran. Elle remplace le padding-inline
	   que .wrap portait avant la refonte -- il faut l'une OU l'autre, pas les
	   deux, sinon les blocs se decalent du fil de l'en-tete. */
	padding: 10px;

	/* --------------------------------------------------------------------
	   PIED DE PAGE COLLE EN BAS
	   --------------------------------------------------------------------
	   Sur une page courte -- un outil avant qu'on lui soumette un domaine --
	   le contenu ne remplit pas l'ecran. Sans ce dispositif, le pied de page
	   se pose au milieu du vide avec une grande bande de fond en dessous : on
	   croit la page tronquee.

	   Trois morceaux INDISSOCIABLES : le corps en colonne flexible, sa hauteur
	   minimale a un ecran, et <main> qui absorbe la place restante (regle
	   "main { flex: 1 0 auto }" plus bas). Retirer l'un des trois suffit a
	   faire remonter le pied.

	   100dvh APRES 100vh, et non a la place : sur mobile, 100vh compte la
	   barre d'adresse comme si elle n'existait pas et fait depasser la page
	   d'une centaine de pixels. 100dvh suit la hauteur reellement visible. La
	   ligne 100vh reste comme repli -- un navigateur qui ignore dvh lit la
	   premiere et saute la seconde.
	   -------------------------------------------------------------------- */
	display: flex;
	flex-direction: column;
	min-height: 100vh;
	min-height: 100dvh;

	font-family: var(--fs-ui);
	/* 13 px et non les 12 du forum : ce site affiche des tableaux de donnees
	   qu'on lit longtemps. La famille et l'interligne sont ceux du forum,
	   l'echelle est d'un cran -- meme reglage que ip.oxmo.org, au pixel. */
	font-size: 13px;
	line-height: 1.45;
	/* Fond explicite : la page est parfois rendue dans un cadre qui peint son
	   propre fond, un body transparent emprunterait alors celui de l'hote. */
	background: var(--bg);
	color: var(--text);
	/* Le corps ne defile jamais horizontalement : les tableaux larges ont
	   leur propre conteneur (.scroll-x). */
	overflow-x: hidden;
}

/* Absorbe toute la hauteur libre, ce qui pousse le pied de page en bas.
   "1 0 auto" et non "1" : la base auto laisse le contenu dicter sa hauteur
   naturelle sur les pages longues, la croissance ne joue que sur les courtes.
   Avec la base 0 de "flex: 1", le contenu d'une page longue serait comprime. */
main { flex: 1 0 auto; }

/* L'echelle typographique est FIXE, en pixels. Elle etait en clamp() et en
   rem : le titre d'accueil montait a 46 px, soit trois fois et demie le corps
   de texte. Le forum ne depasse jamais le double. */
h1, h2, h3, h4 {
	margin: 0 0 6px;
	font-family: inherit;
	font-weight: bold;
	line-height: 1.3;
	text-wrap: balance;
}
h1 { font-size: 17px; }
h2 { font-size: 14px; }
h3 { font-size: 13px; }
h4 { font-size: 12px; }

p { margin: 0 0 8px; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-text); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; }

code, kbd, samp, pre { font-family: var(--fs-mono); font-size: 12px; }

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

hr { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }

/* La largeur de page. Le retrait lateral vient du padding du body, pas d'ici :
   les blocs bordes doivent pouvoir coller au bord de leur .wrap, sinon leur
   trait n'est plus aligne d'un bloc a l'autre. */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; }
.narrow { max-width: 780px; }

.visually-hidden {
	position: absolute; width: 1px; height: 1px;
	padding: 0; margin: -1px; overflow: hidden;
	clip-path: inset(50%); white-space: nowrap; border: 0;
}

.skip-link {
	position: absolute; left: 10px; top: -4rem; z-index: 100;
	background: var(--accent); color: var(--accent-on);
	border: 1px solid var(--line-strong); border-radius: var(--r-sm);
	padding: 5px 10px; font-weight: bold;
	transition: top .15s;
}
.skip-link:focus { top: 10px; color: var(--accent-on); text-decoration: none; }

/* --------------------------------------------------------------------------
   4. En-tete
   --------------------------------------------------------------------------
   Plus de bandeau collant translucide : la charte du forum n'a ni flou, ni
   transparence, ni element flottant. L'en-tete est une simple rangee de
   boutons fermee par un filet, comme la barre et le fil d'Ariane de
   ip.oxmo.org, et elle defile avec la page.

   La position sticky et le backdrop-filter sont partis ensemble : garder le
   collant sans le flou aurait laisse un bandeau opaque qui recouvre le contenu
   au defilement, ce que ne fait aucune des deux autres pages du domaine.
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   TROIS ZONES : marque a gauche, outils AU CENTRE, commandes a droite
   --------------------------------------------------------------------------
   C'etait une rangee flex ou tout etait pousse a droite par un margin-left:
   auto. Les sept boutons d'outils se retrouvaient colles aux quatre commandes,
   et la moitie gauche de l'en-tete restait vide.

   La grille a trois colonnes 1fr / auto / 1fr centre les outils SUR LA PAGE et
   non entre leurs deux voisins : les deux colonnes exterieures font la meme
   largeur quoi qu'elles contiennent, donc la marque (152 px) et les commandes
   (119 px) n'entrainent pas le centre de leur cote. C'est la difference avec un
   simple justify-content: space-between, qui aurait decale les outils de 16 px
   vers la droite -- la moitie de l'ecart entre les deux.

   minmax(0, 1fr) ET NON 1fr : une piste 1fr a une largeur minimale automatique
   egale a son contenu, donc la marque ne pourrait jamais se tronquer et
   l'en-tete deborderait a droite sur ecran etroit -- le bandeau casse constate
   sur iPhone le 2026-08-17. Avec minmax(0, ...), la piste peut descendre sous
   la largeur de son contenu et la troncature de .brand reprend la main.
   -------------------------------------------------------------------------- */
.site-header .wrap {
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
	align-items: center;
	gap: 4px;
	/* Le filet de fermeture, reprise exacte du .fil de ip.oxmo.org. */
	padding-bottom: 6px;
	margin-bottom: 10px;
	border-bottom: 1px solid var(--text-dim);
}

.brand {
	display: inline-flex; align-items: center; gap: 6px;
	font-size: 13px; font-weight: bold;
	color: var(--text); text-decoration: none;
	/* Peut retrecir, et son contenu peut se tronquer : c'est le seul element
	   de l'en-tete dont on accepte de perdre une partie. */
	justify-self: start; min-width: 0; overflow: hidden;
}
.brand > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.brand:hover { color: var(--text); text-decoration: none; }
.brand svg { width: 17px; height: 17px; flex: 0 0 auto; }
.brand .tld { color: var(--text-dim); font-weight: normal; }

.site-nav { justify-self: center; display: flex; align-items: center; gap: 4px; }

/* Les boutons de la barre, au pixel de ceux de ip.oxmo.org : fond de bloc,
   bordure franche, 11 px en capitales, coins a 3 px, pictogramme a gauche. */
.nav-link {
	display: inline-flex; align-items: center; gap: 5px;
	padding: 4px 9px;
	background: var(--surface);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-sm);
	color: var(--text);
	font-size: 11px; letter-spacing: .04em; text-transform: uppercase;
	text-decoration: none; white-space: nowrap;
}
.nav-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
/* L'orange pale du forum, seul point chaud de la chrome. */
.nav-link[aria-current="page"] { background: var(--accent-soft); font-weight: bold; }

/* Le pictogramme est a la taille du texte qu'il precede et legerement efface :
   sept glyphes a pleine encre dans une rangee de boutons tirent l'oeil plus que
   les mots, alors qu'ils ne servent qu'a les retrouver. Celui du bouton courant
   revient a pleine encre, comme sur ip.oxmo.org. */
.nav-link svg { width: 14px; height: 14px; flex: 0 0 auto; opacity: .75; }
.nav-link[aria-current="page"] svg { opacity: 1; }

/* Les quatre commandes -- menu, FR, EN, bascule de theme -- restent calees a
   droite. Elles ne suivent pas les outils au centre : ce ne sont pas des
   outils, et leur place fixe est ce qui permet de les retrouver sans lire. */
.header-tools {
	justify-self: end;
	display: flex; align-items: center; gap: 4px;
}

.icon-btn {
	display: inline-grid; place-items: center;
	width: 26px; height: 26px; padding: 0;
	border: 1px solid var(--line-strong); border-radius: var(--r-sm);
	background: var(--surface); color: var(--text);
	font-family: inherit; cursor: pointer;
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 14px; height: 14px; opacity: .75; }
.icon-btn:hover svg { opacity: 1; }

/* La bascule montre l'icone de la cible, pas de l'etat courant : en clair on
   propose la lune, en sombre le soleil. Les deux sont dans le DOM, une seule
   est visible — sans quoi il faudrait du JS pour permuter le balisage, et
   l'icone serait fausse pendant le premier rendu. */
.theme-toggle .i-sun  { display: none; }
.theme-toggle .i-moon { display: block; }
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) .theme-toggle .i-sun  { display: block; }
	:root:not([data-theme="light"]) .theme-toggle .i-moon { display: none; }
}
:root[data-theme="dark"] .theme-toggle .i-sun  { display: block; }
:root[data-theme="dark"] .theme-toggle .i-moon { display: none; }

.lang-switch {
	display: inline-flex; align-items: center;
	border: 1px solid var(--line-strong); border-radius: var(--r-sm);
	overflow: hidden; background: var(--surface); height: 26px;
}
.lang-switch a {
	padding: 0 6px; height: 100%; display: inline-grid; place-items: center;
	font-size: 11px; letter-spacing: .04em;
	text-transform: uppercase; text-decoration: none; color: var(--text);
}
.lang-switch a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
/* La langue courante est marquee comme la page courante de la barre : orange
   pale et gras, jamais un aplat colore a texte blanc. */
.lang-switch a[aria-current="true"] { background: var(--accent-soft); font-weight: bold; }

/* ------------------------------------------------------------------------
   PALIERS DE L'EN-TETE
   ------------------------------------------------------------------------
   Trois seuils, chacun retirant ce qui devient superflu avant que la place
   ne manque. Le bouton de menu, le selecteur de langue et la bascule de
   theme survivent a tous les paliers : ce sont les commandes, elles ne
   disparaissent jamais.
   ------------------------------------------------------------------------ */

/* Les sept raccourcis d'outils cedent la place au menu deroulant, qui contient
   de toute facon les quatorze.

   LE SEUIL EST MESURE, PAS CHOISI. La rangee complete demande 855 px : marque
   152, sept boutons 556, commandes 119, gouttieres et marge de page 28. Le
   seuil etait a 900 px du temps ou la barre portait quatre boutons sans
   pictogramme ; a sept boutons il ne laissait plus que 11 px de jeu, et le
   premier libelle rallonge par une traduction aurait fait tronquer la marque.
   960 px laisse 70 px. */
@media (max-width: 960px) {
	.site-nav .nav-link { display: none; }
}

/* Le suffixe du nom de domaine part : "dns" seul reste identifiable, et
   l'adresse complete est de toute facon dans la barre du navigateur. */
@media (max-width: 460px) {
	.brand .tld { display: none; }
}

/* --------------------------------------------------------------------------
   5. Menu des outils (deroulant)
   --------------------------------------------------------------------------
   Le seul element flottant du site, et il le reste : quatorze outils ne
   tiennent pas dans une barre a cette largeur. L'ombre portee qui le detachait
   du fond a cede la place a la bordure franche du forum -- c'est elle qui joue
   le role de separation.
   -------------------------------------------------------------------------- */
.tool-menu { position: relative; }
.tool-menu-panel {
	position: absolute; right: 0; top: calc(100% + 4px);
	width: min(92vw, 620px);
	background: var(--surface); border: 1px solid var(--line-strong);
	border-radius: var(--r); padding: 4px;
	display: none; z-index: 50;
}
.tool-menu-panel[data-open="true"] { display: grid; }
@media (min-width: 620px) { .tool-menu-panel[data-open="true"] { grid-template-columns: 1fr 1fr; gap: 2px; } }

/* Meme trame que les tuiles de l'accueil : pictogramme a gauche sur les deux
   lignes de texte, nom et description a droite. C'est ce qui aligne les noms
   sur une meme verticale d'une entree a l'autre. */
.tool-menu-panel a {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-content: start;
	column-gap: 7px; row-gap: 1px;
	padding: 4px 7px; border-radius: var(--r-sm);
	text-decoration: none; color: var(--text);
}
.tool-menu-panel .tm-icon {
	grid-row: 1 / span 2;
	display: grid; place-items: start center;
	width: 16px; margin-top: 2px;
	color: var(--text-dim);
}
.tool-menu-panel .tm-icon svg { width: 16px; height: 16px; }
.tool-menu-panel a:hover .tm-icon { color: var(--text); }
.tool-menu-panel a:hover { background: var(--surface-2); color: var(--text); text-decoration: none; }
.tool-menu-panel .tm-name { font-weight: bold; font-size: 12px; display: block; }
.tool-menu-panel .tm-desc { color: var(--text-dim); font-size: 11px; display: block; line-height: 1.4; }

/* Le filet qui separe les outils des sites voisins. grid-column: 1 / -1 le fait
   traverser LES DEUX colonnes : sans cette ligne il occuperait une cellule et
   les deux voisins remonteraient a cote de lui, ce qui ne separerait rien.
   Il fonctionne tel quel dans la grille a une colonne des ecrans etroits. */
.tool-menu-panel .tm-sep {
	grid-column: 1 / -1;
	height: 1px;
	background: var(--line);
	margin: 5px 3px;
}

/* ------------------------------------------------------------------------
   SUR TELEPHONE, LE PANNEAU EST ANCRE A LA PAGE, PAS AU BOUTON
   ------------------------------------------------------------------------
   Signale le 2026-08-19 : ouvert sur un iPhone, le panneau sortait par la
   GAUCHE de l'ecran et la premiere colonne de texte etait coupee -- « DNS »
   pour « Recherche DNS », « on » pour « Propagation ».

   La cause est arithmetique. Le panneau etait pose en absolute, right: 0 dans
   .tool-menu, donc son bord droit se cale sur celui du BOUTON, qui n'est pas au
   bord de la page : la langue et la bascule de theme le suivent, une centaine de
   pixels. Sa largeur, min(92vw, 620px), se deploie ensuite vers la gauche. A
   390 px : bord droit du bouton a 283, largeur 359, bord gauche a -76.

   Le calcul ne tombe juste que quand la fenetre est nettement plus large que la
   page (au-dessus de ~740 px) ; en dessous, le panneau depasse toujours. Il est
   donc ancre sur .site-header .wrap -- c'est-a-dire sur la page elle-meme -- et
   tendu de bord a bord. Il ne peut plus deborder par construction, quelle que
   soit la largeur : plus aucune soustraction a faire juste.

   Le panneau porte quatorze entrees. Sur un ecran court -- telephone couche --
   elles depassent la hauteur visible, et comme il est en position absolue il
   n'allonge pas le document : le bas serait inatteignable. D'ou la hauteur
   maximale et le defilement interne.
   ------------------------------------------------------------------------ */
@media (max-width: 760px) {
	.site-header .wrap { position: relative; }
	.tool-menu { position: static; }
	.tool-menu-panel {
		left: 0; right: 0; width: auto;
		max-height: calc(100dvh - 70px);
		overflow-y: auto; -webkit-overflow-scrolling: touch;
	}
}

/* --------------------------------------------------------------------------
   6. En-tete de page (hero)
   --------------------------------------------------------------------------
   Ce n'etait pas un bloc mais une grande zone ouverte de 80 px de haut, posee
   sur deux halos en degrade radial. Les deux halos sont partis avec le reste
   des degrades ; la zone est devenue ce qu'elle est sur ip.oxmo.org : le
   PREMIER BLOC de la page, celui qui porte le titre et le formulaire.

   La bordure est posee sur .wrap et non sur .hero : .hero est pleine largeur,
   son trait aurait traverse l'ecran d'un bord a l'autre.
   -------------------------------------------------------------------------- */
.hero { margin-bottom: 10px; }
.hero .wrap {
	background: var(--surface);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-lg);
	padding: 9px 11px;
}
.hero h1 { margin-bottom: 4px; }
.hero .lede {
	font-size: 13px; color: var(--text-soft);
	max-width: 80ch; margin-bottom: 10px;
}

/* Etiquette de surtitre. Carree comme tout le reste : elle etait en
   border-radius: 999px avec un halo autour de son point. */
.eyebrow {
	display: inline-flex; align-items: center; gap: 5px;
	font-size: 11px; font-weight: bold; letter-spacing: .05em;
	text-transform: uppercase; color: var(--text-dim);
	background: var(--surface-2); border: 1px solid var(--line);
	padding: 2px 7px; border-radius: var(--r-sm); margin-bottom: 8px;
}
.eyebrow .dot {
	width: 6px; height: 6px; border-radius: 50%; background: var(--ok);
	flex: 0 0 auto;
}

/* --------------------------------------------------------------------------
   7. Formulaires
   -------------------------------------------------------------------------- */
.field-row {
	display: flex; gap: 6px; flex-wrap: wrap;
	max-width: 660px;
}
.field-row .grow { flex: 1 1 240px; min-width: 0; }

/* L'intitule de champ est celui du forum : 11 px, capitales, gris attenue. */
label {
	display: block; font-size: 11px; color: var(--text-dim);
	text-transform: uppercase; letter-spacing: .05em;
	margin-bottom: 2px;
}
.hint { font-size: 11px; line-height: 1.5; color: var(--text-dim); margin-top: 5px; }

input[type="text"], input[type="url"], input[type="email"], input[type="number"],
select, textarea {
	width: 100%;
	font-family: inherit; font-size: 13px;
	padding: 5px 7px;
	color: var(--text); background: var(--surface);
	border: 1px solid var(--line-strong); border-radius: var(--r-sm);
}
input::placeholder, textarea::placeholder { color: var(--text-dim); }
/* Contour et non halo : le box-shadow de 3 px qui entourait le champ actif
   etait la derniere ombre de la feuille. */
input:focus, select:focus, textarea:focus {
	outline: 2px solid var(--accent-hover);
	outline-offset: -1px;
}
textarea {
	min-height: 150px; resize: vertical;
	font-family: var(--fs-mono); font-size: 12px; line-height: 1.5;
}

/* Le chevron de <select> etait dessine avec deux degrades lineaires. Le
   forum laisse au navigateur le rendu de ses listes : appearance revient donc
   a sa valeur par defaut, et les deux degrades disparaissent. */

.check {
	display: flex; align-items: flex-start; gap: 6px;
	margin-bottom: 5px; font-size: 12px; color: var(--text);
}
.check input { width: auto; margin-top: 2px; accent-color: var(--accent); flex: 0 0 auto; }
.check label {
	margin: 0; font-size: 12px; color: var(--text);
	text-transform: none; letter-spacing: 0;
}

fieldset { border: 1px solid var(--line); border-radius: var(--r); padding: 8px 10px; margin: 0 0 10px; }
legend {
	font-size: 11px; font-weight: bold; color: var(--text-dim);
	text-transform: uppercase; letter-spacing: .05em; padding-inline: 4px;
}

/* Boutons. Le primaire est le bandeau de titre du forum : gris plein, texte
   blanc, gras. Il etait bleu, arrondi a 12 px, avec un survol en brightness
   et un enfoncement de 1 px au clic. */
.btn {
	display: inline-flex; align-items: center; justify-content: center; gap: 5px;
	font-family: inherit; font-size: 12px; font-weight: bold;
	padding: 5px 14px; border-radius: var(--r-sm);
	border: 1px solid var(--line-strong); cursor: pointer;
	background: var(--accent); color: var(--accent-on);
	text-decoration: none; white-space: nowrap;
}
.btn:hover { background: var(--accent-hover); color: var(--accent-on); text-decoration: none; }
.btn svg { width: 13px; height: 13px; }

/* Le bouton secondaire prend le fond de BLOC, pas celui d'alternance : cote a
   cote avec le primaire, l'alternance (#333) et le gris de bandeau (#3a3a3a) du
   theme sombre ne se distinguaient pratiquement pas -- vu sur l'outil d'en-tetes,
   ou « Analyser » et « Effacer » se touchent. */
.btn-ghost { background: var(--surface); color: var(--text); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }

.btn-sm { padding: 3px 9px; font-size: 11px; }

/* --------------------------------------------------------------------------
   8. Blocs et grilles
   --------------------------------------------------------------------------
   .card EST le .bloc de ip.oxmo.org : fond de bloc, bordure franche de 1 px,
   coins a 6 px, aucune ombre. Elle avait des coins a 18 px et un --shadow-sm.

   LE BANDEAU DE TITRE EST LA SIGNATURE DE LA CHARTE, et il est obtenu sans
   toucher aux gabarits. ip.oxmo.org le balise explicitement (.bloc > .titre
   suivi de .int) ; ici les cartes n'ont pas de conteneur interieur, le premier
   enfant est directement le titre ou la ligne de titre. Le bandeau est donc
   pose par des marges negatives qui annulent le padding de la carte, et
   overflow: hidden sur .card fait suivre les coins arrondis.

   La regle ne vise QUE le premier enfant : une carte qui commence par un
   encart ou par la jauge de score n'a pas de bandeau, comme le bloc d'adresse
   de ip.oxmo.org qui n'en a pas non plus.
   -------------------------------------------------------------------------- */
.card {
	background: var(--surface);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-lg);
	padding: 9px 11px;
	overflow: hidden;
}
.card + .card { margin-top: 10px; }
.card h2, .card h3 { margin-top: 0; }

.card-head {
	display: flex; align-items: center; justify-content: space-between;
	gap: 10px; flex-wrap: wrap; margin-bottom: 8px;
}
.card-head h2, .card-head h3 { margin-bottom: 0; }

.card > .card-head:first-child,
.card > h2:first-child,
.card > h3:first-child {
	margin: -9px -11px 9px;
	padding: 7px 11px;
	background: var(--accent);
	color: var(--accent-on);
	font-size: 13px; font-weight: bold;
}
.card > .card-head:first-child h2,
.card > .card-head:first-child h3 { font-size: 13px; color: inherit; }
.card > .card-head:first-child a { color: var(--accent-on); text-decoration: underline; }

.grid { display: grid; gap: 10px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* Intitule de section : 11 px en capitales grises, prolonge par un filet
   jusqu'au bord. Meme regle que .group-label du catalogue (section 21), pour
   que les deux se lisent comme un seul niveau de titre. */
.section-label {
	display: flex; align-items: center; gap: 8px;
	font-size: 11px; font-weight: bold; letter-spacing: .07em;
	text-transform: uppercase; color: var(--text-dim);
	margin: 14px 0 6px;
}
.section-label::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--line); }

/* --------------------------------------------------------------------------
   9. Jauge de score
   --------------------------------------------------------------------------
   La jauge reste circulaire : c'est une representation de donnee, pas de la
   chrome, et le forum a lui aussi ses jauges. Elle passe de 148 a 118 px et
   son nombre de 40 a 30 px -- 40 px de chiffre au-dessus d'un corps de texte
   a 13 px n'avait plus d'echelle commune avec le reste de la page.
   -------------------------------------------------------------------------- */
.score-block {
	display: flex; align-items: center; gap: 14px;
	flex-wrap: wrap;
}
.gauge { position: relative; width: 118px; height: 118px; flex: 0 0 auto; }
.gauge svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.gauge .track { fill: none; stroke: var(--line); stroke-width: 11; }
.gauge .value {
	fill: none; stroke-width: 11; stroke-linecap: butt;
	stroke: var(--gauge-color, var(--accent));
	/* Anime par transition sur stroke-dashoffset : le JS pose la valeur
	   finale apres le premier rendu. Sans JS, la valeur est deja correcte
	   dans l'attribut, l'arc s'affiche simplement sans animation. */
	transition: stroke-dashoffset 1s cubic-bezier(.22, 1, .36, 1);
}
.gauge .readout {
	position: absolute; inset: 0;
	display: grid; place-content: center; text-align: center;
}
.gauge .readout .n {
	font-size: 30px; font-weight: bold; line-height: 1;
	font-variant-numeric: tabular-nums;
	color: var(--gauge-color, var(--accent));
}
.gauge .readout .d {
	font-size: 10px; color: var(--text-dim);
	letter-spacing: .06em; text-transform: uppercase;
}

.score-summary { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 8px; }
.tally {
	display: inline-flex; align-items: center; gap: 4px;
	padding: 2px 6px; border-radius: var(--r-sm);
	font-size: 11px;
	border: 1px solid var(--line); background: var(--surface-2); color: var(--text-soft);
}
.tally .n { font-variant-numeric: tabular-nums; font-weight: bold; }
.tally[data-sev="ok"]      { color: var(--ok);      background: var(--ok-bg);      border-color: var(--ok-line); }
.tally[data-sev="info"]    { color: var(--info);    background: var(--info-bg);    border-color: var(--info-line); }
.tally[data-sev="warn"]    { color: var(--warn);    background: var(--warn-bg);    border-color: var(--warn-line); }
.tally[data-sev="problem"] { color: var(--problem); background: var(--problem-bg); border-color: var(--problem-line); }

/* --------------------------------------------------------------------------
   10. Constats
   -------------------------------------------------------------------------- */
.finding {
	position: relative;
	background: var(--surface); border: 1px solid var(--line-strong);
	border-radius: var(--r); padding: 7px 9px 7px 12px;
	margin-bottom: 6px; overflow: hidden;
}
/* Rail colore a gauche : c'est le repere principal quand on parcourt une
   liste de vingt constats sans les lire. Il survit a la refonte -- il porte du
   sens, il n'est pas decoratif. */
.finding::before {
	content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
	background: var(--sev, var(--line));
}
.finding[data-sev="ok"]      { --sev: var(--ok); }
.finding[data-sev="info"]    { --sev: var(--info); }
.finding[data-sev="warn"]    { --sev: var(--warn); }
.finding[data-sev="problem"] { --sev: var(--problem); }

.finding-head { display: flex; align-items: flex-start; gap: 6px; }
.finding-head .sev-icon { flex: 0 0 auto; width: 15px; height: 15px; margin-top: 2px; color: var(--sev); }
.finding-title { font-weight: bold; font-size: 12px; }
.finding-detail { color: var(--text-soft); font-size: 12px; margin-top: 1px; }

.finding-fix {
	margin-top: 7px; padding-top: 7px;
	border-top: 1px solid var(--line);
	font-size: 12px; color: var(--text-soft);
}
.finding-fix strong { color: var(--text); }

/* --------------------------------------------------------------------------
   11. Enregistrements et valeurs monospace
   -------------------------------------------------------------------------- */
.record {
	position: relative;
	display: flex; align-items: flex-start; gap: 6px;
	background: var(--surface-2); border: 1px solid var(--line);
	border-radius: var(--r-sm); padding: 5px 7px;
	font-family: var(--fs-mono); font-size: 12px; line-height: 1.5;
	word-break: break-all; margin-top: 6px;
}
.record .rec-body { flex: 1 1 auto; min-width: 0; }
.record .rec-meta {
	display: block; font-family: var(--fs-ui); font-size: 10px;
	color: var(--text-dim); margin-bottom: 1px; letter-spacing: .04em;
	text-transform: uppercase; word-break: normal;
}

.copy-btn {
	flex: 0 0 auto; display: inline-grid; place-items: center;
	width: 22px; height: 22px; padding: 0;
	border: 1px solid var(--line-strong); border-radius: var(--r-sm);
	background: var(--surface); color: var(--text);
	font-family: inherit; cursor: pointer;
}
.copy-btn:hover { background: var(--surface-2); color: var(--text); }
.copy-btn svg { width: 12px; height: 12px; }
.copy-btn[data-copied="true"] { color: var(--ok); border-color: var(--ok); background: var(--ok-bg); }

/* --------------------------------------------------------------------------
   12. Tableaux
   -------------------------------------------------------------------------- */
/* Tout tableau large vit dans ce conteneur. C'est lui qui defile, jamais le
   corps de page — verifie a 320 px. */
.scroll-x {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	border: 1px solid var(--line-strong); border-radius: var(--r);
	background: var(--surface);
}
.scroll-x > table { border: 0; margin: 0; }

table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td {
	text-align: left; padding: 4px 7px;
	border-bottom: 1px solid var(--line); vertical-align: top;
}
thead th {
	font-size: 11px; font-weight: bold; letter-spacing: .04em;
	text-transform: uppercase; color: var(--text-dim);
	background: var(--surface-2); white-space: nowrap;
	position: sticky; top: 0; z-index: 1;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--surface-hover); }
td.mono, .mono { font-family: var(--fs-mono); font-size: 12px; word-break: break-all; }
td.num, .num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
td.nowrap, .nowrap { white-space: nowrap; }

/* --------------------------------------------------------------------------
   13. Pastilles d'etat
   -------------------------------------------------------------------------- */
.pill {
	display: inline-flex; align-items: center; gap: 4px;
	padding: 1px 6px; border-radius: var(--r-sm);
	font-size: 11px;
	border: 1px solid var(--line); background: var(--surface-2); color: var(--text-soft);
	white-space: nowrap;
}
.pill[data-sev="ok"]      { color: var(--ok);      background: var(--ok-bg);      border-color: var(--ok-line); }
.pill[data-sev="info"]    { color: var(--info);    background: var(--info-bg);    border-color: var(--info-line); }
.pill[data-sev="warn"]    { color: var(--warn);    background: var(--warn-bg);    border-color: var(--warn-line); }
.pill[data-sev="problem"] { color: var(--problem); background: var(--problem-bg); border-color: var(--problem-line); }
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   14. Encarts
   --------------------------------------------------------------------------
   Meme forme que le .message de ip.oxmo.org : le fond ET la bordure prennent
   la couleur de la severite. L'encart portait un rail de 3 px a gauche et un
   fond neutre, ce qui le faisait ressembler a un constat sans en etre un.
   -------------------------------------------------------------------------- */
.note {
	border: 1px solid var(--line); background: var(--surface-2);
	border-radius: var(--r);
	padding: 7px 10px; font-size: 12px; line-height: 1.5; color: var(--text-soft);
	margin: 8px 0;
}
.note strong { color: var(--text); }
.note[data-sev="ok"]      { background: var(--ok-bg);      border-color: var(--ok); }
.note[data-sev="info"]    { background: var(--info-bg);    border-color: var(--info); }
.note[data-sev="warn"]    { background: var(--warn-bg);    border-color: var(--warn); }
.note[data-sev="problem"] { background: var(--problem-bg); border-color: var(--problem); }

.empty {
	text-align: center; padding: 18px 10px;
	color: var(--text-dim); font-style: italic;
}

/* --------------------------------------------------------------------------
   15. Onglets
   -------------------------------------------------------------------------- */
.tabs {
	display: flex; gap: 2px; border-bottom: 1px solid var(--line);
	margin-bottom: 10px; overflow-x: auto;
}
.tabs a, .tabs button {
	padding: 4px 9px; border: 0; background: none; cursor: pointer;
	font-family: inherit; font-size: 12px; color: var(--text-dim);
	border-bottom: 2px solid transparent; margin-bottom: -1px;
	text-decoration: none; white-space: nowrap;
}
.tabs a:hover, .tabs button:hover { color: var(--text); text-decoration: none; }
.tabs [aria-selected="true"], .tabs [aria-current="page"] {
	color: var(--text); font-weight: bold; border-bottom-color: var(--line-strong);
}

/* --------------------------------------------------------------------------
   16. Indicateur de chargement
   --------------------------------------------------------------------------
   Le squelette scintillant (.skeleton) est parti : il etait bati sur un
   degrade en mouvement, que la charte n'admet pas, et aucun gabarit ne s'en
   servait.
   -------------------------------------------------------------------------- */
.loading {
	display: inline-flex; align-items: center; gap: 6px;
	color: var(--text-dim); font-size: 12px;
}
.spinner {
	width: 13px; height: 13px; flex: 0 0 auto;
	border: 2px solid var(--line); border-top-color: var(--text);
	border-radius: 50%; animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   17. Pied de page
   -------------------------------------------------------------------------- */
.site-footer {
	margin-top: 14px;
	font-size: 11px; color: var(--text-dim);
}
/* Le filet est sur .wrap, comme celui de l'en-tete : sur .site-footer il
   traverserait l'ecran d'un bord a l'autre, alors que tout le reste de la page
   s'arrete a 1180 px. */
.site-footer .wrap {
	display: flex; gap: 4px 14px; flex-wrap: wrap;
	align-items: center; justify-content: space-between;
	padding-top: 8px; border-top: 1px solid var(--line);
}
.site-footer a { color: var(--text-dim); text-decoration: underline; }
.site-footer a:hover { color: var(--text); }
.footer-links { display: flex; gap: 4px 14px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   18. Utilitaires
   -------------------------------------------------------------------------- */
.stack > * + * { margin-top: 10px; }
.stack-sm > * + * { margin-top: 5px; }
.row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.muted { color: var(--text-dim); }
.soft  { color: var(--text-soft); }
.small { font-size: 11px; }
.tnum  { font-variant-numeric: tabular-nums; }
.mt-0 { margin-top: 0; } .mb-0 { margin-bottom: 0; }
.mt-2 { margin-top: 18px; }

@media print {
	.site-header, .site-footer, .copy-btn, .btn { display: none !important; }
	body { background: #fff; color: #000; }
	.card, .finding { break-inside: avoid; border-color: #ccc; }
}

/* --------------------------------------------------------------------------
   19. Constats qui pesent sur la note
   --------------------------------------------------------------------------
   Ajoute le 2026-08-17. La severite seule ne disait pas ce qui coutait des
   points : "info" recouvre a la fois un defaut mineur qui fait baisser la note
   et une simple remarque qui n'y touche pas. Les deux etaient rendus a
   l'identique, si bien qu'un domaine sortait a 95 "avec que des ok et des
   info" sans qu'on puisse voir ou etaient passes les cinq points manquants.

   La regle de lecture est celle de la couleur du rail :

     vert    conforme, rien a signaler
     gris    remarque sans effet sur la note
     orange  fait perdre des points
     rouge   probleme, fait perdre beaucoup de points

   L'attribut data-cost n'est present que si le cout est superieur a zero,
   c'est lui qui commande la bascule.
   -------------------------------------------------------------------------- */

/* Neutre : rail gris, teinte volontairement effacee. Le lecteur doit pouvoir
   sauter ces constats du regard. */
.finding[data-sev="info"]:not([data-cost]) { --sev: var(--text-dim); }
.finding[data-sev="info"]:not([data-cost]) .sev-icon { color: var(--text-dim); }

/* Coute des points : orange, quelle que soit la severite nominale. Un "info"
   qui fait perdre 4 points se lit alors comme ce qu'il est -- quelque chose a
   regarder -- et non comme une remarque anodine. */
.finding[data-sev="info"][data-cost] { --sev: var(--warn); }
.finding[data-sev="info"][data-cost] .sev-icon { color: var(--warn); }

/* Le rail des constats qui coutent est plus large : la difference se voit en
   parcourant la page sans lire, ce qui est precisement l'usage. */
.finding[data-cost]::before { width: 5px; }

/* Etiquette du cout, a droite du titre. */
.cost {
	display: inline-block;
	margin-left: 5px;
	padding: 0 4px;
	border-radius: var(--r-sm);
	font-size: 10px;
	font-weight: bold;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
	vertical-align: 1px;
	color: var(--warn);
	background: var(--warn-bg);
	border: 1px solid var(--warn-line);
}
.finding[data-sev="problem"] .cost {
	color: var(--problem);
	background: var(--problem-bg);
	border-color: var(--problem-line);
}

/* --------------------------------------------------------------------------
   20. Donnees observees dans un constat
   --------------------------------------------------------------------------
   Ajoute le 2026-08-17. Les constats enoncaient un verdict sans montrer sur
   quoi il reposait : "2 serveurs de noms actifs" ne disait pas lesquels, et le
   lecteur ne pouvait ni verifier ni agir. Ce bloc affiche les valeurs
   reellement lues.

   Grille a deux colonnes : le libelle a gauche, cale sur la largeur du plus
   long, la valeur a droite. Une entree sans libelle occupe toute la largeur --
   c'est le cas des listes (serveurs de noms, MX), ou un libelle repete a
   chaque ligne serait du bruit.
   -------------------------------------------------------------------------- */
.evidence {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 1px 8px;
	margin: 7px 0 0;
	padding: 5px 7px;
	background: var(--surface-2);
	border: 1px solid var(--line);
	border-radius: var(--r-sm);
	font-size: 11px;
}
.evidence dt {
	color: var(--text-dim);
	font-family: var(--fs-ui);
	white-space: nowrap;
}
.evidence dd {
	margin: 0;
	font-family: var(--fs-mono);
	color: var(--text);
	/* break-all et non break-word : les valeurs sont des noms de domaine, des
	   adresses IP et des enregistrements, qui n'ont pas d'espaces ou coupure. */
	word-break: break-all;
}
.evidence dd.full { grid-column: 1 / -1; }

/* --------------------------------------------------------------------------
   21. Catalogue des outils de la page d'accueil
   --------------------------------------------------------------------------
   Refait le 2026-08-17. Chaque groupe avait sa propre grille en
   "auto-fit, minmax(240px, 1fr)" ; auto-fit effacant les colonnes vides, le
   nombre de colonnes suivait le nombre d'outils du groupe :

     DNS (5 outils)        4 colonnes de 257 px
     Messagerie (6)        4 colonnes de 257 px
     Securite (2)          2 colonnes de 530 px
     Web (1)               1 colonne  de 1076 px

   Soit trois largeurs de tuile sur une meme page, sans aucun alignement
   vertical d'une section a la suivante.

   Le nombre de colonnes est desormais FIXE par palier. Toutes les tuiles ont
   la meme largeur, la meme hauteur et les memes reperes verticaux, du haut de
   la page au bas. Trois principes tiennent ce resultat :

     1. grid-template-columns: repeat(N, minmax(0, 1fr)) -- N fixe, jamais
        deduit du contenu. Le minmax(0, ...) evite qu'un long mot insecable
        elargisse sa colonne au detriment des autres.
     2. grid-auto-rows: 1fr -- toutes les lignes d'un groupe prennent la
        hauteur de la plus haute, donc aucune tuile plus courte que sa voisine.
     3. une reserve de trois lignes sur la description. Sans elle, le point 2
        egalise les tuiles a l'interieur d'un groupe mais pas d'un groupe a
        l'autre : un groupe dont les descriptions tiennent sur deux lignes
        serait plus plat que le voisin qui en demande trois. La reserve fixe la
        hauteur par construction, sans dependre du texte le plus long du
        groupe -- donc sans bouger le jour ou une traduction est reecrite.

   La tuile est batie sur la meme trame a toutes les largeurs -- icone a
   gauche, nom et description a droite. Un second gabarit vertical pour les
   grands ecrans aurait double la surface a maintenir, pour un resultat que
   rien ne rendait meilleur.
   -------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------
   LES SECTIONS PARTAGENT LA MEME GRILLE QUE LES TUILES
   ------------------------------------------------------------------------
   Les groupes sont poses dans une grille de meme pas que celle des tuiles, et
   chaque section occupe autant de colonnes qu'elle a d'outils (classe span-N
   posee par home.php). Deux consequences :

     - "Securite" (2 outils) et "Web" (1) se partagent la derniere ligne au
       lieu de laisser trois cellules vides ;
     - une section de 2 colonnes donne exactement la meme largeur de tuile
       qu'une section de 3, parce que la gouttiere INTERIEURE (celle de
       .tool-grid) et la gouttiere EXTERIEURE (celle de .tool-sections) ont la
       meme valeur. C'est cette egalite qui aligne tout, sans avoir besoin de
       subgrid : changer l'une des deux sans l'autre decale les colonnes d'une
       section large par rapport a celles d'une section etroite.

   align-self: start est indispensable. Sans lui, une section courte posee a
   cote d'une section haute serait etiree a sa hauteur, et son grid-auto-rows:
   1fr interieur transformerait sa tuile unique en pave de 400 px de haut.
   ------------------------------------------------------------------------ */
.tool-sections {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 14px 6px;
}
/* CHAQUE CATEGORIE EST UN BLOC, au sens du forum : bandeau de titre plein en
   tete, corps en fond de bloc, bordure franche de 1 px, coins a 6 px. C'est la
   forme de .card, obtenue ici sans le detour des marges negatives puisque le
   gabarit a deja le conteneur interieur qu'il faut (.tool-grid).

   Le titre etait auparavant un simple intitule gris prolonge par un filet.
   Il tenait, mais il ne disait pas que les quatre groupes etaient quatre
   objets distincts : poses a meme la page, ils se lisaient comme une seule
   liste coupee par des sous-titres. */
.tool-group {
	grid-column: span 3;
	align-self: start;
	background: var(--surface);
	border: 1px solid var(--line-strong);
	border-radius: var(--r-lg);
	overflow: hidden;
}
.tool-group.span-1 { grid-column: span 1; }
.tool-group.span-2 { grid-column: span 2; }

/* Le bandeau. Pas de capitales ici, contrairement aux intitules de section :
   « DNS et domaine » se lit mieux tel quel, et le bandeau se distingue deja
   par son aplat. */
.group-label {
	margin: 0;
	padding: 7px 11px;
	background: var(--accent);
	color: var(--accent-on);
	font-size: 13px;
	font-weight: bold;
	letter-spacing: 0;
	text-transform: none;
}

.tool-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	grid-auto-rows: 1fr;
	gap: 6px;
	padding: 9px 11px;
}
.span-1 .tool-grid { grid-template-columns: minmax(0, 1fr); }
.span-2 .tool-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Deux colonnes : une section large retombe a 2, une section d'un seul outil
   garde sa colonne unique et reste donc a cote de sa voisine. */
@media (max-width: 1000px) {
	.tool-sections { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.tool-group, .tool-group.span-2 { grid-column: span 2; }
	.tool-grid, .span-2 .tool-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Une seule colonne : les tuiles n'ont plus de voisine a egaler, et la reserve
   de trois lignes ne laisserait que du vide sous les descriptions courtes.
   Le seuil est a 700 px et non 640 : entre les deux, deux colonnes donnent des
   tuiles etroites ou la plus longue description passe a quatre lignes, ce qui
   depareille de nouveau les groupes. */
@media (max-width: 700px) {
	.tool-sections { grid-template-columns: minmax(0, 1fr); gap: 8px; }
	.tool-group, .tool-group.span-1, .tool-group.span-2 { grid-column: 1 / -1; }
	.tool-grid, .span-1 .tool-grid, .span-2 .tool-grid {
		grid-template-columns: minmax(0, 1fr); grid-auto-rows: auto;
		gap: 4px; padding: 7px 8px;
	}
}

/* LA TUILE PORTE LE GRIS D'ALTERNANCE, comme celles de ip.oxmo.org et de
   tools.oxmo.org -- et pour la meme raison : elle est DANS un bloc, donc le
   gris d'alternance (#d6d6d6) ressort sur le fond de bloc (#efefef) qui
   l'entoure.

   Elle avait porte le fond de bloc pendant un temps, quand la grille etait
   posee a meme la page : l'alternance sur le fond de page (#cbcbcb) ne se
   detachait plus et les quatorze tuiles se fondaient dans le fond. Le bloc
   ayant repris sa place autour d'elles, le rapport d'origine est retabli.
   Les deux valeurs vont ensemble -- changer le fond du bloc sans changer
   celui de la tuile refait disparaitre l'une dans l'autre.

   Le survol monte d'un cran vers le fond de bloc et franchit la bordure. La
   tuile avait des coins a 18 px, une pastille de couleur derriere son
   pictogramme, et se soulevait de 2 px avec une ombre portee. */
.tool-card {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-content: start;
	column-gap: 8px; row-gap: 1px;
	padding: 7px 9px;
	background: var(--surface-2); border: 1px solid var(--line);
	border-radius: var(--r); text-decoration: none; color: var(--text);
}
.tool-card:hover {
	background: var(--surface); border-color: var(--line-strong);
	color: var(--text); text-decoration: none;
}

/* L'icone occupe les deux lignes de texte : c'est ce qui aligne les noms sur
   une meme horizontale d'une tuile a l'autre. */
.tool-card .tc-icon {
	grid-row: 1 / span 2;
	display: grid; place-items: start center;
	width: 20px; color: var(--text-dim);
	margin-top: 2px;
}
.tool-card .tc-icon svg { width: 20px; height: 20px; }

.tool-card .tc-name {
	display: flex; align-items: center; gap: 6px;
	font-weight: bold; font-size: 12px;
}
.tool-card .tc-desc { color: var(--text-dim); font-size: 11px; line-height: 1.4; }

/* Reserve de trois lignes des qu'il y a plusieurs colonnes : c'est ce qui rend
   toutes les tuiles de la page identiques, groupe par groupe. En dessous de
   701 px il n'y a qu'une colonne, plus rien a egaler, et la reserve ne ferait
   que creuser du blanc. */
@media (min-width: 701px) {
	.tool-card .tc-desc { min-height: calc(3 * 1.4em); }
}

/* Fleche TOUJOURS presente, seule sa couleur bouge au survol. Elle etait
   auparavant en opacity: 0 avec un libelle "Verifier" revele au survol : la
   tuile changeait d'aspect sous le curseur, et au doigt -- ou il n'y a pas de
   survol -- rien n'indiquait jamais que la tuile etait cliquable. */
.tool-card .tc-arrow {
	margin-left: auto; flex: 0 0 auto;
	width: 12px; height: 12px; color: var(--text-dim);
}
.tool-card:hover .tc-arrow { color: var(--text); }

/* --------------------------------------------------------------------------
   22. Ecrans etroits et retouches tactiles
   --------------------------------------------------------------------------
   Mesures faites a 320 et 390 px, pas estimees.
   -------------------------------------------------------------------------- */
@media (max-width: 700px) {
	/* Meme retrait que ip.oxmo.org sur telephone : 7 px au lieu de 10. */
	body { padding: 7px; }
	.skip-link { left: 7px; }
	.skip-link:focus { top: 7px; }
}

/* SAISIE A 16 px SUR MOBILE — CE N'EST PAS UN CHOIX ESTHETIQUE.
   Safari iOS zoome AUTOMATIQUEMENT sur un champ dont la police descend sous
   16 px des qu'il recoit le focus : la page grossit, se decale, et le visiteur
   doit la repincer pour revoir le bouton. Les champs sont a 13 px, comme ceux
   du forum. 16px en dur, et non 1rem : un visiteur ayant reduit la taille de
   police par defaut repasserait sous le seuil. */
@media (max-width: 760px) {
	input[type="text"], input[type="url"], input[type="email"], input[type="number"],
	select, textarea { font-size: 16px; }
}

/* CIBLES TACTILES. Les liens du pied de page faisaient 23 px de haut, soit la
   hauteur du texte, contre 44 px recommandes au doigt ; les boutons de la
   barre en font 26. Le texte reste a sa taille -- c'est la zone cliquable qui
   grandit, grossir le texte aurait deforme la charte. */
@media (max-width: 760px) {
	.footer-links { gap: 2px 14px; }
	.footer-links a { display: inline-block; padding: 6px 0; }
	.icon-btn { width: 32px; height: 32px; }
	.lang-switch { height: 32px; }
	.lang-switch a { padding: 0 8px; }
	.nav-link { padding: 8px 9px; }
}
