/* ─────────────────────────────────────────────────────────────
   find — Couche de base & composants

   Voir tokens.css pour la raison du fond sombre : la carte est claire,
   et c'est elle qui doit eclairer l'ecran.

   Deux regles portees ici :
     - toute DONNEE MESUREE est en mono tabulaire (.data) ;
     - les actions sont douces, les donnees sont vives (rayons).
   ───────────────────────────────────────────────────────────── */

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

/* ⚠️ L'attribut `hidden` doit TOUJOURS gagner, et sans cette regle il perd.
   `hidden` ne vaut que par une declaration de la feuille du navigateur, qu'une
   simple `display: inline-flex` d'auteur suffit a battre. Le defaut est
   silencieux et trompeur : l'element est bel et bien masque du point de vue de
   l'accessibilite, mais il reste PEINT a l'ecran.

   Il avait deja mordu cinq fois dans ce depot — #app-android et #app-ios
   s'affichaient sur sept vues alors qu'aucun APK n'est publie (donc un 404 au
   clic), #plage sur la carte etait visible sans qu'on ait choisi « Periode
   precise », et la barre de lecture de /resume apparaissait avant tout
   chargement, ce qui faisait que « Lecture » ne repondait pas.

   Une regle par classe ne ferme rien : le piege revient a la classe suivante.
   `!important` est ici l'emploi canonique — il rend a `hidden` l'autorite que
   la specification lui donne. */
[hidden] { display: none !important; }

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

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

::selection { background: var(--accent-dim); color: var(--ink); }

/* ── Typographie ── */
h1, h2, h3 { line-height: 1.15; font-weight: var(--fw-semibold); text-wrap: balance; }
p { text-wrap: pretty; }

.headline { font-size: var(--fs-headline); font-weight: var(--fw-semibold); letter-spacing: -0.015em; }
.title    { font-size: var(--fs-title);    font-weight: var(--fw-semibold); }
.muted    { color: var(--slate); }
.faint    { color: var(--faint); }

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

/* ⚠️ Toute valeur mesuree — coordonnee, pourcentage, horodatage,
   identifiant technique. `tabular-nums` aligne les chiffres colonne par
   colonne : deux latitudes voisines se comparent d'un coup d'oeil au
   lieu de se compter. */
.data {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.92em;
  letter-spacing: -0.01em;
}

/* ── Layout helpers ── */
.container { width: 100%; max-width: 1080px; margin-inline: auto; padding-inline: var(--sp-5); }
.container--narrow { max-width: 420px; }
.stack > * + * { margin-top: var(--sp-4); }
.stack-2 > * + * { margin-top: var(--sp-2); }
.row { display: flex; align-items: center; gap: var(--sp-3); }
.spacer { flex: 1; }
.center-screen { min-height: 100vh; display: grid; place-items: center; padding: var(--sp-5); }

/* ── Focus visible ── */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ── Boutons ── */
.btn {
  --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: var(--border-2);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font: inherit; font-weight: var(--fw-medium); font-size: var(--fs-sm);
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd); border-radius: var(--r-md);
  padding: 0.55rem 0.95rem; cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; }
.btn[disabled]:hover { background: var(--btn-bg); }

/* ⚠️ Texte SOMBRE sur l'ambre. Blanc sur ambre tourne autour de 2:1 et
   devient illisible des qu'on baisse la luminosite de l'ecran. */
.btn--primary { --btn-bg: var(--accent-2); --btn-fg: var(--on-accent); --btn-bd: var(--accent-2); }
.btn--primary:hover { background: var(--accent); --btn-bd: var(--accent); }

.btn--ghost { --btn-bd: var(--border); }
.btn--ghost:hover { background: var(--surface-2); }

.btn--danger { --btn-fg: var(--danger); --btn-bd: var(--border-2); }
.btn--danger:hover { background: var(--danger-bg); --btn-bd: var(--danger); }

.btn--sm { font-size: var(--fs-label); padding: 0.35rem 0.6rem; border-radius: var(--r-sm); }
.btn--block { width: 100%; }

/* ── Champs ── */
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field__label { font-size: var(--fs-label); font-weight: var(--fw-medium); color: var(--slate); }

input, select, textarea {
  font: inherit; font-size: var(--fs-sm); color: var(--ink);
  background: oklch(12% 0.012 265); border: 1px solid var(--border-2); border-radius: var(--r-md);
  padding: 0.6rem 0.75rem; width: 100%;
  transition: border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
}
/* Le champ est plus SOMBRE que la carte qui le porte : c'est ce creux qui
   dit « on ecrit ici ». Sur fond sombre, un champ plus clair que son
   support ressemble a un bloc de texte deja rempli. */
input::placeholder { color: var(--faint); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px oklch(80% 0.155 78 / 0.18);
}
/* ⚠️ Le selecteur porte sur la CLASSE, pas sur `select`. Ecrit
   `select.select--inline`, il laissait les `<input>` qui portent la meme classe
   retomber sur la regle generique `input, select, textarea { width: 100% }` —
   les deux champs date-heure de /resume prenaient donc toute la largeur, et il
   fallait parcourir l'ecran entier pour atteindre le calendrier. */
.select--inline { width: auto; min-width: 9rem; padding: 0.4rem 0.6rem; }

/* Un champ date-heure affiche « 27/08/2026 11:10 » plus son icone : 9rem ne
   suffisent pas, le texte serait tronque par le controle natif. */
input.select--inline[type="datetime-local"] { min-width: 11.5rem; }

/* Le remplissage automatique de Chrome force un fond blanc et un texte noir,
   ce qui creve un theme sombre. Le seul levier fiable est une ombre interne
   assez large pour recouvrir le champ. */
input:-webkit-autofill,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--ink);
  box-shadow: 0 0 0 1000px oklch(12% 0.012 265) inset;
}

/* ── Surfaces ── */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--sp-6);
}

/* ── Accordeon de reglages ──
   Meme mecanique que le menu de la barre : <details>/<summary>, donc
   ouverture, fermeture et pilotage clavier natifs, sans une ligne de
   JavaScript.

   ⚠️ Ce n'est pas une carte qui se replie, c'est un SOMMAIRE. Quatre reglages
   sans rapport les uns avec les autres — essai, emails, pays, fournisseur
   d'identite — tenaient sur une page de plusieurs ecrans qu'il fallait
   parcourir pour savoir ce qui existait. Replies, ils tiennent tous a l'ecran
   d'un coup, et la page dit enfin ce qu'elle sait regler. */
.acc {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

.acc > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-6);
  font-size: var(--fs-title); font-weight: var(--fw-semibold);
  border-radius: var(--r-lg);
}
.acc > summary::-webkit-details-marker { display: none; }
.acc > summary:hover { background: var(--surface-2); }

/* Le titre reste un <h2> a l'interieur du resume : replies, ces blocs sont
   toute la structure de la page, et un lecteur d'ecran doit pouvoir les
   parcourir comme des titres. Il herite donc de la taille du resume. */
.acc > summary > .title { font-size: inherit; }

/* Le chevron est a droite : c'est la que l'oeil va chercher l'etat d'une
   ligne pleine largeur, alors qu'un marqueur colle au titre se lit comme une
   puce. */
.acc > summary::after {
  content: "";
  margin-left: auto;
  border: 5px solid transparent;
  border-top-color: var(--slate);
  transform: translateY(3px);
  transition: transform var(--dur-fast) var(--ease-out);
}
.acc[open] > summary::after { transform: translateY(-2px) rotate(180deg); }

/* Ouvert, l'en-tete cesse d'etre un bloc autonome et devient le haut du
   panneau : le trait dit ou commence le contenu. */
.acc[open] > summary {
  border-bottom: 1px solid var(--border);
  border-end-start-radius: 0; border-end-end-radius: 0;
}

.acc__body { padding: var(--sp-6); }

.badge {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font-size: var(--fs-label); font-weight: var(--fw-medium);
  padding: 0.15rem 0.5rem; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--slate); border: 1px solid var(--border);
}
.badge--accent { background: var(--accent-bg); color: var(--accent); border-color: var(--accent-dim); }
.badge--stale  { background: var(--warn-bg); color: var(--warn); border-color: oklch(45% 0.09 78); }
.badge--danger { background: var(--danger-bg); color: var(--danger); border-color: oklch(45% 0.10 25); }

/* ── Message inline ── */
.msg { font-size: var(--fs-sm); padding: 0.5rem 0.75rem; border-radius: var(--r-md); }
.msg--err { background: var(--danger-bg); color: var(--danger); }
.msg--ok  { background: var(--success-bg); color: var(--success); }

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

/* ─────────────────────────────────────────────────────────────
   Shell de la carte
   ───────────────────────────────────────────────────────────── */

body.map-page { height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }

.appbar {
  position: relative; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5);
  background: oklch(12% 0.012 265);
  border-bottom: 1px solid var(--border);
}

/* ⚠️ Le point ambre du logo n'est pas un ornement : c'est le meme signal
   que le marqueur sur la carte. La marque dit ce que fait le produit. */
.appbar__brand {
  display: inline-flex; align-items: baseline; gap: 1px;
  font-weight: var(--fw-semibold); letter-spacing: -0.02em; font-size: var(--fs-title);
  color: var(--ink);
}
.appbar__brand::after {
  content: ""; align-self: center;
  width: 6px; height: 6px; margin-left: 3px;
  border-radius: var(--r-pill);
  background: var(--accent);
  box-shadow: 0 0 8px oklch(80% 0.155 78 / 0.6);
}

.map-shell { flex: 1; position: relative; min-height: 0; }

/* ⚠️ La carte garde ses tuiles CLAIRES : c'est elle, la source de lumiere
   de l'ecran. Ne pas la passer en tuiles sombres « pour la coherence » —
   on perdrait le contraste qui fait ressortir le marqueur, et il faudrait
   dependre d'un fournisseur de tuiles externe de plus. */
#map { position: absolute; inset: 0; z-index: var(--z-map); background: var(--surface-2); }

/* Panneau d'infos, flottant sur la carte. Assez opaque pour rester lisible
   au-dessus de n'importe quelle tuile — un panneau translucide sur une carte
   devient illisible des qu'il passe sur une zone urbaine dense. */
.panel {
  position: absolute; z-index: var(--z-panel);
  top: var(--sp-4); right: var(--sp-4); width: min(320px, calc(100% - 2 * var(--sp-4)));
  background: oklch(14% 0.014 265 / 0.94); backdrop-filter: blur(10px);
  border: 1px solid var(--border-2); border-radius: var(--r-lg);
  padding: var(--sp-4); box-shadow: var(--shadow-pop);
}
.panel__title {
  font-size: var(--fs-label); font-weight: var(--fw-semibold); color: var(--slate);
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* Le resume porte le nom de l'appareil et le chevron. Replie, il ne reste que
   cette ligne : on sait toujours quel appareil on regarde, et la carte est
   rendue. */
.panel__summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex; align-items: center; gap: var(--sp-2);
  /* Cible tactile confortable sans agrandir le panneau replie. */
  min-height: 24px;
}
.panel__summary::-webkit-details-marker { display: none; }

/* Meme chevron que le menu de la barre, et pour la meme raison : l'oeil le
   cherche a droite d'une ligne pleine largeur. Jamais d'ambre — l'accent ne
   designe que l'appareil recherche et l'action principale. */
.panel__summary::after {
  content: "";
  margin-left: auto;
  border: 4px solid transparent;
  border-top-color: var(--slate);
  transform: translateY(2px);
}
.panel__fold[open] > .panel__summary::after {
  transform: translateY(-2px) rotate(180deg);
}
.panel__fold[open] > .panel__body { margin-top: var(--sp-3); }

/* Replie, le panneau ne prend que la place de son nom : une barre pleine
   largeur masquerait une bande de carte pour n'afficher qu'une ligne.
   ⚠️ :has() n'est pas indispensable — la ou il manque, le panneau garde sa
   largeur, ce qui reste parfaitement utilisable. Rien ne depend de lui. */
.panel:has(> .panel__fold:not([open])) {
  width: auto;
  max-width: min(320px, calc(100% - 2 * var(--sp-4)));
}

.stat-list { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-4); font-size: var(--fs-sm); }
.stat-list dt { color: var(--slate); }
.stat-list dd {
  text-align: right;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 0.92em; letter-spacing: -0.01em;
}

/* Bandeau d'etat (erreur reseau, aucun appareil, aucune position) */
.notice {
  position: absolute; z-index: var(--z-toast);
  left: 50%; bottom: var(--sp-5); transform: translateX(-50%);
  width: min(92vw, 420px); text-align: center;
  border: 1px solid var(--border-2);
  box-shadow: var(--shadow-pop);
}

/* ── Comptes ── */
.user-list { list-style: none; }
/* ⚠️ Cette ligne est PARTAGEE par quatre ecrans : /comptes, /appareils,
   /abonnements et la liste des pays de /configuration. Elle porte a chaque fois
   le meme montage — une identite, des etats, puis des actions poussees a droite
   par un .spacer. Toute retouche ici se voit sur les quatre. */
.user-row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm);

  /* ⚠️ Sans ce retour a la ligne, un compte cumulant ses badges et ses cinq
     actions depasse l'ecran — et le depassement est silencieux : rien ne coupe,
     la ligne s'allonge simplement hors du cadre. C'est arrive sur /comptes, ou
     un compte en essai porte jusqu'a quatre badges et cinq boutons.

     Le .spacer garde son role : il absorbe l'espace libre de SA ligne, donc les
     actions restent a droite tant qu'elles tiennent, et passent en dessous des
     que ce n'est plus le cas. Aucun media query n'est necessaire pour ca — la
     largeur disponible suffit a decider. */
  flex-wrap: wrap;
}
.user-row:last-child { border-bottom: none; }

/* L'identite ne se coupe pas en deux : une adresse email qui se scinde au
   milieu ne se lit plus, et c'est elle qui identifie la ligne. */
.user-row > :first-child { overflow-wrap: anywhere; }

/* Bandeau d'impersonation : doit se voir immediatement. Sur fond sombre
   l'ambre est deja l'accent, donc l'avertissement passe par une INVERSION
   — fond plein, texte sombre — et non par une nuance de plus. */
.imp-bar {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-4);
  background: var(--warn);
  color: var(--on-accent);
  font-size: var(--fs-sm); font-weight: var(--fw-medium);
}
.imp-bar b { font-weight: var(--fw-semibold); }
.imp-bar .btn { margin-left: auto; --btn-fg: var(--on-accent); --btn-bd: oklch(45% 0.09 78); }
.imp-bar .btn:hover { background: oklch(72% 0.13 78); }

/* Jeton d'appareil : montre une seule fois, il doit etre lisible sans ambiguite
   (le 0 et le O, le 1 et le l) et selectionnable d'un coup. */
.token {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  word-break: break-all;
  user-select: all;
  color: var(--accent);
  background: oklch(12% 0.012 265);
  border: 1px solid var(--border-2);
  border-radius: var(--r-data);
  padding: var(--sp-3);
}

@media (max-width: 680px) {
  .appbar { padding: var(--sp-3) var(--sp-4); }
  .appbar__brand { width: 100%; }
  /* ⚠️ EN HAUT A DROITE sur telephone aussi, plus en bas.
     Colle au bord inferieur, le panneau replie tombait sous la barre d'adresse
     et la zone de gestes : on pouvait le replier, pas le rouvrir — un pli sans
     retour, ce qui est pire que pas de pli du tout. Il ne reste donc que le
     rembourrage a resserrer, la position de base convient. */
  .panel { padding: var(--sp-3); }

  /* Le bandeau d'etat retrouve le bas, que le panneau libere. */

  /* ⚠️ Le panneau des menus est ancre a DROITE (`right: 0`) : sur grand ecran
     les menus sont en fin de barre, et c'est le bon cote. Sur telephone la
     barre passe a la ligne et « Parametres » se retrouve a GAUCHE — le panneau,
     large d'au moins 180 px, debordait alors hors de l'ecran par la gauche.
     Symptome : « Profil », court, disparaissait entierement, et les entrees
     plus longues n'affichaient que leur fin (« ...eils », « ...uration »). On
     ancre donc a gauche sous ce point de rupture. */
  .menu__panel {
    left: 0;
    right: auto;
    /* Le `min-width` de 180 px suffisait a lui seul a faire deborder un ecran
       tres etroit : il est ramene a ce que la fenetre peut offrir. */
    min-width: min(180px, calc(100vw - var(--sp-4) * 2));
    max-width: calc(100vw - var(--sp-4) * 2);
  }

  /* Le selecteur de langue, lui, reste en fin de barre : ancre a gauche, c'est
     par la droite qu'il sortirait. */
  .menu[data-menu-langue] .menu__panel {
    left: auto;
    right: 0;
  }
}

/* ── Menu « Paramètres » de la barre d'application ──
   <details>/<summary> : ouverture, fermeture et pilotage clavier natifs, sans
   JavaScript. nav.js ne gere que ce que le HTML ne peut pas savoir seul (le
   role du compte, la page courante, la fermeture au clic exterieur). */
.menu { position: relative; }

.menu > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::after {
  content: "";
  display: inline-block;
  margin-left: 0.4em;
  border: 4px solid transparent;
  border-top-color: currentColor;
  transform: translateY(2px);
}
.menu[open] > summary::after { transform: translateY(-2px) rotate(180deg); }

.menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--sp-2));
  min-width: 180px;
  padding: var(--sp-1);
  background: var(--surface);
  border: 1px solid var(--border-2);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
}

.menu__item {
  padding: 0.5rem 0.65rem;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--ink);
  text-decoration: none;
}
.menu__item:hover { background: var(--surface-2); text-decoration: none; }
.menu__item[aria-current="page"] {
  background: var(--accent-bg);
  color: var(--accent);
  font-weight: var(--fw-medium);
}


/* ── Étiquette du marqueur sur la carte ──
   Elle se pose sur des tuiles CLAIRES : c'est donc une pastille sombre,
   l'inverse du reste de l'interface. Le style Leaflet par defaut — jaune
   pale, bordure grise — n'appartient a aucune palette. */
.leaflet-tooltip.device-label {
  background: oklch(16% 0.014 265 / 0.92);
  border: 1px solid var(--accent-dim);
  border-radius: var(--r-data);
  box-shadow: 0 2px 8px oklch(0% 0 0 / 0.35);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  padding: 2px 8px;
  white-space: nowrap;
}
.leaflet-tooltip.device-label::before { border-top-color: var(--accent-dim); }

/* Les infobulles et controles Leaflet suivent le meme theme : laisses par
   defaut, ils reintroduisent du blanc pur au milieu d'un ecran sombre. */
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border-2); box-shadow: var(--shadow-pop);
}
.leaflet-popup-content-wrapper { border-radius: var(--r-md); }
.leaflet-container a.leaflet-popup-close-button { color: var(--slate); }
.leaflet-bar a, .leaflet-bar a:hover {
  background: var(--surface); color: var(--ink); border-bottom-color: var(--border);
}
.leaflet-bar a:hover { background: var(--surface-2); }
.leaflet-control-attribution {
  background: oklch(16% 0.014 265 / 0.85) !important;
  color: var(--faint);
}
.leaflet-control-attribution a { color: var(--slate); }


/* ── Dialogue d'edition ──
   <dialog> natif : gestion du focus, fermeture par Echap et fond modal fournis
   par le navigateur. Rien a reimplementer. */
.dialogue {
  border: 1px solid var(--border-2);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  width: min(28rem, calc(100vw - 2 * var(--sp-4)));
}
.dialogue::backdrop { background: oklch(8% 0.01 265 / 0.7); backdrop-filter: blur(2px); }


/* ── Marqueur de l'appareil recherche ──
   Construit en CSS plutot qu'avec l'icone Leaflet par defaut : celle-ci est
   une image PNG bleue livree avec la bibliotheque, hors palette et hors de
   notre controle.

   ⚠️ Le halo qui pulse est fonctionnel. Sur une carte dezoomee assez pour
   contenir a la fois le telephone et soi-meme, un point de huit pixels se
   perd dans le bati ; le mouvement est la seule chose que l'oeil trouve sans
   la chercher. C'est le seul element anime de l'application. */
.pin-wrap { background: none; border: none; }

.pin {
  position: relative;
  display: block; width: 22px; height: 22px;
}
.pin::after {
  content: "";
  position: absolute; inset: 6px;
  border-radius: var(--r-pill);
  background: var(--accent);
  border: 2px solid oklch(18% 0.02 265);
  box-sizing: content-box;
}
.pin__halo {
  position: absolute; inset: 0;
  border-radius: var(--r-pill);
  background: oklch(80% 0.155 78 / 0.35);
  animation: pin-pulse 2.4s var(--ease-out) infinite;
}

@keyframes pin-pulse {
  0%   { transform: scale(0.55); opacity: 0.9; }
  70%  { transform: scale(1.7);  opacity: 0; }
  100% { transform: scale(1.7);  opacity: 0; }
}

/* Le halo reste, fixe : c'est lui qui donne sa taille de cible au point.
   Seul le mouvement disparait. */
@media (prefers-reduced-motion: reduce) {
  .pin__halo { animation: none; transform: scale(1); opacity: 0.35; }
}

/* ── Liens d'installation de l'application mobile ──
   ⚠️ Pas d'ambre ici. L'accent du projet ne designe qu'une chose : l'appareil
   recherche et l'action principale. Sur la vitrine il est deja pris par
   « Se connecter » — un second element ambre couperait le signal en deux au
   moment ou la page essaie de faire creer un compte. */
.app-lien { display: inline-flex; align-items: center; gap: var(--sp-1); }
.app-lien__glyphe { flex: none; opacity: .8; }
.app-lien:hover .app-lien__glyphe { opacity: 1; }

/* ─────────────────────────── /resume ───────────────────────────
   La comete : quatre pastilles d'opacite decroissante qui parcourent
   la plage chargee. */

/* ⚠️ divIcon construit en CSS, jamais l'icone par defaut de Leaflet — un PNG
   bleu livre avec la bibliotheque, hors palette et hors de notre controle.
   ⚠️ AUCUN halo qui pulse ici, contrairement au marqueur de la carte : la-bas
   le halo compense l'immobilite d'un point unique sur une carte dezoomee, ici
   c'est le deplacement qui attire l'oeil. Deux mouvements se disputeraient le
   regard. */
.comete__pastille {
  display: block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--on-accent);
  box-sizing: border-box;
}

/* La barre de lecture. Masquee tant qu'aucun trajet n'est charge. */
.lecteur {
  position: absolute;
  left: var(--sp-3);
  right: var(--sp-3);
  bottom: var(--sp-3);
  z-index: 500;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
}

/* Le bandeau d'etat se pose en bas au centre, la ou vit deja la barre de
   lecture. Quand les deux sont a l'ecran — cas du message de troncature, qui
   accompagne un trajet bel et bien charge — le bandeau passe au-dessus d'elle
   plutot que par-dessus. `~` fonctionne parce que #lecteur precede #resume-msg
   dans le HTML. */
/* ⚠️ Sur /resume le bandeau d'etat se pose EN HAUT de la carte, pas en bas.
   Deux raisons. La barre du haut occupe quatre lignes sur telephone — la carte
   n'a plus qu'un tiers de l'ecran, et un message pose tout en bas tombe sous la
   zone de gestes du systeme. Et surtout, c'est en haut que le regard vient de
   cliquer sur « Charger » : y repondre ailleurs, c'est ne pas repondre. Un
   « Aucune position » invisible se lit exactement comme une page en panne, et
   c'est ce qui s'est produit. */
.map-page .notice.notice--haut {
  top: var(--sp-3);
  bottom: auto;
}

.lecteur__reglage {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-label);
}

.lecteur__curseur { width: 10rem; }
.lecteur__curseur--court { width: 5rem; }

.lecteur__mesure {
  font-size: var(--fs-label);
  white-space: nowrap;
}

/* La pastille qui annonce a quoi sert la barre d'opacite : elle porte la
   couleur du parcours effectue, donc le reglage n'a pas besoin d'etiquette. */
.trace-pastille {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: var(--trace-passee);
}

/* Case a cocher en ligne, dans une barre d'outils. */
.check {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-label);
  white-space: nowrap;
}

/* Sous 680 px la barre du haut passe deja en colonne : la barre de lecture doit
   rester lisible sans recouvrir la carte, seule chose que cet ecran sert a
   montrer. */
@media (max-width: 680px) {
  .lecteur { gap: var(--sp-2); }
  .lecteur__curseur { width: 6rem; }
  .lecteur__curseur--court { width: 4rem; }
}

/* ─────────────────────── /appareils : zone surveillee ───────────────────────
   Le formulaire d'alertes demandait trois nombres. Personne ne connait les
   coordonnees de la limite qu'il veut poser autour de chez lui : la carte
   n'est donc pas un ornement, c'est le champ de saisie. Et le cercle EST
   l'explication du rayon — taper 300 ne dit rien, voir le cercle couvrir la
   maison et le bout de la rue dit tout. */
.zone-map {
  /* Assez haut pour reconnaitre un quartier, assez bas pour que le seuil de
     batterie reste visible sous la carte : un reglage qui en cache un autre
     se fait oublier. */
  height: 240px;
  border-radius: var(--r-data);
  border: 1px solid var(--line);
  /* Leaflet peint ses tuiles en dehors du cadre pendant un deplacement. */
  overflow: hidden;
  /* Le fond porte la couleur du chrome, pas du blanc : si les tuiles ne
     repondent pas — geoblock, coupure — il reste un cadre propre, comme le
     hero de la landing. */
  background: var(--surface-2);
}

@media (max-width: 680px) {
  /* Sur telephone la page entiere defile, et une carte haute pousse les deux
     autres reglages hors de l'ecran. */
  .zone-map { height: 190px; }
}

/* Le meme point ambre que la carte principale, sans le halo qui pulse : ici
   le marqueur est sous les doigts de qui vient de le poser, il n'a pas a se
   signaler. Voir aussi la comete de /resume, meme raisonnement. */
.zone-pin { background: none; border: none; }
.zone-pin::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  border: 2px solid oklch(18% 0.02 265);
  box-sizing: border-box;
  cursor: grab;
}
