/* ==========================================================================
   nfc.guide, feuille de style unique
   --------------------------------------------------------------------------
   Invariants a ne jamais casser (voir CONVENTIONS.md) :
   1. Aucune valeur de couleur, d'espacement, de rayon ou de taille de police
      n'est ecrite en dur dans une regle. Tout passe par une variable CSS.
   2. Nommage a plat et prefixe : ng-quelquechose. Pas de BEM, pas de classe
      utilitaire generique.
   3. Deux points de rupture au maximum : 48rem et 64rem. Ne pas en ajouter.
   4. Palette reduite : 2 gris de texte, 2 fonds, 1 accent, 1 etat d'erreur.
      L'accent est la couleur de marque #ffa024, identique dans les deux
      themes par choix de l'editeur. Chaque jeton porte son ratio mesure,
      y compris quand il est bas.
      Pas de degrade, pas d'ombre portee decorative, pas d'animation gratuite.
   5. Le theme sombre redefinit uniquement les variables de couleur, jamais
      une regle de mise en page.
   ========================================================================== */


/* ==========================================================================
   1. JETONS DE THEME
   ========================================================================== */

:root {
  /* --- Fonds ------------------------------------------------------------ */
  --ng-bg:            #ffffff;
  --ng-bg-alt:        #f4f5f7;

  /* --- Textes ----------------------------------------------------------- */
  --ng-text:          #1a1d21;   /* contraste 15.9:1 sur --ng-bg */
  --ng-text-muted:    #5a6169;   /* contraste  6.3:1 sur --ng-bg */

  /* --- Accent unique ----------------------------------------------------
     La couleur de marque #ffa024 est portee telle quelle dans les deux
     themes, par choix de l'editeur, pour la coherence de la marque.

     Consequence assumee : sur le fond blanc du theme clair elle donne
     2.0:1, sous le minimum de 4.5:1 pour du texte et sous les 3:1 des
     elements d'interface. Les liens, l'anneau de focus et la rubrique
     courante sont concernes. Sur le fond du theme sombre elle donne
     8.8:1. Ne pas assombrir le theme clair sans l'accord de l'editeur :
     la decision a ete prise en connaissance de la mesure.

     Le survol s'ecarte dans la direction utile a chaque theme : plus
     sombre sur fond clair, plus clair sur fond sombre. */
  --ng-accent:        #ffa024;   /* contraste  2.0:1 sur --ng-bg */
  --ng-accent-strong: #e08a10;   /* contraste  2.7:1 sur --ng-bg */
  --ng-accent-soft:   #fdf1e3;   /* fond des blocs accentues, 15.2:1 avec --ng-text */

  /* Texte pose SUR l'accent, dans les deux themes. Le fond etant clair et
     sature, un texte fonce est le seul lisible : 8.3:1, contre 2.0:1 pour
     du blanc. */
  --ng-on-accent:     #1a1d21;   /* contraste  8.3:1 sur --ng-accent */

  /* --- Etat d'erreur ---------------------------------------------------- */
  --ng-error:         #b3261e;   /* contraste  6.5:1 sur --ng-bg */
  --ng-error-soft:    #fbeceb;

  /* --- Bordures --------------------------------------------------------- */
  --ng-border:        #d8dbdf;
  --ng-border-strong: #b6bcc4;
  --ng-bw:            1px;

  /* --- Rayons ----------------------------------------------------------- */
  --ng-r-sm:          3px;
  --ng-r-md:          6px;
  --ng-r-lg:          10px;

  /* --- Typographie ------------------------------------------------------ */
  --ng-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                  "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --ng-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                  "Liberation Mono", monospace;

  --ng-fs-xs:         0.8125rem;  /* 13px */
  --ng-fs-sm:         0.9375rem;  /* 15px */
  --ng-fs-body:       1.0625rem;  /* 17px sur mobile, cf. point de rupture 1 */
  --ng-fs-lead:       1.1875rem;  /* chapeau et bloc reponse directe */
  --ng-fs-h3:         1.25rem;
  --ng-fs-h2:         1.5rem;
  --ng-fs-h1:         1.875rem;
  --ng-fs-display:    2.125rem;   /* h1 de l'accueil uniquement */

  --ng-lh-body:       1.65;
  --ng-lh-tight:      1.25;
  --ng-lh-ui:         1.4;

  --ng-fw-normal:     400;
  --ng-fw-medium:     600;
  --ng-fw-bold:       700;

  /* --- Espacements, echelle unique -------------------------------------- */
  --ng-s1:            0.25rem;
  --ng-s2:            0.5rem;
  --ng-s3:            0.75rem;
  --ng-s4:            1rem;
  --ng-s5:            1.5rem;
  --ng-s6:            2rem;
  --ng-s7:            3rem;
  --ng-s8:            4rem;

  /* --- Mesures de mise en page ------------------------------------------ */
  --ng-maxw-page:     72rem;      /* largeur maximale de l'enveloppe */
  --ng-maxw-prose:    54ch;       /* environ 72 signes rendus. L'unite ch
                                     vaut la largeur du "0", sensiblement
                                     plus large que la moyenne des signes,
                                     donc 54ch et non 70ch. Mesure a refaire
                                     si la pile de polices change. */
  --ng-w-aside:       15rem;      /* sommaire lateral sur grand ecran */
  --ng-gutter:        var(--ng-s4);

  /* Respiration au-dessus d'une ancre atteinte par le sommaire. L'entete
     n'etant pas collante, il n'y a aucune hauteur a compenser. */
  --ng-header-clear:  var(--ng-s5);

  /* --- Divers ----------------------------------------------------------- */
  --ng-z-header:      100;
  --ng-z-skip:        200;
  --ng-focus-w:       2px;
  --ng-focus-off:     2px;
  --ng-dur:           120ms;
}

/* Theme sombre automatique. Le garde :not([data-theme="light"]) laisse la
   priorite au choix manuel memorise par le bloc ng:theme. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ng-bg:            #14171a;
    --ng-bg-alt:        #1e2226;
    --ng-text:          #e8eaed;
    --ng-text-muted:    #a3abb4;
    --ng-accent:        #ffa024;   /* contraste  8.8:1 sur --ng-bg */
    --ng-accent-strong: #ffbc5e;   /* contraste 10.8:1 sur --ng-bg */
    /* --ng-on-accent n'est pas redefini : un texte fonce sur l'orange
       convient aux deux themes. */
    --ng-accent-soft:   #3a2a14;
    --ng-error:         #f2b8b5;
    --ng-error-soft:    #33211f;
    --ng-border:        #2e343a;
    --ng-border-strong: #454d55;
  }
}

/* Choix manuel sombre, prioritaire dans les deux sens. */
:root[data-theme="dark"] {
  --ng-bg:            #14171a;
  --ng-bg-alt:        #1e2226;
  --ng-text:          #e8eaed;
  --ng-text-muted:    #a3abb4;
  --ng-accent:        #ffa024;   /* contraste  8.8:1 sur --ng-bg */
  --ng-accent-strong: #ffbc5e;   /* contraste 10.8:1 sur --ng-bg */
  /* --ng-on-accent n'est pas redefini : un texte fonce sur l'orange
     convient aux deux themes. */
  --ng-accent-soft:   #3a2a14;
  --ng-error:         #f2b8b5;
  --ng-error-soft:    #33211f;
  --ng-border:        #2e343a;
  --ng-border-strong: #454d55;
}

/* Indique au navigateur la couleur des controles natifs (barres de
   defilement, champs de formulaire) pour chaque etat de theme. */
:root                    { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}


/* ==========================================================================
   2. REINITIALISATION ET BASE
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: var(--ng-header-clear);   /* respiration sous une ancre */
}

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

body {
  margin: 0;
  background: var(--ng-bg);
  color: var(--ng-text);
  font-family: var(--ng-font-sans);
  font-size: var(--ng-fs-body);
  line-height: var(--ng-lh-body);
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; }
img { display: block; }

a {
  color: var(--ng-accent);
  text-decoration-thickness: var(--ng-bw);
  text-underline-offset: 0.15em;
}
a:hover { color: var(--ng-accent-strong); }

/* Le focus visible n'est jamais supprime, il est seulement redessine. */
:focus-visible {
  outline: var(--ng-focus-w) solid var(--ng-accent);
  outline-offset: var(--ng-focus-off);
  border-radius: var(--ng-r-sm);
}

hr {
  border: 0;
  border-top: var(--ng-bw) solid var(--ng-border);
  margin: var(--ng-s6) 0;
}

code, kbd, samp, pre { font-family: var(--ng-font-mono); font-size: 0.9em; }


/* ==========================================================================
   3. UTILITAIRES MINIMAUX
   ========================================================================== */

.ng-vh {                       /* visible uniquement pour les technologies
                                  d'assistance */
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.ng-wrap {
  width: 100%;
  max-width: var(--ng-maxw-page);
  margin-inline: auto;
  padding-inline: var(--ng-gutter);
}

.ng-skip {
  position: absolute;
  left: var(--ng-s3);
  top: calc(-1 * var(--ng-s8));
  z-index: var(--ng-z-skip);
  padding: var(--ng-s2) var(--ng-s4);
  background: var(--ng-bg);
  color: var(--ng-accent);
  border: var(--ng-bw) solid var(--ng-accent);
  border-radius: var(--ng-r-md);
  font-weight: var(--ng-fw-medium);
  transition: top var(--ng-dur) ease;
}
.ng-skip:focus { top: var(--ng-s3); }


/* ==========================================================================
   4. ENTETE, NAVIGATION, LANGUES, THEME
   --------------------------------------------------------------------------
   Sans JavaScript, la navigation reste entierement deployee et utilisable.
   La classe ng-js est posee par le bloc ng:theme avant le premier rendu :
   elle seule active le repliement mobile et affiche le bouton d'ouverture.
   ========================================================================== */

.ng-header {
  /* Volontairement NON collante. Meme depuis que les langues sont dans un
     menu deroulant, la barre occupe deux lignes des que la navigation est
     deployee : collante, elle confisquerait une part notable du viewport
     mobile en permanence. Le sommaire lateral collant remplit le role de
     reperage sur les pages longues. Decision de l'editeur, voir CLAUDE.md. */
  z-index: var(--ng-z-header);
  background: var(--ng-bg);
  border-bottom: var(--ng-bw) solid var(--ng-border);
}

.ng-header-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ng-s3);
  min-height: var(--ng-s7);
  padding-block: var(--ng-s2);
}

/* L'ordre visuel est pilote ici et non par l'ordre du HTML, pour que le bloc
   ng:header reste identique au caractere pres dans les six langues. Les deux
   commandes, langue et theme, sont groupees a droite ; seule la navigation
   passe sur sa propre ligne. */
.ng-logo         { order: 1; }
.ng-nav-toggle   { order: 2; }
.ng-lang         { order: 3; }
.ng-theme-toggle { order: 4; }
.ng-nav          { order: 5; }

.ng-logo {
  font-weight: var(--ng-fw-bold);
  font-size: var(--ng-fs-lead);
  color: var(--ng-text);
  text-decoration: none;
  letter-spacing: -0.01em;
  margin-right: auto;
}
.ng-logo:hover { color: var(--ng-accent); }

/* Bouton d'ouverture du menu, masque tant que JavaScript n'a pas repondu. */
.ng-nav-toggle {
  display: none;
  align-items: center;
  gap: var(--ng-s2);
  padding: var(--ng-s2) var(--ng-s3);
  background: transparent;
  color: var(--ng-text);
  border: var(--ng-bw) solid var(--ng-border-strong);
  border-radius: var(--ng-r-md);
  font: inherit;
  font-size: var(--ng-fs-sm);
  cursor: pointer;
}
.ng-js .ng-nav-toggle { display: inline-flex; }
.ng-nav-toggle:hover { border-color: var(--ng-accent); color: var(--ng-accent); }

.ng-icon { width: 1em; height: 1em; fill: none; stroke: currentColor;
           stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.ng-nav {
  flex-basis: 100%;
  padding-bottom: var(--ng-s3);
}
.ng-js .ng-nav[data-ng-collapsed="true"] { display: none; }

.ng-nav-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--ng-s1) var(--ng-s4);
}

.ng-nav-link {
  display: inline-block;
  padding-block: var(--ng-s2);
  color: var(--ng-text-muted);
  font-size: var(--ng-fs-sm);
  text-decoration: none;
  border-bottom: var(--ng-focus-w) solid transparent;
}
.ng-nav-link:hover { color: var(--ng-accent); }
.ng-nav-link[aria-current="page"] {
  color: var(--ng-text);
  font-weight: var(--ng-fw-medium);
  border-bottom-color: var(--ng-accent);
}

/* --- Selecteur de langue -------------------------------------------------
   Menu deroulant natif, <details> et <summary>. Aucune ligne de JavaScript
   n'est necessaire : le comportement est le meme avec et sans, le clavier et
   les lecteurs d'ecran sont pris en charge par le navigateur, et la liste
   reste dans le DOM meme repliee, donc lisible par les robots.

   main.js n'ajoute qu'une commodite, la fermeture au clic exterieur et a la
   touche Echap, dont l'absence ne casse rien.

   Phase 1 : la langue courante est un span aria-current, les cinq autres
   sont des span aria-disabled sans href. Aucun lien, donc rien a suivre.
   ------------------------------------------------------------------------ */

.ng-lang { position: relative; }

/* Meme gabarit que la bascule de theme, elargi pour loger le code de langue. */
.ng-lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--ng-s2);
  height: var(--ng-s6);
  padding-inline: var(--ng-s3);
  background: transparent;
  color: var(--ng-text-muted);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
  font-size: var(--ng-fs-sm);
  cursor: pointer;
  list-style: none;              /* retire le triangle sur Firefox */
}
.ng-lang-toggle::-webkit-details-marker { display: none; }  /* et sur Safari */
.ng-lang-toggle:hover { color: var(--ng-accent); border-color: var(--ng-accent); }
.ng-lang-toggle .ng-icon { width: 1.125rem; height: 1.125rem; }
.ng-lang[open] > .ng-lang-toggle { color: var(--ng-accent); border-color: var(--ng-accent); }

.ng-lang-code { font-weight: var(--ng-fw-medium); letter-spacing: 0.02em; }

/* Le panneau s'ancre a droite : le bouton est en fin de barre, une ouverture
   vers la gauche est la seule qui reste dans la page sur mobile. */
.ng-lang-list {
  position: absolute;
  inset-inline-end: 0;
  z-index: 1;
  margin-block-start: var(--ng-s2);
  min-width: 100%;
  list-style: none;
  padding: var(--ng-s2);
  background: var(--ng-bg);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
  font-size: var(--ng-fs-sm);
}

.ng-lang-item { white-space: nowrap; }

.ng-lang-item > * {
  display: block;
  padding: var(--ng-s2) var(--ng-s3);
  border-radius: var(--ng-r-sm);
}

.ng-lang-item [aria-current="true"] {
  color: var(--ng-text);
  font-weight: var(--ng-fw-medium);
}

.ng-lang-item [aria-disabled="true"] {
  color: var(--ng-text-muted);
  opacity: 0.55;
  cursor: default;
}

.ng-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--ng-s6);
  height: var(--ng-s6);
  padding: 0;
  background: transparent;
  color: var(--ng-text-muted);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
  cursor: pointer;
}
.ng-theme-toggle:hover { color: var(--ng-accent); border-color: var(--ng-accent); }
.ng-theme-toggle .ng-icon { width: 1.125rem; height: 1.125rem; }
/* Le pictogramme lune ne s'affiche qu'en theme clair, et inversement. */
.ng-theme-toggle [data-ng-icon="dark"]  { display: block; }
.ng-theme-toggle [data-ng-icon="light"] { display: none; }
:root[data-theme="dark"] .ng-theme-toggle [data-ng-icon="dark"]  { display: none; }
:root[data-theme="dark"] .ng-theme-toggle [data-ng-icon="light"] { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ng-theme-toggle [data-ng-icon="dark"]  { display: none; }
  :root:not([data-theme="light"]) .ng-theme-toggle [data-ng-icon="light"] { display: block; }
}


/* ==========================================================================
   5. STRUCTURE DE PAGE
   ========================================================================== */

.ng-main {
  display: block;
  padding-block: var(--ng-s6) var(--ng-s8);
}

.ng-breadcrumb {
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
  margin-block: var(--ng-s5);
}
.ng-breadcrumb ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--ng-s2);
}
.ng-breadcrumb li + li::before {
  content: "/";
  margin-right: var(--ng-s2);
  color: var(--ng-border-strong);
}
.ng-breadcrumb [aria-current="page"] { color: var(--ng-text); }


/* ==========================================================================
   6. ARTICLE : GABARIT COMMUN AUX PILIERS ET AUX GUIDES
   --------------------------------------------------------------------------
   Enfants directs de .ng-article, dans cet ordre :
     1 .ng-article-head   (h1, bloc reponse directe, fil d'Ariane)
     2 .ng-toc            (sommaire ancre, statique)
     3 .ng-prose          (corps)
     4 .ng-index          (index des guides, sur les piliers uniquement)
     5 .ng-faq
     6 .ng-related        (pour aller plus loin)
     7 .ng-article-foot   (CTA puis signature et date)
   Le sommaire couvre volontairement bien plus de lignes qu'il n'y en a, pour
   que l'ajout d'une section au gabarit ne demande aucune retouche du CSS.
   Cela n'ajoute aucune hauteur tant que row-gap reste nul sur la grille.
   ========================================================================== */

/* Filet pour les noms de constante cites en texte brut, dans une reponse de
   FAQ qui ne peut porter aucune balise : un mot ne se coupe que s'il ne tient
   pas seul sur une ligne, le reste du texte n'est pas touche. */
.ng-article { display: block; overflow-wrap: break-word; }

.ng-article-head { max-width: var(--ng-maxw-prose); }

.ng-article h1 {
  font-size: var(--ng-fs-h1);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
  letter-spacing: -0.015em;
  margin: 0 0 var(--ng-s4);
}

/* --- Bloc reponse directe -------------------------------------------------
   Le paragraphe de 40 a 60 mots que les moteurs generatifs extraient.
   Il doit rester lisible hors contexte, donc visuellement distinct sans
   ressembler a un encart secondaire.
   ------------------------------------------------------------------------ */
.ng-answer {
  margin: 0 0 var(--ng-s5);
  padding: var(--ng-s4) var(--ng-s5);
  background: var(--ng-accent-soft);
  border-left: var(--ng-focus-w) solid var(--ng-accent);
  border-radius: 0 var(--ng-r-md) var(--ng-r-md) 0;
  font-size: var(--ng-fs-lead);
  line-height: var(--ng-lh-body);
}
.ng-answer p { margin: 0; }

/* --- Sommaire ancre, entierement statique -------------------------------- */
.ng-toc {
  max-width: var(--ng-maxw-prose);
  margin-block: 0 var(--ng-s6);
  padding: var(--ng-s4) var(--ng-s5);
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
}
.ng-toc-title {
  margin: 0 0 var(--ng-s3);
  font-size: var(--ng-fs-xs);
  font-weight: var(--ng-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ng-text-muted);
}
.ng-toc ol { list-style: none; margin: 0; padding: 0; }
.ng-toc ol ol { margin-top: var(--ng-s1); padding-left: var(--ng-s4); }
.ng-toc li { margin-bottom: var(--ng-s2); font-size: var(--ng-fs-sm); }
.ng-toc a { text-decoration: none; }
.ng-toc a:hover { text-decoration: underline; }


/* ==========================================================================
   7. TYPOGRAPHIE DU CORPS
   ========================================================================== */

.ng-prose { max-width: var(--ng-maxw-prose); }

.ng-prose > * { margin-block: 0 var(--ng-s4); }

.ng-prose h2 {
  margin-block: var(--ng-s7) var(--ng-s4);
  font-size: var(--ng-fs-h2);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
  letter-spacing: -0.01em;
}

.ng-prose h3 {
  margin-block: var(--ng-s6) var(--ng-s3);
  font-size: var(--ng-fs-h3);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-medium);
}

.ng-prose p  { margin-block: 0 var(--ng-s4); }
.ng-prose ul,
.ng-prose ol { margin-block: 0 var(--ng-s4); padding-left: var(--ng-s5); }
.ng-prose li { margin-bottom: var(--ng-s2); }
.ng-prose li > ul,
.ng-prose li > ol { margin-block: var(--ng-s2) 0; }

.ng-prose strong { font-weight: var(--ng-fw-medium); }

/* Un nom de constante Android depasse la colonne a 375 px
   (android.permission.DISPATCH_NFC_MESSAGE) : il se coupe alors, et seulement
   s'il ne tient pas seul sur une ligne. */
.ng-prose code {
  overflow-wrap: anywhere;
  padding: 0.1em 0.35em;
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-sm);
}

.ng-prose blockquote {
  margin-inline: 0;
  padding-left: var(--ng-s4);
  border-left: var(--ng-focus-w) solid var(--ng-border-strong);
  color: var(--ng-text-muted);
}

/* --- Encart de mise en garde ou de precision ----------------------------- */
.ng-callout {
  margin-block: var(--ng-s5);
  padding: var(--ng-s4) var(--ng-s5);
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border);
  border-left-width: var(--ng-focus-w);
  border-left-color: var(--ng-border-strong);
  border-radius: var(--ng-r-md);
  font-size: var(--ng-fs-sm);
}
.ng-callout > :last-child { margin-bottom: 0; }
.ng-callout-title {
  margin: 0 0 var(--ng-s2);
  font-size: var(--ng-fs-xs);
  font-weight: var(--ng-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ng-text-muted);
}
.ng-callout[data-ng-tone="warn"] {
  background: var(--ng-error-soft);
  border-left-color: var(--ng-error);
}
.ng-callout[data-ng-tone="warn"] .ng-callout-title { color: var(--ng-error); }


/* ==========================================================================
   8. TABLEAUX
   --------------------------------------------------------------------------
   Toute donnee comparative passe par un tableau HTML, jamais par une image.
   Le conteneur defile horizontalement pour que le corps de page, lui, ne
   defile jamais lateralement.
   ========================================================================== */

.ng-table-wrap {
  max-width: var(--ng-maxw-prose);
  margin-block: var(--ng-s5);
  overflow-x: auto;
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
}

.ng-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--ng-fs-sm);
}

.ng-table caption {
  padding: var(--ng-s3) var(--ng-s4);
  text-align: left;
  font-size: var(--ng-fs-xs);
  color: var(--ng-text-muted);
  border-bottom: var(--ng-bw) solid var(--ng-border);
}

.ng-table th,
.ng-table td {
  padding: var(--ng-s3) var(--ng-s4);
  text-align: left;
  vertical-align: top;
  border-bottom: var(--ng-bw) solid var(--ng-border);
}

.ng-table thead th {
  background: var(--ng-bg-alt);
  font-weight: var(--ng-fw-medium);
  white-space: nowrap;
}

.ng-table tbody th { font-weight: var(--ng-fw-medium); }
.ng-table tbody tr:last-child th,
.ng-table tbody tr:last-child td { border-bottom: 0; }


/* ==========================================================================
   9. ILLUSTRATIONS
   --------------------------------------------------------------------------
   Les schemas sont des SVG inline. Ils heritent des couleurs du theme par
   currentColor et par les variables ci-dessous, donc aucun fichier n'est a
   dupliquer entre les six langues.
   ========================================================================== */

.ng-figure {
  max-width: var(--ng-maxw-prose);
  margin: var(--ng-s6) 0;
}

.ng-figure > svg,
.ng-figure > img {
  width: 100%;
  height: auto;
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
}

.ng-figure figcaption {
  margin-top: var(--ng-s3);
  font-size: var(--ng-fs-sm);
  line-height: var(--ng-lh-ui);
  color: var(--ng-text-muted);
}

/* Jetons dedies aux schemas inline. */
.ng-svg {
  --ng-svg-line:  var(--ng-border-strong);
  --ng-svg-fill:  var(--ng-bg);
  --ng-svg-key:   var(--ng-accent);
  --ng-svg-label: var(--ng-text);
  --ng-svg-muted: var(--ng-text-muted);
  color: var(--ng-svg-label);
  font-family: var(--ng-font-sans);
}
.ng-svg text        { fill: var(--ng-svg-label); font-size: 13px; }
.ng-svg text.ng-svg-sm { fill: var(--ng-svg-muted); font-size: 11px; }
.ng-svg .ng-svg-box { fill: var(--ng-svg-fill); stroke: var(--ng-svg-line); stroke-width: 1.5; }
.ng-svg .ng-svg-key { stroke: var(--ng-svg-key); fill: none; stroke-width: 1.5; }
.ng-svg .ng-svg-dim { stroke: var(--ng-svg-line); fill: none; stroke-width: 1; }


/* ==========================================================================
   10. FAQ, LIENS CONNEXES, ACCORDEONS
   --------------------------------------------------------------------------
   La FAQ n'est PAS un accordeon : ses reponses restent ouvertes en
   permanence, pour que les moteurs generatifs les extraient sans avoir a
   simuler une interaction, et pour que le JSON-LD FAQPage decrive
   exactement ce qui est visible.
   L'accordeon .ng-accordion s'appuie sur <details>, donc il fonctionne au
   clavier sans une ligne de JavaScript.
   ========================================================================== */

.ng-faq,
.ng-related {
  max-width: var(--ng-maxw-prose);
  margin-top: var(--ng-s7);
  padding-top: var(--ng-s5);
  border-top: var(--ng-bw) solid var(--ng-border);
}

.ng-faq h2,
.ng-related h2 {
  margin: 0 0 var(--ng-s5);
  font-size: var(--ng-fs-h2);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
}

.ng-faq-item { margin-bottom: var(--ng-s5); }
.ng-faq-item h3 {
  margin: 0 0 var(--ng-s2);
  font-size: var(--ng-fs-h3);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-medium);
}
.ng-faq-item p { margin: 0 0 var(--ng-s3); }
.ng-faq-item > :last-child { margin-bottom: 0; }

.ng-related-list { list-style: none; margin: 0; padding: 0; }
.ng-related-list li { margin-bottom: var(--ng-s3); }
.ng-related-list .ng-related-note {
  display: block;
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}

.ng-accordion {
  margin-block: var(--ng-s4);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-md);
  overflow: hidden;
}
.ng-accordion > summary {
  padding: var(--ng-s3) var(--ng-s4);
  background: var(--ng-bg-alt);
  font-weight: var(--ng-fw-medium);
  cursor: pointer;
}
.ng-accordion > summary:hover { color: var(--ng-accent); }
.ng-accordion[open] > summary { border-bottom: var(--ng-bw) solid var(--ng-border); }
.ng-accordion-body { padding: var(--ng-s4); }
.ng-accordion-body > :last-child { margin-bottom: 0; }


/* ==========================================================================
   10 bis. INDEX DES GUIDES D'UN PILIER
   --------------------------------------------------------------------------
   Dimensionne pour cinquante entrees et plus. Trois partis pris :

   1. Titre seul, sans ligne de description. A cinquante entrees la
      lisibilite passe avant la richesse, et chaque description serait un
      texte supplementaire a traduire six fois. Les titres de guides sont
      deja formules comme des questions, ils se suffisent.
   2. Colonnes CSS plutot que cartes. Une grille de cartes a cinquante
      entrees fait trois ecrans de defilement, trois colonnes de titres en
      font un demi.
   3. Les grappes thematiques sont un regroupement d'AFFICHAGE. Elles ne
      creent jamais un troisieme niveau d'URL : la structure reste
      /{pilier}/{guide}/, sans exception.
   ========================================================================== */

.ng-index {
  margin-top: var(--ng-s7);
  padding-top: var(--ng-s5);
  border-top: var(--ng-bw) solid var(--ng-border);
}

.ng-index > h2 {
  margin: 0 0 var(--ng-s4);
  font-size: var(--ng-fs-h2);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
}

.ng-index-meta {
  margin: 0 0 var(--ng-s4);
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}

/* Renvois vers les grappes, pour eviter d'imposer un defilement complet
   quand le pilier compte plusieurs dizaines d'entrees. */
.ng-index-jump {
  list-style: none;
  margin: 0 0 var(--ng-s6);
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--ng-s2) var(--ng-s4);
  font-size: var(--ng-fs-sm);
}

.ng-index-group { margin-bottom: var(--ng-s6); }
.ng-index-group:last-child { margin-bottom: 0; }

.ng-index-group > h3 {
  margin: 0 0 var(--ng-s4);
  padding-bottom: var(--ng-s2);
  border-bottom: var(--ng-bw) solid var(--ng-border);
  font-size: var(--ng-fs-xs);
  font-weight: var(--ng-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ng-text-muted);
  scroll-margin-top: var(--ng-s5);
}

.ng-index-list {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 1;
  column-gap: var(--ng-s6);
}

.ng-index-list li {
  break-inside: avoid;
  margin-bottom: var(--ng-s3);
  font-size: var(--ng-fs-sm);
  line-height: var(--ng-lh-ui);
}

.ng-index-list a { text-decoration: none; }
.ng-index-list a:hover { text-decoration: underline; }


/* ==========================================================================
   11. BLOC D'APPEL A L'ACTION
   --------------------------------------------------------------------------
   Un seul par page, apres la FAQ. Deux variantes exclusives :
   data-ng-cta="cards" pour nfc.cards, data-ng-cta="tools" pour NFC Tools.
   Ne jamais afficher les deux sur une meme page.
   ========================================================================== */

.ng-cta {
  max-width: var(--ng-maxw-prose);
  margin-top: var(--ng-s7);
  padding: var(--ng-s5);
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border-strong);
  border-radius: var(--ng-r-lg);
}
.ng-cta-label {
  margin: 0 0 var(--ng-s2);
  font-size: var(--ng-fs-xs);
  font-weight: var(--ng-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ng-text-muted);
}
.ng-cta h2 {
  margin: 0 0 var(--ng-s3);
  font-size: var(--ng-fs-h3);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-medium);
}

/* Icone de l'application, seule image posee dans une page de contenu. Elle
   est decorative : le titre a cote nomme deja l'application, donc son alt
   reste vide, faute de quoi un lecteur d'ecran annoncerait deux fois « NFC
   Tools ». Les dimensions sont aussi portees en attributs, pour que la place
   soit reservee avant le chargement. */
.ng-cta-head {
  display: flex;
  align-items: center;
  gap: var(--ng-s4);
  margin-bottom: var(--ng-s3);
}

/* Le titre, puis sa ligne de service en dessous, empiles dans la hauteur de
   l'icone. Les marges des deux elements sont annulees et l'ecart passe par
   le gap, faute de quoi la pile depasse l'icone et c'est le texte qui fixe
   la hauteur de la rangee.

   Le libelle porte ici sa taille et son interligne parce que « .ng-cta p »,
   plus specifique que « .ng-cta-label », lui imposait sinon celles d'un
   paragraphe. */
.ng-cta-head > div {
  display: flex;
  flex-direction: column;
  gap: var(--ng-s1);
  min-width: 0;
}
.ng-cta-head h2 { margin: 0; }
.ng-cta-head .ng-cta-label {
  margin: 0;
  font-size: var(--ng-fs-xs);
  line-height: var(--ng-lh-tight);
}
/* La tuile claire sert au logo nfc.cards, dont l'arc exterieur est gris
   fonce sur fond transparent et se perdrait dans le theme sombre. Elle est
   invisible derriere le logo NFC Tools, qui est un carre orange opaque, donc
   la meme regle sert les deux. Ce blanc n'est pas une couleur de theme mais
   le fond du logo : il ne passe pas par un jeton et ne suit pas le theme. */
.ng-cta-icon {
  flex: none;
  width: 56px;
  height: 56px;
  border-radius: var(--ng-r-lg);
  background: #fff;
}
.ng-cta p { margin: 0 0 var(--ng-s4); font-size: var(--ng-fs-sm); }
.ng-cta-actions { display: flex; flex-wrap: wrap; gap: var(--ng-s3); }

/* Logos de plateforme dans les boutons de telechargement. Les fichiers sont
   des glyphes noirs sur fond transparent : ils servent de MASQUE, et la
   couleur vient de currentColor, donc du bouton. Le glyphe suit ainsi son
   libelle, fonce sur le bouton principal et accent sur le bouton discret,
   sans regle par theme.

   Pose en <img>, le glyphe resterait noir et disparaitrait sur le bouton
   discret du theme sombre, ou le fond est sombre lui aussi. C'est la meme
   logique que .ng-icon, qui suit currentColor par son stroke.

   La taille est en em pour suivre le libelle si la charte typographique
   bouge. Le prefixe webkit reste necessaire pour Safari. */
.ng-btn-icon {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  background: currentColor;
  -webkit-mask: center / contain no-repeat;
  mask: center / contain no-repeat;
}
.ng-btn-icon[data-ng-store="apple"] {
  -webkit-mask-image: url("/assets/img/store-apple.png");
  mask-image: url("/assets/img/store-apple.png");
}
.ng-btn-icon[data-ng-store="android"] {
  -webkit-mask-image: url("/assets/img/store-android.png");
  mask-image: url("/assets/img/store-android.png");
}
.ng-btn-icon[data-ng-store="web"] {
  -webkit-mask-image: url("/assets/img/store-web.png");
  mask-image: url("/assets/img/store-web.png");
}

.ng-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--ng-s2);
  padding: var(--ng-s3) var(--ng-s5);
  border-radius: var(--ng-r-md);
  font-size: var(--ng-fs-sm);
  font-weight: var(--ng-fw-medium);
  line-height: var(--ng-lh-ui);
  text-decoration: none;
  border: var(--ng-bw) solid var(--ng-accent);
  background: var(--ng-accent);
  color: var(--ng-on-accent);
  cursor: pointer;
}
.ng-btn:hover { background: var(--ng-accent-strong); border-color: var(--ng-accent-strong); color: var(--ng-on-accent); }
.ng-btn[data-ng-variant="quiet"] {
  background: transparent;
  color: var(--ng-accent);
}
.ng-btn[data-ng-variant="quiet"]:hover { background: var(--ng-accent-soft); color: var(--ng-accent-strong); }


/* ==========================================================================
   12. SIGNATURE, DATE, BLOC AUTEUR
   ========================================================================== */

.ng-article-foot { max-width: var(--ng-maxw-prose); }

.ng-byline {
  margin-top: var(--ng-s6);
  padding-top: var(--ng-s4);
  border-top: var(--ng-bw) solid var(--ng-border);
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}


/* ==========================================================================
   13. ACCUEIL ET PAGES DE PILIER : GRILLES DE CARTES
   ========================================================================== */

.ng-hero {
  max-width: var(--ng-maxw-prose);
  margin-block: var(--ng-s5) var(--ng-s7);
}
.ng-hero h1 {
  margin: 0 0 var(--ng-s4);
  font-size: var(--ng-fs-display);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
  letter-spacing: -0.02em;
}
.ng-hero-lead {
  margin: 0;
  font-size: var(--ng-fs-lead);
  color: var(--ng-text-muted);
}

.ng-section { margin-top: var(--ng-s8); }
.ng-section > h2 {
  margin: 0 0 var(--ng-s5);
  font-size: var(--ng-fs-h2);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-bold);
}
.ng-section-intro {
  max-width: var(--ng-maxw-prose);
  margin: calc(-1 * var(--ng-s3)) 0 var(--ng-s5);
  color: var(--ng-text-muted);
}

.ng-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ng-s4);
}

.ng-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--ng-s5);
  background: var(--ng-bg);
  border: var(--ng-bw) solid var(--ng-border);
  border-radius: var(--ng-r-lg);
}
.ng-card:hover { border-color: var(--ng-accent); }
.ng-card h3 {
  margin: 0 0 var(--ng-s2);
  font-size: var(--ng-fs-h3);
  line-height: var(--ng-lh-tight);
  font-weight: var(--ng-fw-medium);
}
.ng-card h3 a { text-decoration: none; }
.ng-card h3 a:hover { text-decoration: underline; }
.ng-card p {
  margin: 0 0 var(--ng-s3);
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}
.ng-card > :last-child { margin-bottom: 0; }
.ng-card-count {
  margin-top: auto;
  padding-top: var(--ng-s3);
  font-size: var(--ng-fs-xs);
  color: var(--ng-text-muted);
}

/* Rubrique annoncee mais pas encore publiee. Meme dispositif que le
   selecteur de langue : aucun href, donc aucune URL vide a indexer et
   aucun lien mort. Le marqueur ng:sections permet de l'activer d'un coup
   le jour ou la page existe. */
.ng-card[data-ng-state="planned"] { border-style: dashed; }
.ng-card[data-ng-state="planned"]:hover { border-color: var(--ng-border); }
.ng-card [aria-disabled="true"] { color: var(--ng-text-muted); cursor: default; }


/* ==========================================================================
   14. RECHERCHE INTERNE
   --------------------------------------------------------------------------
   La liste complete des pages reste presente dans le HTML en permanence.
   Elle sert de repli si le JSON ne se charge pas, et elle rend la page
   indexable sans JavaScript.
   ========================================================================== */

.ng-search { max-width: var(--ng-maxw-prose); }

.ng-search-field { margin-block: var(--ng-s5); }
.ng-search-label {
  display: block;
  margin-bottom: var(--ng-s2);
  font-size: var(--ng-fs-sm);
  font-weight: var(--ng-fw-medium);
}
.ng-search-input {
  width: 100%;
  padding: var(--ng-s3) var(--ng-s4);
  background: var(--ng-bg);
  color: var(--ng-text);
  border: var(--ng-bw) solid var(--ng-border-strong);
  border-radius: var(--ng-r-md);
  font: inherit;
  font-size: var(--ng-fs-body);
}
.ng-search-input:hover { border-color: var(--ng-accent); }

.ng-search-status {
  margin-block: var(--ng-s4);
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}
.ng-search-status[data-ng-tone="error"] { color: var(--ng-error); }

.ng-search-results { list-style: none; margin: 0; padding: 0; }
.ng-search-results li {
  padding-block: var(--ng-s4);
  border-bottom: var(--ng-bw) solid var(--ng-border);
}
.ng-search-results a {
  font-size: var(--ng-fs-lead);
  font-weight: var(--ng-fw-medium);
  text-decoration: none;
}
.ng-search-results a:hover { text-decoration: underline; }
.ng-search-cat {
  display: block;
  margin-bottom: var(--ng-s1);
  font-size: var(--ng-fs-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ng-text-muted);
}
.ng-search-desc {
  margin: var(--ng-s2) 0 0;
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}
.ng-search-mark { background: var(--ng-accent-soft); color: inherit; }

.ng-search-fallback { margin-top: var(--ng-s7); }


/* ==========================================================================
   15. OPPOSITION A LA MESURE D'AUDIENCE (page politique de cookies)
   ========================================================================== */

.ng-optout {
  max-width: var(--ng-maxw-prose);
  margin-block: var(--ng-s6);
  padding: var(--ng-s5);
  background: var(--ng-bg-alt);
  border: var(--ng-bw) solid var(--ng-border-strong);
  border-radius: var(--ng-r-lg);
}
.ng-optout h2 {
  margin: 0 0 var(--ng-s3);
  font-size: var(--ng-fs-h3);
  font-weight: var(--ng-fw-medium);
}
.ng-optout-state {
  margin: 0 0 var(--ng-s4);
  font-size: var(--ng-fs-sm);
}
.ng-optout-state strong { font-weight: var(--ng-fw-bold); }
.ng-optout-state[data-ng-state="off"] strong { color: var(--ng-error); }

.ng-optout-note {
  margin: var(--ng-s4) 0 0;
  font-size: var(--ng-fs-xs);
  line-height: var(--ng-lh-ui);
  color: var(--ng-text-muted);
}

/* Adresse de courriel, ecrite « nom [at] domaine » et jamais en clair. La
   regle empeche seulement la coupure de ligne au milieu de l'adresse. */
.ng-mail { white-space: nowrap; }

.ng-search-fallback > h2 {
  margin: 0 0 var(--ng-s4);
  padding-top: var(--ng-s5);
  border-top: var(--ng-bw) solid var(--ng-border);
  font-size: var(--ng-fs-h3);
  font-weight: var(--ng-fw-medium);
}


/* ==========================================================================
   16. PIED DE PAGE
   ========================================================================== */

.ng-footer {
  margin-top: var(--ng-s8);
  padding-block: var(--ng-s6);
  background: var(--ng-bg-alt);
  border-top: var(--ng-bw) solid var(--ng-border);
  font-size: var(--ng-fs-sm);
  color: var(--ng-text-muted);
}

.ng-footer-cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--ng-s5);
  margin-bottom: var(--ng-s6);
}

.ng-footer h2 {
  margin: 0 0 var(--ng-s3);
  font-size: var(--ng-fs-xs);
  font-weight: var(--ng-fw-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ng-text);
}

.ng-footer ul { list-style: none; margin: 0; padding: 0; }
.ng-footer li { margin-bottom: var(--ng-s2); }

.ng-footer-legal {
  padding-top: var(--ng-s5);
  border-top: var(--ng-bw) solid var(--ng-border);
  font-size: var(--ng-fs-xs);
}
.ng-footer-legal p { margin: 0 0 var(--ng-s3); }

.ng-footer-legalnav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ng-s2) var(--ng-s4);
}
.ng-footer-legalnav li { margin-bottom: 0; }


/* ==========================================================================
   17. POINT DE RUPTURE 1 : 48rem
   ========================================================================== */

@media (min-width: 48rem) {
  :root {
    --ng-fs-body:    1.125rem;   /* 18px */
    --ng-fs-lead:    1.25rem;
    --ng-fs-h3:      1.375rem;
    --ng-fs-h2:      1.75rem;
    --ng-fs-h1:      2.25rem;
    --ng-fs-display: 2.75rem;
    --ng-gutter:     var(--ng-s5);

  }

  .ng-header-bar { min-height: auto; }
  .ng-nav { padding-bottom: 0; }

  /* Au dela de cette largeur, la navigation est toujours deployee et le
     bouton d'ouverture disparait, y compris quand JavaScript est actif. */
  .ng-js .ng-nav-toggle { display: none; }
  .ng-js .ng-nav[data-ng-collapsed="true"] { display: block; }

  .ng-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ng-footer-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ng-index-list { columns: 2; }
  .ng-answer { padding: var(--ng-s5) var(--ng-s6); }
}


/* ==========================================================================
   18. POINT DE RUPTURE 2 : 64rem
   --------------------------------------------------------------------------
   Le sommaire quitte le flux et devient une colonne collante a droite.
   Il reste au meme endroit dans le HTML, seul son placement change.
   Attention : row-gap doit rester nul, sinon le span de .ng-toc ajoute
   autant d'espaces vides que de lignes traversees.
   ========================================================================== */

@media (min-width: 64rem) {
  :root { --ng-gutter: var(--ng-s6); }

  .ng-article:has(> .ng-toc) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--ng-w-aside);
    column-gap: var(--ng-s7);
    row-gap: 0;
    align-items: start;
  }

  .ng-article > *          { grid-column: 1; min-width: 0; }
  .ng-article-head         { grid-column: 1 / -1; }

  .ng-article > .ng-toc {
    grid-column: 2;
    grid-row: 2 / span 20;     /* marge deliberee, voir section 6 */
    position: sticky;
    top: var(--ng-s5);
    align-self: start;
    max-height: calc(100vh - var(--ng-s6));
    overflow-y: auto;
    margin: 0;
    background: transparent;
    border: 0;
    border-left: var(--ng-bw) solid var(--ng-border);
    border-radius: 0;
    padding: var(--ng-s1) 0 var(--ng-s1) var(--ng-s4);
  }

  .ng-grid        { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ng-footer-cols { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ng-index-list  { columns: 3; }
}
