/* ================================================================
   Bleme — thème sombre « application mobile »
   Même grammaire que /srv/annuaire, /srv/contact, /srv/agenda,
   /srv/play et /srv/actu (topbar fixe + pastille d'onglets flottante
   opaque, sidebar sur grand écran, icônes Lucide inline), avec une
   identité propre : UNE COULEUR PLEINE PAR PAGE sur un quasi-noir
   commun (jaune, rouge, vert-cyan), chacune dérivant vers une
   seconde teinte — là où l'Annuaire est bleu marine, Contact
   turquoise, l'Agenda vert et or, Play violet et Actu corail.
   Règle absolue : AUCUN box-shadow, nulle part (préférence
   utilisateur) — les reliefs sont rendus par bordures et fonds.
   Jamais d'emoji : uniquement des icônes Lucide.
   ================================================================ */
:root {
  color-scheme: dark;
  /* LE QUASI-NOIR COMMUN. Tout le sol d'une page est bâti dessus, en y posant
     un peu de la couleur de la page (§ « la couleur de la page », plus bas).
     Ce n'est plus une nuit ambrée teintée après coup : une page est de sa
     couleur DÈS le fond, ce qui la rend à la fois plus sombre et plus franche.
     Ne jamais s'en servir directement dans une règle. */
  --nuit: #070609;
  --accent: #ffa62b;
  --accent-2: #ffc670;
  --sur-accent: #241500;
  --puce: var(--accent);
  --degrade-marque: linear-gradient(135deg, #ffa62b, #2dd4bf);
  --sur-marque: #ffffff;
  --ok: #48d6a0;
  --ok-doux: #113026;
  --warn: #ffcc4d;
  --warn-doux: #3a2f0f;
  --danger: #ff6b78;
  --danger-doux: #381820;
  --rayon: 18px;
  --rayon-petit: 12px;
  --sidebar: 238px;
  /* Encoches et barres système : la topbar et la pastille d'onglets s'en
     écartent au lieu de passer dessous. Mêmes noms que dans les autres
     applications du groupe. */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* LA COULEUR DE LA PAGE. Une classe `zone-*` sur <body> (posée par head.ejs)
   suffit à habiller toute la page : accent, sol, gris de texte, dégradé et
   bouton plein en découlent, sans une seule règle dupliquée.

   Chaque page EST d'une couleur, et son dégradé DÉRIVE vers une seconde :
     Plan            CUIVRE     qui dérive vers un OR
     Opportunités    VERT-CYAN  qui dérive vers le CUIVRE
     Recherches      BLEU CIEL  qui dérive vers le CUIVRE
     Administration  VIOLET     (sans dérive : ce n'est pas une page de travail)

   Trois réglages par zone, et rien d'autre à écrire :
     --fruit    la couleur de la page. Elle bâtit TOUT le sol — fond, surfaces,
                traits, pastille du bas, fond des champs — et jusqu'aux gris du
                texte, qui portent une pointe de la même couleur pour ne pas
                rester des gris d'une autre page.
     --fruit-2  la dérive : où va le dégradé, et vers quoi penche le coin du
                bouton plein.
     --halo     la force de cette dérive en haut de page.

   Le sol est bâti SUR LE QUASI-NOIR (--nuit), pas sur une nuit ambrée qu'on
   teinterait : c'est ce qui donne un fond franchement coloré et nettement plus
   sombre qu'avant. La rampe (6 % pour le fond, 14 % pour une carte, 32 % pour
   un trait…) est la même pour toutes les zones — seule la couleur change.

   Les chiffres sont MESURÉS, pas choisis à l'œil, et `npm test` les revérifie :
   3:1 pour --accent (il sert de bordure de focus et de trait fin), 4,5:1 pour
   --muet, --texte et --sur-accent, qui portent du texte. Le point qui décide
   est toujours le plus clair réellement visible : le fond, PLUS le voile,
   PLUS le halo. Ne retoucher aucun de ces réglages sans relancer le test. */

/* PLAN — page CUIVRE, dérive OR. C'est la page d'accueil, celle où l'on
   travaille : le plan d'action et ce que chaque tactique a donné. Le cuivre est
   la couleur de Commerce dans tout le groupe (registre d'Admin, fiches de
   Recom). Il se distingue de l'or de Bleme (#ffa62b, franchement jaune) et du
   corail d'Actu (#ff5a5f, franchement rouge) : il est au milieu, et c'est
   exactement là qu'aucune des deux n'est. */
.zone-plan {
  --accent: #f0873f;
  --accent-2: #f8b078;
  --sur-accent: #200d02;
  --puce: var(--accent);
  --fruit: #f0873f;
  --fruit-2: #f5c451;
  --halo: 12%;
}

/* OPPORTUNITÉS — page VERT-CYAN, dérive cuivre. C'est la page du DEHORS : ce
   que la recherche web a ramené du monde réel. Une autre couleur que le plan,
   parce qu'on ne fait pas la même chose sur les deux pages — d'un côté on
   décide, de l'autre on trie ce qui existe. */
.zone-opportunites {
  --accent: #2dd4bf;
  --accent-2: #6ee7d7;
  --sur-accent: #021816;
  --puce: var(--accent);
  --fruit: #21cfb4;
  --fruit-2: #f0873f;
  --halo: 11%;
}

/* RECHERCHES — page BLEU CIEL, dérive cuivre. Même bleu que la page équivalente
   de Roadmap et de Recom, et c'est volontaire : dans tout le groupe, cette
   teinte veut dire « ce que la machine a fait ». */
.zone-recherches {
  --accent: #38bdf8;
  --accent-2: #7dd3fc;
  --sur-accent: #021420;
  --puce: var(--accent);
  --fruit: #38bdf8;
  --fruit-2: #f0873f;
  --halo: 11%;
}

/* ADMINISTRATION — page VIOLET, sans dérive : le dégradé y reste dans la
   couleur de la page. Ce n'est pas une matière de l'application, elle n'a pas
   à s'annoncer d'une seconde teinte. */
.zone-admin {
  --accent: #c9a6ff;
  --accent-2: #ddc4ff;
  --sur-accent: #150b20;
  --puce: var(--accent);
  --fruit: #c9a6ff;
  --fruit-2: #c9a6ff;
  --halo: 10%;
}

* { box-sizing: border-box; }
/* Pas de fond sur <html> : sans lui, c'est celui de <body> qui remonte au
   canevas, teinte comprise. Une page verte reste verte jusque dans le
   rebond élastique du défilement, où l'on verrait sinon la nuit nue. */
html { min-height: 100%; }
body {
  /* Sans zone — connexion, page d'erreur — la page prend l'or de Bleme et
     dérive vers son or clair : jamais de page grise, jamais de couleur
     étrangère écrite en dur. */
  --fruit: var(--accent);
  --fruit-2: var(--accent-2);
  --halo: 10%;

  /* LE SOL, bâti sur le quasi-noir avec la couleur de la page. La rampe est
     la même partout : c'est elle qui fait qu'une carte se distingue du fond et
     qu'un trait se distingue d'une carte. Une carte ne se détache PAS par sa
     luminance (1,06:1 à peine) mais par sa bordure — c'était déjà vrai avant,
     ne pas essayer de « corriger » ça en éclaircissant les surfaces. */
  --fond: color-mix(in srgb, var(--fruit) 6%, var(--nuit));
  --fond-2: color-mix(in srgb, var(--fruit) 10%, var(--nuit));
  --surface: color-mix(in srgb, var(--fruit) 14%, var(--nuit));
  --surface-2: color-mix(in srgb, var(--fruit) 19%, var(--nuit));
  --surface-3: color-mix(in srgb, var(--fruit) 24%, var(--nuit));
  --trait: color-mix(in srgb, var(--fruit) 32%, var(--nuit));
  --trait-fort: color-mix(in srgb, var(--fruit) 45%, var(--nuit));
  /* Un champ de saisie est plus SOMBRE que la page : c'est un creux, pas une
     carte. Jamais de couleur de champ écrite en dur (règle héritée). */
  --champ: color-mix(in srgb, var(--fruit) 3%, var(--nuit));
  --tabbar-base: color-mix(in srgb, var(--fruit) 8%, var(--nuit));
  /* Le fond des boutons secondaires, onglets actifs et notices. 13 % et pas
     plus : à 18 %, le bordeaux des problématiques ne tenait plus que 2,96:1
     sur son propre fond doux, alors qu'il lui sert de bordure. */
  --accent-doux: color-mix(in srgb, var(--accent) 13%, var(--fond));

  /* LES GRIS APPARTIENNENT À LA PAGE. Un gris ambré sur une page vert-cyan a
     l'air sale : chaque gris porte donc une pointe de la couleur de la page.
     Assez pour appartenir à la page, pas assez pour colorer la lecture. */
  --texte: color-mix(in srgb, var(--fruit) 5%, #fbf8f4);
  --texte-2: color-mix(in srgb, var(--fruit) 10%, #ded8d0);
  --muet: color-mix(in srgb, var(--fruit) 14%, #9d9791);

  min-height: 100vh;
  margin: 0;
  /* LE DÉGRADÉ : la page part de sa couleur et DÉRIVE vers la seconde, en haut
     à droite, là où le regard entre. Deux couches et pas une ombre — le relief
     reste affaire de fonds et de bordures.
     Le halo est posé en REM, pas en pourcentage : un « -20% » se mesure sur la
     hauteur du document, et sur une longue liste il partait si haut qu'on ne le
     voyait plus. En rem, une page courte et une page longue portent le même
     dégradé. Et surtout pas de `background-attachment: fixed` — Safari mobile
     le rend par à-coups au défilement, et c'est ici une application mobile. */
  background:
    radial-gradient(circle 36rem at 78% -7rem, color-mix(in srgb, var(--fruit-2) var(--halo), transparent), transparent),
    linear-gradient(178deg, color-mix(in srgb, var(--fruit-2) 5%, transparent), transparent 44rem),
    var(--fond);
  color: var(--texte);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; }
button, select { cursor: pointer; }
button:disabled { cursor: not-allowed; opacity: .55; }
img, svg { display: block; }
.lucide { width: 1.12em; height: 1.12em; flex: 0 0 auto; }
.muted { color: var(--muet); }

.layout { min-height: 100vh; }
.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 20;
  display: flex;
  width: var(--sidebar);
  flex-direction: column;
  gap: 6px;
  padding: 24px 16px;
  border-right: 1px solid var(--trait);
  /* Le fond de la barre latérale vient de la nuit de l'application, jamais
     d'une couleur écrite en dur : même formule que /srv/play. */
  background: color-mix(in srgb, var(--fond) 92%, transparent);
}
.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 54px;
  margin: 0 4px 22px;
  font-size: 1.2rem;
  font-weight: 800;
  letter-spacing: -.02em;
}
.brand-ico {
  display: inline-grid;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 12px;
  background: var(--degrade-marque);
  color: var(--sur-marque);
}
.brand-ico svg { width: 25px; height: 25px; }
.sidebar > a {
  display: flex;
  min-height: 47px;
  align-items: center;
  gap: 12px;
  padding: 0 13px;
  border: 1px solid transparent;
  border-radius: 13px;
  color: var(--texte-2);
  font-weight: 660;
}
.sidebar > a:hover { border-color: var(--trait); background: var(--surface); color: var(--texte); }
.sidebar > a.active { border-color: color-mix(in srgb, var(--accent) 45%, var(--trait)); background: var(--accent-doux); color: var(--accent-2); }
.sidebar .ico { display: grid; width: 22px; place-items: center; }
.logout-form { margin-top: auto; }
.logout-form button {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--trait);
  border-radius: 12px;
  background: transparent;
  color: var(--muet);
}
.logout-form button:hover { color: var(--texte); border-color: var(--trait-fort); }

.topbar, .tabbar { display: none; }

/* Pastille du SEUL compteur de l'interface (cloche de la topbar). Rouge, comme
   dans le reste du groupe : elle ne compte que les problématiques ouvertes sans
   solution, jamais une bonne nouvelle. */
.notif-dot {
  position: absolute; top: -4px; right: -6px; min-width: 18px; height: 18px;
  background: var(--danger); color: #fff; border-radius: 99px; font-size: 11px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; padding: 0 4px;
}

.content {
  width: min(1160px, calc(100% - var(--sidebar)));
  min-height: 100vh;
  margin-left: var(--sidebar);
  padding: 42px clamp(28px, 5vw, 72px) 90px;
}

h1, h2, h3, p { margin-top: 0; }
h1 { margin-bottom: 0; font-size: clamp(2rem, 5vw, 3.3rem); line-height: 1.06; letter-spacing: -.045em; }
h2 { margin-bottom: 14px; font-size: 1.18rem; letter-spacing: -.018em; }
h3 { margin-bottom: 7px; font-size: 1.05rem; }
.eyebrow { margin: 0 0 6px; color: var(--accent-2); font-size: .75rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 24px; }
.head-actions, .action-bar, .carte-actions, .inline-end { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.inline-end { justify-content: flex-end; margin-top: 24px; }
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 38px 0 15px; }
.section-head h2 { margin: 0; }
.back { display: inline-flex; align-items: center; gap: 7px; margin-bottom: 22px; color: var(--muet); font-weight: 700; }
.back:hover { color: var(--accent-2); }

.notice {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  margin-bottom: 25px;
  padding: 15px 17px;
  border: 1px solid color-mix(in srgb, var(--accent) 36%, var(--trait));
  border-radius: var(--rayon-petit);
  background: color-mix(in srgb, var(--accent-doux) 65%, var(--surface));
  color: var(--texte-2);
}
.notice p { margin: 0; }
.notice-ico { display: grid; margin-top: 2px; color: var(--accent-2); }
.flash, .alerte {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 18px;
  padding: 13px 15px;
  border: 1px solid var(--trait-fort);
  border-radius: var(--rayon-petit);
  background: var(--surface);
}
.flash.ok { border-color: color-mix(in srgb, var(--ok) 45%, var(--trait)); color: var(--ok); }
.flash.err, .alerte { border-color: color-mix(in srgb, var(--danger) 45%, var(--trait)); background: var(--danger-doux); color: #ffb3bb; }

.btn, button.btn {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 15px;
  border: 1px solid transparent;
  border-radius: 12px;
  font-weight: 760;
  line-height: 1.2;
}
/* Le bouton plein porte le MÊME geste que la page : il part de l'accent et
   dérive vers la seconde teinte dans son coin haut gauche. C'est ce qui le
   raccroche au dégradé du fond au lieu d'en être un aplat posé dessus.
   L'encre reste --sur-accent, mesurée sur les deux bouts du dégradé — 5,84:1
   au plus serré (le blanc sur le bordeaux des problématiques). */
.btn.primaire {
  background: linear-gradient(142deg, color-mix(in srgb, var(--fruit-2) 30%, var(--accent)), var(--accent) 62%);
  color: var(--sur-accent);
}
.btn.primaire:hover {
  background: linear-gradient(142deg, color-mix(in srgb, var(--fruit-2) 30%, var(--accent-2)), var(--accent-2) 62%);
}
.btn.secondaire { border-color: color-mix(in srgb, var(--accent) 45%, var(--trait)); background: var(--accent-doux); color: var(--accent-2); }
.btn.secondaire:hover { border-color: var(--accent); }
.btn.fantome { border-color: var(--trait); background: transparent; color: var(--texte-2); }
.btn.fantome:hover { border-color: var(--trait-fort); color: var(--texte); }
.btn.danger { border-color: color-mix(in srgb, var(--danger) 55%, var(--trait)); background: var(--danger-doux); color: #ffadb7; }
.icon-btn {
  display: inline-grid;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  place-items: center;
  border: 1px solid var(--trait);
  border-radius: 12px;
  background: transparent;
  color: var(--muet);
}
.icon-btn:hover, .icon-btn.active { border-color: var(--accent); background: var(--accent-doux); color: var(--accent-2); }
.danger-text { color: var(--danger); }

/* ================================================================
   LA RANGÉE DE CHIFFRES — même dessin que /srv/admin, au pixel près.
   Une tuile dit toujours trois choses, dans cet ordre :
     1. un LIBELLÉ porté par une icône ;
     2. une VALEUR, chiffres proportionnels — surtout pas `tabular-nums`,
        qui donne à chaque chiffre la largeur d'un zéro et fait flotter un
        « 12 » à cette taille ; le tabulaire est réservé aux colonnes ;
     3. une PREUVE : la jauge d'un rapport, quand il y a un rapport.
   L'encre reste de l'encre : la valeur ne prend JAMAIS la couleur de
   l'état, c'est la jauge et l'icône qui la portent. Sans quoi un chiffre
   rouge se lit comme une alarme alors qu'il dit juste « 2 sur 3 ».
   ================================================================ */
.stats-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin: 22px 0 28px;
}
.stat {
  display: flex;
  min-height: 124px;
  flex-direction: column;
  gap: 9px;
  padding: 15px 17px 16px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  /* Un fond très légèrement dégradé : le relief vient du fond et de la
     bordure, jamais d'une ombre (règle absolue de l'application). */
  background: linear-gradient(158deg, var(--surface-2), var(--surface) 62%);
}
.stat:hover { border-color: color-mix(in srgb, var(--accent) 55%, var(--trait)); }
.stat-tete {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muet);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: -.005em;
}
/* L'icône porte l'état EN PLUS de la jauge : une couleur seule ne dit rien
   à qui ne la distingue pas, et l'ambre et le vert sont justement la paire
   la plus proche pour un œil protanope. */
.stat-ico {
  display: grid;
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 9px;
  background: var(--accent-doux);
  color: var(--accent-2);
}
.stat-ico .lucide { width: 15px; height: 15px; }
.stat-ico.bon { background: var(--ok-doux); color: var(--ok); }
.stat-ico.moyen { background: var(--warn-doux); color: var(--warn); }
.stat-ico.mauvais { background: var(--danger-doux); color: var(--danger); }
.stat-val {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 3px 8px;
  margin-top: auto;
  color: var(--texte);
  font-size: 1.9rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.035em;
}
.stat-val small {
  color: var(--muet);
  font-size: .78rem;
  font-weight: 640;
  letter-spacing: 0;
}

/* La jauge : la preuve d'un rapport, sous la valeur. Neutre par défaut —
   une teinte d'état ne se pose que là où le rapport dit vraiment une bonne
   ou une mauvaise nouvelle. */
.jauge {
  position: relative;
  height: 8px;
  overflow: hidden;
  border-radius: 999px;
  --jauge-teinte: var(--accent);
  background: color-mix(in srgb, var(--jauge-teinte) 17%, var(--fond));
  border: 1px solid color-mix(in srgb, var(--jauge-teinte) 26%, transparent);
}
.jauge > i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--jauge-teinte);
  transition: width .25s ease;
}
.jauge.bon { --jauge-teinte: var(--ok); }
.jauge.moyen { --jauge-teinte: var(--warn); }
.jauge.mauvais { --jauge-teinte: var(--danger); }

.tabs { display: flex; gap: 7px; margin: 18px 0; overflow-x: auto; scrollbar-width: none; }
.tabs::-webkit-scrollbar { display: none; }
.tabs a { flex: 0 0 auto; padding: 9px 13px; border: 1px solid var(--trait); border-radius: 999px; color: var(--muet); font-size: .88rem; font-weight: 720; }
.tabs a:hover { color: var(--texte); }
.tabs a.active { border-color: var(--accent); background: var(--accent-doux); color: var(--accent-2); }

.filters {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) auto auto auto;
  gap: 9px;
  margin-bottom: 22px;
}
.search-wrap { position: relative; }
.search-wrap > .lucide { position: absolute; top: 50%; left: 13px; z-index: 1; color: var(--muet); transform: translateY(-50%); }
.search-wrap input { width: 100%; padding-left: 40px; padding-right: 46px; }
.micro { position: absolute; inset: 4px 4px 4px auto; display: grid; width: 38px; place-items: center; border: 0; border-radius: 9px; background: transparent; color: var(--muet); }
.micro.ecoute { background: var(--danger-doux); color: var(--danger); outline: 1px solid var(--danger); }

input, select, textarea {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--trait);
  border-radius: 11px;
  outline: 0;
  background: var(--champ);
  color: var(--texte);
}
input, select { padding: 9px 12px; }
input::placeholder, textarea::placeholder { color: color-mix(in srgb, var(--muet) 78%, transparent); opacity: 1; }
textarea { min-height: 100px; padding: 12px 13px; resize: vertical; }
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: 2px solid color-mix(in srgb, var(--accent) 20%, transparent); }
input[type="color"] { width: 58px; padding: 4px; }
label { display: grid; gap: 7px; color: var(--texte-2); font-size: .9rem; font-weight: 680; }
label small { color: var(--muet); font-weight: 450; }
label.check { display: flex; min-height: 44px; align-items: center; gap: 9px; align-self: end; }
label.check input { width: 19px; min-height: 19px; accent-color: var(--accent); }

.form-card, .panel {
  margin-bottom: 24px;
  padding: clamp(18px, 4vw, 27px);
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--surface);
}
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 17px; margin-bottom: 20px; }
.form-grid .full { grid-column: 1 / -1; }
.compact-form { display: flex; align-items: end; gap: 12px; }
.compact-form label:first-of-type { flex: 1; }
.highlight { border-color: color-mix(in srgb, var(--accent) 45%, var(--trait)); background: color-mix(in srgb, var(--accent-doux) 45%, var(--surface)); }
.error-panel { border-color: color-mix(in srgb, var(--danger) 50%, var(--trait)); }
.danger-zone { display: flex; align-items: end; justify-content: flex-end; gap: 12px; margin-top: 38px; padding-top: 20px; border-top: 1px solid var(--trait); }
.danger-zone input[type="number"] { width: 110px; }

.cards-list { display: grid; gap: 13px; }
.carte {
  position: relative;
  display: flex;
  gap: 16px;
  padding: 20px;
  overflow: hidden;
  border: 1px solid var(--trait);
  border-radius: var(--rayon);
  background: var(--surface);
}
.carte::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--puce); }
.carte:hover { border-color: color-mix(in srgb, var(--puce) 52%, var(--trait)); }
.carte.is-new { background: color-mix(in srgb, var(--accent-doux) 35%, var(--surface)); }
.carte-main { min-width: 0; flex: 1; }
.actu-visuel { width: clamp(170px, 24vw, 245px); aspect-ratio: 16 / 9; flex: 0 0 auto; align-self: flex-start; overflow: hidden; border: 1px solid var(--trait); border-radius: 14px; background: var(--fond-2); }
.actu-visuel img, .article-hero img { width: 100%; height: 100%; object-fit: cover; }
.actu-visuel:hover { border-color: color-mix(in srgb, var(--puce) 55%, var(--trait)); }
.carte h2 { margin: 6px 0 9px; font-size: clamp(1.05rem, 2vw, 1.25rem); line-height: 1.3; }
.carte h2 a:hover { color: var(--accent-2); }
.meta-line { display: flex; align-items: center; flex-wrap: wrap; gap: 7px 10px; color: var(--muet); font-size: .78rem; }
.puce { display: inline-flex; align-items: center; gap: 5px; color: var(--puce); font-weight: 800; }
.resume { margin-bottom: 12px; color: var(--texte-2); }
.points { margin: 11px 0 15px; padding: 0; list-style: none; }
.points li { position: relative; margin: 6px 0; padding-left: 19px; color: var(--texte-2); }
.points li::before { content: ""; position: absolute; top: .62em; left: 2px; width: 6px; height: 6px; border-radius: 50%; background: var(--puce); }
.points.large li { margin: 11px 0; color: var(--texte); font-size: 1rem; }
.lien-offre { display: flex; align-items: flex-start; gap: 8px; color: var(--accent-2); font-size: .91rem; }
.carte-actions { margin-top: 15px; }
.carte-actions form { display: flex; }
.pourquoi { padding: 10px 12px; border-left: 2px solid var(--puce); background: color-mix(in srgb, var(--puce) 7%, transparent); color: var(--texte-2); font-size: .9rem; }
.details-inline { display: flex; flex-wrap: wrap; gap: 8px 15px; color: var(--muet); font-size: .84rem; }
.details-inline span { display: inline-flex; align-items: center; gap: 5px; }
.date-puce { display: grid; width: 57px; height: 62px; flex: 0 0 auto; place-content: center; border: 1px solid color-mix(in srgb, var(--puce) 50%, var(--trait)); border-radius: 14px; background: color-mix(in srgb, var(--puce) 10%, var(--fond)); text-align: center; }
.date-puce strong { color: var(--texte); font-size: 1.45rem; line-height: 1; }
.date-puce span { margin-top: 4px; color: var(--puce); font-size: .69rem; font-weight: 800; }

.badge { display: inline-flex; align-items: center; width: max-content; padding: 3px 8px; border: 1px solid var(--trait); border-radius: 999px; color: var(--texte-2); font-size: .71rem; font-weight: 780; white-space: nowrap; }
.badge.ok { border-color: color-mix(in srgb, var(--ok) 48%, var(--trait)); background: var(--ok-doux); color: #82ebc1; }
.badge.warn { border-color: color-mix(in srgb, var(--warn) 48%, var(--trait)); background: var(--warn-doux); color: #ffd080; }
.badge.err { border-color: color-mix(in srgb, var(--danger) 48%, var(--trait)); background: var(--danger-doux); color: #ffadb7; }
.badge.gris { color: var(--muet); }

.detail-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 9px 15px; margin: 0 0 18px; color: var(--muet); }
/* Une carte de solution illustrée : l'image à gauche, le texte à droite —
   même dessin qu'une carte d'actualité. Sur téléphone, elle passe au-dessus
   (voir la règle ≤ 900 px), sinon il ne resterait rien du texte. */
.carte-illustree { align-items: flex-start; }
.article-hero-bloc { margin: 0 0 20px; }
.article-hero-bloc figcaption { display: flex; align-items: center; gap: 6px; margin-top: 8px; font-size: .8rem; }
.article-hero-bloc .article-hero { margin-bottom: 0; }
.article-hero { width: 100%; max-height: 520px; aspect-ratio: 16 / 8; margin: 0 0 20px; overflow: hidden; border: 1px solid var(--trait); border-radius: var(--rayon); background: var(--fond-2); }
.detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.article-text { max-width: 76ch; color: var(--texte-2); font-size: 1.02rem; }
.article-text p { margin-bottom: 1.1em; }
.callout { margin-top: 19px; padding: 14px 16px; border-left: 3px solid var(--accent); background: var(--accent-doux); }
.callout p { margin: 6px 0 0; color: var(--texte-2); }
.facts { margin: 0; }
.facts > div { display: grid; grid-template-columns: minmax(105px, .45fr) 1fr; gap: 15px; padding: 11px 0; border-bottom: 1px solid var(--trait); }
.facts > div:last-child { border-bottom: 0; }
.facts dt { display: flex; align-items: center; gap: 7px; color: var(--muet); }
.facts dd { margin: 0; overflow-wrap: anywhere; }
.facts a { display: inline-flex; align-items: center; gap: 5px; color: var(--accent-2); }

.mini-list { display: grid; gap: 8px; }
.mini-list > a { display: flex; min-height: 57px; align-items: center; justify-content: space-between; gap: 15px; padding: 11px 13px; border: 1px solid var(--trait); border-radius: 12px; background: var(--surface); }
.mini-list > a:hover { border-color: var(--accent); }
.mini-list > a > span { display: grid; min-width: 0; }
.mini-list strong { overflow: hidden; text-overflow: ellipsis; }
.mini-list small { color: var(--muet); }
.empty { display: grid; min-height: 210px; place-items: center; align-content: center; padding: 25px; border: 1px dashed var(--trait-fort); border-radius: var(--rayon); color: var(--muet); text-align: center; }
.empty > .lucide { width: 34px; height: 34px; margin-bottom: 10px; color: var(--accent); }
.empty h2 { margin-bottom: 5px; color: var(--texte); }
.empty p { margin: 0; }
.empty.compact { min-height: 130px; }

.progress-card { display: none; margin: 0 0 20px; padding: 15px 17px; border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--trait)); border-radius: 14px; background: var(--accent-doux); }
.progress-card.visible { display: block; }
.progress-top { display: flex; justify-content: space-between; gap: 15px; }
.progress-track { height: 7px; margin: 11px 0 8px; overflow: hidden; border-radius: 999px; background: var(--fond); }
.progress-track span { display: block; width: 12%; height: 100%; border-radius: inherit; background: var(--accent); transition: width .25s ease; }
.progress-card p { margin: 0; color: var(--muet); font-size: .84rem; }

/* L'avis de moteur : quel moteur répond, et pourquoi. Il n'apparaît que
   lorsqu'il a quelque chose à dire — un relais pris ou deux quotas épuisés. */
.progress-avis { display: none; align-items: flex-start; gap: 9px; margin-top: 11px !important;
  padding: 10px 12px; border: 1px solid var(--trait-fort); border-radius: var(--rayon-petit);
  background: var(--surface); font-size: .84rem; line-height: 1.45; }
.progress-avis.visible { display: flex; }
.progress-avis svg { flex: none; margin-top: 2px; width: 16px; height: 16px; }
.progress-avis.info { border-color: color-mix(in srgb, var(--warn) 45%, var(--trait));
  background: var(--warn-doux); color: var(--warn); }
.progress-avis.alerte { border-color: color-mix(in srgb, var(--danger) 45%, var(--trait));
  background: var(--danger-doux); color: #ffb3bb; }

.actions-grid { display: grid; gap: 12px; margin: 18px 0 26px; }
.actions-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.action-tile { display: flex; width: 100%; min-height: 78px; align-items: center; gap: 13px; padding: 15px; border: 1px solid var(--trait); border-radius: 15px; background: var(--surface); color: var(--texte); text-align: left; }
.action-tile:hover { border-color: var(--accent); }
.action-tile > .lucide { width: 25px; height: 25px; color: var(--accent); }
.action-tile span { display: grid; }
.action-tile small { color: var(--muet); font-weight: 450; }

.table-list { display: grid; gap: 9px; }
.source-row, .subject-row { display: flex; align-items: center; gap: 13px; padding: 15px; border: 1px solid var(--trait); border-radius: 14px; background: var(--surface); }
.source-row { border-left: 3px solid var(--puce); }

/* ================================================================
   LA LIGNE D'UN SUJET — une ligne EST un formulaire.
   Le CSS a longtemps visé un formulaire IMBRIQUÉ dans la ligne, élément qui
   n'existe pas dans le balisage : toute la mise en grille, écran large comme
   téléphone, ne s'appliquait donc à rien. Restait le `display: flex`, où le
   nom et la couleur — chacun en `width: 100 %` par la règle générale des
   champs — s'écrasaient côte à côte sans jamais passer à la ligne. D'où une
   page illisible sur téléphone. Viser `.subject-row` DIRECTEMENT.
   Les zones nommées sont là pour ça : le balisage ne bouge pas, seule la
   disposition change d'un écran à l'autre.
   ================================================================ */
.subject-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto auto auto;
  grid-template-areas: "puce nom couleur compte valider archiver";
  align-items: center;
  gap: 10px;
  /* La couleur du sujet se voit sur toute la hauteur de sa ligne, comme pour
     une source : une pastille de 11 px ne suffit pas à repérer une ligne dans
     une liste de quarante. */
  border-left: 3px solid var(--puce);
}
.subject-row .color-dot { grid-area: puce; }
.subject-row .sujet-nom { grid-area: nom; }
.subject-row .sujet-couleur { grid-area: couleur; width: auto; }
.subject-row .sujet-compte { grid-area: compte; font-size: .82rem; white-space: nowrap; }
.subject-row .sujet-compte a { text-decoration: underline; text-underline-offset: 3px; }
.subject-row .sujet-compte a:hover { color: var(--texte); }
.subject-row .sujet-valider { grid-area: valider; }
.subject-row .sujet-archiver { grid-area: archiver; }
/* Les deux boutons n'ont qu'une icône : ils gardent la cible de 44 px du
   groupe, mais sans le rembourrage d'un bouton qui porte du texte. */
.subject-row .btn.fantome { min-width: 44px; padding-inline: 10px; }
.source-icon { display: grid; width: 43px; height: 43px; flex: 0 0 auto; place-items: center; border-radius: 12px; background: color-mix(in srgb, var(--puce) 12%, var(--fond)); color: var(--puce); }
.source-main { min-width: 0; flex: 1; }
.source-main h2 { margin: 4px 0 2px; }
.source-main p { margin: 0; }
.source-message { color: var(--danger); font-size: .82rem; }
.row-actions { display: flex; gap: 7px; }
.muted-row { opacity: .58; }
.color-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--puce); }

/* ================================================================
   LES PRIORITÉS DES SUJETS. Une grille et non une ligne flex : un
   <input type="range"> a une largeur intrinsèque têtue sur iOS, et
   `minmax(0, 1fr)` est ce qui l'oblige à rétrécir au lieu de pousser
   la ligne hors de l'écran (leçon reprise du module d'origine).
   ================================================================ */
.prio-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 40%) 42px;
  grid-template-areas: "puce nom compte jauge valeur" "mots mots mots mots mots";
  align-items: center;
  gap: 9px 10px;
  padding: 12px 14px;
  border: 1px solid var(--trait);
  border-left: 3px solid var(--puce);
  border-radius: 14px;
  background: var(--surface);
}
.prio-row .color-dot { grid-area: puce; }
.prio-nom { grid-area: nom; min-width: 0; overflow: hidden; font-weight: 680; text-overflow: ellipsis; white-space: nowrap; }
.prio-compte { grid-area: compte; font-size: .76rem; white-space: nowrap; }
.prio-jauge { grid-area: jauge; width: 100%; min-width: 0; min-height: 0; padding: 0; border: 0; background: transparent; accent-color: var(--accent); }
.prio-valeur {
  grid-area: valeur;
  padding: 3px 0;
  border: 1px solid var(--trait);
  border-radius: 9px;
  background: var(--fond);
  color: var(--texte);
  font-size: .84rem;
  font-weight: 780;
  text-align: center;
}
/* Une priorité à 0 ne veut pas dire « faible » mais « jamais » : elle
   s'éteint, au lieu de se fondre dans les autres valeurs basses. */
.prio-valeur.zero { border-style: dashed; color: var(--muet); }
.prio-valeur.haute { border-color: color-mix(in srgb, var(--ok) 45%, var(--trait)); color: var(--ok); }
.prio-mots { grid-area: mots; font-size: .84rem; }

@media (max-width: 900px) {
  /* Le libellé prend toute la largeur, le trio compteur/curseur/valeur passe
     dessous — sinon le nom d'un sujet se réduit à trois lettres. */
  .prio-row {
    grid-template-columns: auto minmax(0, 1fr) 42px;
    grid-template-areas: "puce nom nom" "compte jauge valeur" "mots mots mots";
  }
  .prio-nom { white-space: normal; }
}

/* Sources, thèmes et médias fiables. Les deux pages partagent la même zone
   ambre et restent des réglages passifs de l'unique recherche manuelle. */
.section-head.compact { margin: 0 0 17px; }
.source-tabs { margin-top: 0; }
.source-add-panel { margin-top: 22px; }
.source-quick-form { margin-bottom: 0; }
.source-submit { margin-top: 0; }
.source-managed { align-items: flex-start; }
.source-managed .row-actions { align-self: center; }
.source-assign { display: grid; grid-template-columns: repeat(2, minmax(130px, 1fr)); gap: 8px; margin-top: 11px; }
.source-assign select { min-height: 38px; padding-block: 6px; color: var(--texte-2); font-size: .82rem; }

.themes-panel { margin-top: 38px; scroll-margin-top: 20px; }
.theme-list { display: grid; gap: 11px; }
.theme-card { padding: 14px; border: 1px solid var(--trait); border-left: 3px solid var(--puce); border-radius: 14px; background: var(--surface-2); }
.theme-top { display: flex; align-items: center; gap: 10px; }
.theme-edit { display: grid; grid-template-columns: auto minmax(170px, 1fr) auto auto; align-items: center; gap: 9px; min-width: 0; flex: 1; }
.theme-edit input[type="color"] { width: 45px; min-height: 40px; }
.theme-edit input[name="nom"] { min-height: 40px; font-weight: 760; }
.theme-edit .icon-btn, .theme-top > form .icon-btn { width: 40px; height: 40px; }
.category-list { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-top: 12px; }
.category-chip { display: inline-flex; min-height: 34px; align-items: center; gap: 5px; padding: 4px 5px 4px 11px; border: 1px solid var(--trait); border-radius: 999px; background: var(--fond-2); color: var(--texte-2); font-size: .8rem; font-weight: 700; }
.category-chip form { display: inline-flex; }
.category-chip button { display: grid; width: 27px; height: 27px; padding: 0; place-items: center; border: 0; border-radius: 50%; background: transparent; color: var(--muet); }
.category-chip button:hover { background: var(--danger-doux); color: var(--danger); }
.category-chip .lucide { width: 14px; height: 14px; }
.category-add { display: flex; align-items: center; gap: 6px; min-width: min(270px, 100%); }
.category-add input { min-height: 36px; }
.category-add .icon-btn { width: 36px; height: 36px; }
.theme-add { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--trait); }

.tag-fieldset { margin: 0; padding: 0; border: 0; }
.tag-fieldset legend { margin-bottom: 8px; color: var(--texte-2); font-size: .9rem; font-weight: 680; }
.tag-choices { display: flex; flex-wrap: wrap; gap: 7px; }
.tag-choices label { display: inline-flex; min-height: 38px; align-items: center; gap: 7px; padding: 6px 11px; border: 1px solid var(--trait); border-radius: 999px; background: var(--fond-2); cursor: pointer; }
.tag-choices label:has(input:checked) { border-color: var(--accent); background: var(--accent-doux); color: var(--accent-2); }
.tag-choices input { width: 17px; min-height: 17px; accent-color: var(--accent); }
.trusted-hint { margin: -5px 0 0; font-size: .82rem; }
.trusted-import-panel { display: grid; grid-template-columns: minmax(0, 1fr) minmax(360px, .8fr); align-items: end; gap: 22px; }
.trusted-import-panel h2 { margin-bottom: 7px; }
.trusted-import-panel p { margin-bottom: 0; }
.trusted-import-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.trusted-import-form .btn { grid-column: 1 / -1; }
.trusted-list-head { align-items: end; }
.trusted-search { width: min(390px, 100%); }
.trusted-search input { padding-left: 40px; }
.trusted-tags button { flex: 0 0 auto; min-height: 38px; padding: 8px 12px; border: 1px solid var(--trait); border-radius: 999px; background: transparent; color: var(--muet); font-size: .84rem; font-weight: 720; }
.trusted-tags button:hover { color: var(--texte); }
.trusted-tags button.active { border-color: var(--accent); background: var(--accent-doux); color: var(--accent-2); }
.trusted-tags button span { color: var(--muet); font-size: .72rem; }
.trusted-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 11px; }
.trusted-card { display: flex; min-width: 0; min-height: 155px; flex-direction: column; justify-content: space-between; gap: 15px; padding: 16px; border: 1px solid var(--trait); border-radius: 15px; background: var(--surface); }
.trusted-card:hover { border-color: var(--trait-fort); }
.trusted-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.trusted-card-top > div { min-width: 0; }
.trusted-card h2 { margin: 0 0 5px; overflow-wrap: anywhere; }
.trusted-card a { display: inline-flex; max-width: 100%; align-items: center; gap: 5px; overflow: hidden; color: var(--accent-2); font-size: .85rem; font-weight: 700; text-overflow: ellipsis; white-space: nowrap; }
.trusted-card-tags { display: flex; flex-wrap: wrap; gap: 5px; }
.trusted-card[hidden] { display: none; }

.service-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.service-card { display: flex; align-items: flex-start; gap: 13px; padding: 17px; border: 1px solid var(--trait); border-radius: 15px; background: var(--surface); }
.service-card > div { min-width: 0; flex: 1; }
.service-card p { margin-bottom: 0; color: var(--texte-2); }
.service-card .icon-btn { width: 38px; height: 38px; }
.service-ico { display: grid; width: 43px; height: 43px; flex: 0 0 auto; place-items: center; border-radius: 12px; background: var(--accent-doux); color: var(--accent-2); }

.admin-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 13px; margin-bottom: 25px; }
.admin-tile { display: flex; min-height: 105px; align-items: center; gap: 14px; padding: 18px; border: 1px solid var(--trait); border-radius: var(--rayon); background: var(--surface); }
.admin-tile:hover { border-color: var(--accent); }
.admin-tile > span:nth-child(2) { display: grid; min-width: 0; flex: 1; }
.admin-tile small { color: var(--muet); }
.tile-ico { display: grid; width: 48px; height: 48px; place-items: center; border-radius: 14px; background: var(--accent-doux); color: var(--accent-2); }
.tile-ico .lucide { width: 23px; height: 23px; }

/* Un tableau large défile DANS son cadre, jamais en poussant la page. La règle
   porte sur le <div> qui l'enveloppe : un <table> ne défile pas, overflow-x n'a
   aucun effet sur un display: table. Même conteneur que .table-scroll chez les
   voisines. */
.data-table {
  max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--trait); border-radius: 14px;
}
table { width: 100%; border-collapse: collapse; background: var(--surface); font-size: .86rem; }
th, td { padding: 11px 13px; border-bottom: 1px solid var(--trait); text-align: left; vertical-align: top; }
th { background: var(--surface-2); color: var(--muet); font-size: .73rem; letter-spacing: .06em; text-transform: uppercase; }
tbody tr:last-child td { border-bottom: 0; }

.bars { display: flex; height: 135px; align-items: end; gap: 5px; padding-top: 10px; }
.bars > div { display: flex; height: 100%; min-width: 7px; flex: 1; flex-direction: column; justify-content: end; gap: 5px; }
.bars span { width: 100%; min-height: 4px; border-radius: 4px 4px 1px 1px; background: var(--accent); }
.bars small { color: var(--muet); font-size: .6rem; text-align: center; }

.pagination { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 24px; color: var(--muet); }

/* La page de connexion suit la même règle que les autres : son dégradé vient
   de la couleur de l'application, pas d'un bleu écrit en dur hérité d'ailleurs
   (c'est le même travers que le fond de champ bleu corrigé plus haut). */
.login-page { display: grid; min-height: 100vh; place-items: center; padding: 22px; background: radial-gradient(circle 40rem at 50% -4rem, color-mix(in srgb, var(--fruit-2) 16%, transparent), transparent), var(--fond); }
.login-box { width: min(430px, 100%); padding: clamp(23px, 6vw, 36px); border: 1px solid var(--trait); border-radius: 24px; background: var(--surface); }
.login-brand { display: flex; align-items: center; gap: 13px; margin-bottom: 23px; }
.login-brand h1 { font-size: 2.25rem; }
.login-box form { display: grid; gap: 15px; }
.error-box { text-align: center; }
.error-box .login-brand { justify-content: center; }
.error-box .notice { text-align: left; }

@media (max-width: 980px) {
  .filters { grid-template-columns: 1fr 1fr; }
  .filters .search-wrap { grid-column: 1 / -1; }
  .detail-grid { grid-template-columns: 1fr; }
  .service-grid { grid-template-columns: 1fr; }
  .trusted-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .trusted-import-panel { grid-template-columns: 1fr; }
}

/* ================================================================
   MODE APPLICATION (≤ 900px) : topbar fixe + pastille d'onglets
   flottante opaque. Grammaire commune à /srv/annuaire, /srv/contact,
   /srv/agenda et /srv/play — même seuil, mêmes mesures, mêmes gestes.
   La barre du bas est une pastille d'encre OPAQUE, détachée des bords,
   sans bordure ni flou, dont les onglets sont strictement identiques :
   la seule destination mise en avant est la page ouverte. Ne pas y
   réintroduire de trait, d'ombre ni de backdrop-filter.
   ================================================================ */
@media (max-width: 900px) {
  .layout { display: block; }
  .sidebar { display: none; }

  .topbar {
    display: flex; align-items: center; gap: 12px;
    position: fixed; top: 0; left: 0; right: 0; z-index: 60;
    background: color-mix(in srgb, var(--fond) 86%, transparent);
    -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--trait);
    padding: 10px 16px;
    padding-top: calc(10px + var(--safe-top));
    padding-left: calc(16px + var(--safe-left));
    padding-right: calc(16px + var(--safe-right));
  }
  /* La marque reprend la taille du groupe (34 px) : c'est elle qui donne sa
     hauteur à la barre, et une barre plus haute que chez les voisines se
     verrait au premier coup d'œil. */
  .topbar .brand-ico { margin: 0; width: 34px; height: 34px; border-radius: 11px; }
  .topbar .brand-ico svg { width: 21px; height: 21px; }
  .topbar-title { flex: 1; font-weight: 800; font-size: 17px; letter-spacing: -.2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Bouton texte « Admin » (sans icône) : même convention que l'Annuaire. */
  .topbar-admin {
    display: inline-flex; align-items: center; min-height: 34px;
    padding: 6px 14px; border-radius: 999px;
    background: rgba(255, 255, 255, .07); border: 1px solid var(--trait);
    color: var(--texte); font-size: 13.5px; font-weight: 700; letter-spacing: -.01em;
    white-space: nowrap; flex: none;
  }
  .topbar-admin:hover { text-decoration: none; border-color: var(--accent); }
  .topbar-admin.on {
    background: var(--accent-doux); color: var(--accent-2);
    border-color: color-mix(in srgb, var(--accent) 45%, var(--trait));
  }
  .topbar-bell { position: relative; display: inline-flex; padding: 4px 2px; color: var(--texte); flex: none; }
  .topbar-bell .lucide { width: 22px; height: 22px; }
  .topbar-bell:hover { text-decoration: none; }

  .tabbar {
    display: flex; align-items: stretch; gap: 6px;
    position: fixed; z-index: 60;
    left: calc(12px + var(--safe-left));
    right: calc(12px + var(--safe-right));
    bottom: calc(4px + var(--safe-bottom));
    transform: translateY(15px);
    padding: 7px;
    background: var(--tabbar-base);
    border-radius: 26px;
  }
  /* Sous la barre, la safe area devient un aplat opaque : le contenu
     s'arrête visuellement avant les bords arrondis. */
  body::after {
    content: ""; position: fixed; z-index: 59;
    left: 0; right: 0; bottom: 0;
    height: calc(4px + var(--safe-bottom));
    pointer-events: none; background: var(--tabbar-base);
  }
  .tab {
    position: relative; flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px; min-height: 66px; padding: 10px 2px;
    color: var(--muet); text-decoration: none; cursor: pointer;
    font-weight: 700; line-height: 1; letter-spacing: -.01em;
    border-radius: 20px; background: transparent;
    -webkit-user-select: none; user-select: none;
    transition: background .16s ease, color .16s ease, transform .1s ease;
  }
  .tab:hover { text-decoration: none; }
  .tab:active { transform: scale(.95); }
  .tab .t-ico { display: flex; align-items: center; justify-content: center; }
  .tab .t-ico .lucide { width: 25px; height: 25px; }
  .tab .t-lbl { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
  .tab.on { background: var(--accent-doux); color: var(--accent-2); font-weight: 800; }

  .content {
    width: 100%; margin-left: 0; min-height: 0;
    padding: calc(64px + var(--safe-top)) 14px calc(96px + var(--safe-bottom));
    padding-left: calc(14px + var(--safe-left));
    padding-right: calc(14px + var(--safe-right));
  }
  .login-box { margin: max(8vh, calc(24px + var(--safe-top))) auto; }
}

@media (max-width: 740px) {
  :root { --rayon: 16px; }
  h1 { font-size: 2.15rem; }
  .page-head { align-items: flex-start; flex-direction: column; margin-bottom: 19px; }
  /* Un titre de section et son bouton passent l'un sous l'autre plutôt que de
     forcer la largeur de la page. */
  .section-head { flex-wrap: wrap; }
  .page-head > form, .page-head > .btn, .head-actions { width: 100%; }
  .page-head > form .btn, .page-head > .btn, .head-actions .btn { flex: 1; }
  .notice { margin-bottom: 18px; }
  .stats-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stat { min-height: 108px; padding: 13px 14px 14px; gap: 12px; }
  .stat-val { font-size: 1.6rem; }
  .stat-tete { font-size: .74rem; }
  .filters { grid-template-columns: 1fr; }
  .filters .search-wrap { grid-column: auto; }
  .filters .btn { width: 100%; }
  input, select, textarea { font-size: 16px; }
  .form-grid { grid-template-columns: 1fr; }
  .form-grid .full { grid-column: auto; }
  .compact-form { align-items: stretch; flex-direction: column; }
  .carte { padding: 16px; }
  .actu-card { flex-direction: column; }
  .actu-visuel { width: 100%; aspect-ratio: 16 / 9; }
  .carte-illustree { flex-direction: column; }
  .article-hero { aspect-ratio: 16 / 9; }
  .carte-actions .btn { padding-inline: 12px; }
  .piste-card { align-items: flex-start; }
  .date-puce { width: 50px; height: 57px; }
  .actions-grid.two, .admin-grid { grid-template-columns: 1fr; }
  .source-row { align-items: flex-start; }
  .source-icon { display: none; }
  .row-actions { flex-direction: column; }
  .source-assign { grid-template-columns: 1fr; }
  .theme-top { align-items: flex-start; }
  .theme-edit { grid-template-columns: auto minmax(0, 1fr) auto; }
  .theme-edit .muted { grid-column: 2 / -1; }
  .category-add { width: 100%; }
  .category-add input { min-width: 0; }
  .trusted-import-form { grid-template-columns: 1fr; }
  .trusted-import-form .btn { grid-column: auto; }
  .trusted-list-head { align-items: stretch; }
  .trusted-search { width: 100%; }
  .trusted-grid { grid-template-columns: 1fr; }
  /* SUR TÉLÉPHONE, la ligne se plie en trois : le nom sur toute la largeur —
     c'est le seul champ qu'on vient vraiment modifier —, puis la couleur avec
     les deux actions, puis les compteurs. Rien ne se chevauche et rien ne
     descend sous la taille où l'on peut le lire. */
  .subject-row {
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "puce    nom     nom     nom"
      "couleur couleur valider archiver"
      "compte  compte  compte  compte";
    gap: 11px 9px;
  }
  .subject-row .sujet-couleur { width: 100%; }
  .subject-row .sujet-compte { justify-self: start; white-space: normal; }
  .service-card { padding: 14px; }
  .service-ico { display: none; }
  .facts > div { grid-template-columns: 1fr; gap: 4px; }
  .action-bar { align-items: stretch; }
  .action-bar form { flex: 1 1 auto; }
  .action-bar .btn { width: 100%; }
  .danger-zone { align-items: stretch; flex-direction: column; }
  .danger-zone label, .danger-zone input[type="number"], .danger-zone .btn { width: 100%; }
  .bars { height: 105px; }
  .bars small { display: none; }
  .pagination { flex-wrap: wrap; }
}

/* ================================================================
   COMMERCE — la fiche de STRATÉGIE et la fiche d'OPPORTUNITÉ.
   Les deux matières de l'application, et elles ne se ressemblent pas
   exprès : une stratégie est une chose qu'on ESSAIE (elle porte donc
   des compteurs), une opportunité est un fait EXTÉRIEUR (elle porte
   donc un état « en direct » et une adresse).
   Aucun box-shadow, jamais d'emoji : règles du groupe.
   ================================================================ */

/* L'ANGLE — prospection ou visibilité. C'est TOUTE la fusion des deux
   modules d'origine : une pastille, pas une page. */
.angle-puce {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border: 1px solid color-mix(in srgb, var(--teinte, var(--accent)) 45%, var(--trait));
  border-radius: 999px;
  background: color-mix(in srgb, var(--teinte, var(--accent)) 12%, var(--fond));
  color: var(--teinte, var(--accent-2));
  font-size: .71rem;
  font-weight: 800;
  white-space: nowrap;
}
.angle-puce .lucide { width: 13px; height: 13px; }

.fiche {
  overflow: hidden;
  border: 1px solid var(--trait);
  border-left: 3px solid var(--puce);
  border-radius: var(--rayon);
  background: var(--surface);
  scroll-margin-top: 90px;
}
.fiche + .fiche { margin-top: 11px; }
.fiche[open] { border-color: color-mix(in srgb, var(--puce) 45%, var(--trait)); }
.fiche.est-close { opacity: .62; border-left-style: dashed; }

.fiche > summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--surface-2);
  cursor: pointer;
  list-style: none;
}
.fiche > summary::-webkit-details-marker { display: none; }
.fiche > summary:hover { background: var(--surface-3); }
.fiche-chevron {
  display: grid;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--puce) 45%, var(--trait));
  border-radius: 50%;
  background: color-mix(in srgb, var(--puce) 16%, var(--fond));
  color: var(--puce);
  transition: transform .18s ease;
}
.fiche-chevron .lucide { width: 15px; height: 15px; }
.fiche[open] .fiche-chevron { transform: rotate(90deg); }
.fiche-tete { min-width: 0; flex: 1; }
.fiche-tete strong { display: block; font-size: .95rem; line-height: 1.35; }
.fiche-faits {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px 9px;
  margin-top: 6px;
  color: var(--muet);
  font-size: .74rem;
}
.fiche-faits span { display: inline-flex; align-items: center; gap: 4px; }
.fiche-faits .lucide { width: 13px; height: 13px; }
.fiche-corps { padding: 15px 16px 16px 58px; border-top: 1px solid var(--trait); }
.fiche-grille { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(260px, .75fr); gap: 18px; }
.fiche-bloc { margin-bottom: 14px; }
.fiche-bloc:last-child { margin-bottom: 0; }
.fiche-bloc h3 { margin: 0 0 5px; color: var(--muet); font-size: .66rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; }
.fiche-bloc p { margin: 0; color: var(--texte-2); font-size: .88rem; line-height: 1.55; white-space: pre-line; }

/* Les astuces : une liste, pas un paragraphe. C'est ce qu'on relit juste avant
   de s'y remettre, donc ça doit se balayer de l'oeil. */
.astuces { margin: 6px 0 0; padding: 0; list-style: none; }
.astuces li {
  position: relative;
  margin: 6px 0;
  padding-left: 19px;
  color: var(--texte-2);
  font-size: .86rem;
  line-height: 1.5;
}
.astuces li::before {
  content: "";
  position: absolute;
  top: .62em;
  left: 2px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--puce);
}

/* LE SUIVI — le bloc qui fait la différence entre un plan d'action et une
   liste de voeux. Deux boutons d'un clic au-dessus du formulaire complet :
   c'est le geste qu'on fait vraiment, « je viens de le tenter ». */
.suivi {
  padding: 14px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-petit);
  background: var(--fond-2);
}
.suivi-titre { margin-bottom: 10px; color: var(--texte); font-size: .8rem; font-weight: 800; }
.suivi label { gap: 4px; margin-bottom: 9px; font-size: .72rem; }
.suivi input, .suivi select { min-height: 40px; }
.suivi-essai { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px; }
.suivi-essai .btn { min-height: 42px; padding-inline: 8px; font-size: .82rem; }
.suivi-chiffres { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.suivi-chiffres label { margin-bottom: 0; }
.suivi .btn.enregistrer { width: 100%; margin-top: 11px; }
.suivi-outils { display: flex; justify-content: flex-end; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--trait); }

/* LE TAUX DE SUCCÈS. Il n'est PAS stocké : il se déduit des essais et des
   succès. Une valeur dérivée rangée en base finit toujours par diverger de ce
   dont elle dérive (leçon de /srv/recentre, 13 août 2026). */
.taux {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 10px;
}
.taux strong { color: var(--texte); font-size: 1.6rem; line-height: 1; }
.taux small { color: var(--muet); font-size: .76rem; }
.taux-vide { color: var(--muet); font-size: .82rem; font-style: italic; }

/* L'ÉTAT « EN DIRECT » d'une opportunité : ouvert, fermé, à venir, passé.
   Il est CALCULÉ AU RENDU, en heure de Paris, et jamais rangé en base —
   « ouvert » écrit en base est faux dès la minute suivante. */
.direct {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--trait);
  border-radius: 999px;
  font-size: .74rem;
  font-weight: 800;
  white-space: nowrap;
}
.direct .lucide { width: 14px; height: 14px; }
.direct.ok { border-color: color-mix(in srgb, var(--ok) 48%, var(--trait)); background: var(--ok-doux); color: #82ebc1; }
.direct.warn { border-color: color-mix(in srgb, var(--warn) 48%, var(--trait)); background: var(--warn-doux); color: #ffd080; }
.direct.err { border-color: color-mix(in srgb, var(--danger) 48%, var(--trait)); background: var(--danger-doux); color: #ffadb7; }
.direct.gris { color: var(--muet); }

/* Le lien vers l'extérieur. Commerce est la seule application du groupe dont
   les fiches portent des adresses de sites tiers : elles passent toutes par le
   redirecteur web.datadn.org (extUrl, server.js). */
.lien-dehors {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 4px;
  color: var(--accent-2);
  font-size: .86rem;
  font-weight: 700;
  overflow-wrap: anywhere;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.sources-liste { margin: 6px 0 0; padding: 0; list-style: none; font-size: .78rem; }
.sources-liste li { margin: 4px 0; color: var(--muet); overflow-wrap: anywhere; }

/* Les gestes d'une opportunité : quatre états, alignés, aucun mis en avant.
   Trier n'est pas décider — la décision, c'est d'y aller ou pas. */
.gestes { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.gestes form { display: flex; }
.gestes .btn { min-height: 38px; padding-inline: 11px; font-size: .8rem; }

.avis-moteur {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 0 20px;
  padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--warn) 45%, var(--trait));
  border-radius: var(--rayon-petit);
  background: var(--warn-doux);
  color: var(--warn);
  font-size: .86rem;
  line-height: 1.5;
}
.avis-moteur .lucide { flex: none; margin-top: 2px; }
.avis-moteur.alerte { border-color: color-mix(in srgb, var(--danger) 45%, var(--trait)); background: var(--danger-doux); color: #ffb3bb; }

.rapport-brut {
  max-height: 60vh;
  overflow: auto;
  margin: 0;
  padding: 15px 17px;
  border: 1px solid var(--trait);
  border-radius: var(--rayon-petit);
  background: var(--champ);
  color: var(--texte-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .fiche-grille { grid-template-columns: 1fr; }
}
@media (max-width: 740px) {
  .fiche-corps { padding: 13px 14px 14px; }
  .suivi-chiffres { grid-template-columns: 1fr; }
  .suivi-essai { grid-template-columns: 1fr; }
}

/* ================================================================
   iPhone étroit (≤ 380px) : la pastille et la topbar se resserrent —
   même réglage que dans le reste du groupe.
   ================================================================ */
@media (max-width: 380px) {
  .tabbar { gap: 4px; padding: 6px; }
  .tab { min-height: 62px; gap: 5px; border-radius: 18px; }
  .tab .t-ico .lucide { width: 23px; height: 23px; }
  .tab .t-lbl { font-size: 12px; }
  .topbar-admin { padding: 6px 11px; font-size: 13px; }
  .topbar { gap: 9px; }
}

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