/* Gestineo — Module Immobilier — feuille de style mobile-first (iPhone 12, portrait) */
:root {
  /* Palette pastel : les SURFACES sont douces, le texte et les icônes restent
     assez foncés pour rester lisibles (AA) — un pastel n'est pas un texte délavé. */
  --brand:#5f6fc9; --brand-dark:#4d5cb0; --brand-weak:#eceffb; --brand-ring:rgba(95,111,201,.25);
  /* ⚠️ ASSOMBRI LE 24/08 : `--accent` porte du texte BLANC (bouton d'appel
     à l'action) et sortait à 3,08:1 — sous le seuil AA, sur le bouton qu'on
     doit lire du premier coup d'œil. La TEINTE ne bouge pas, seule la
     luminosité : la marque reste la marque, elle devient lisible. 4,84:1. */
  --accent:#a75f38; --accent-weak:#fbeee4;
  /* Les deux univers du propriétaire, chacun sa teinte pastel. */
  --immo:#5f6fc9;  --immo-weak:#eceffb;      /* Mon Immo    — bleu lavande */
  --patri:#8a6fc0; --patri-weak:#f2ecfb;     /* Patrimonia  — violet doux  */
  --bg:#f8f7fc; --card:#ffffff; --ink:#2b2a3d; --ink-soft:#4c4a63; --muted:#6f6c88; --line:#eceaf4;
  /* Deux tons par état : le clair TEINTE les surfaces, le foncé PORTE le texte.
     Sans ce dédoublement, un libellé pastel sur fond pastel tombe sous le seuil AA. */
  --ok:#4a8f6d;     --ok-bg:#e8f4ee;     --ok-ink:#2f6b4f;
  --warn:#b3803a;   --warn-bg:#fbf2e4;   --warn-ink:#8a5f21;
  /* Même mesure, même remède : la pastille rouge portait du blanc à 3,89:1.
     5,13:1 désormais. */
  --danger:#b04f54; --danger-bg:#fbebec; --danger-ink:#99414a;
  --brand-ink:#414f9e; --patri-ink:#654a9a;
  --neutral-weak:#f1f0f7;   /* fond de badge / encadré neutre */
  --chev:#c6c3d6;           /* chevrons et séparateurs discrets */
  /* La largeur de l'app : la même valeur que `--app` de module.css — les deux
     feuilles servent le même produit et doivent tenir la même colonne. */
  --app-large:480px;
  /* Le fond HORS de la colonne, sur grand écran seulement. */
  --hors-app:#b6acd4;
  --radius:14px; --radius-sm:10px;
  --shadow:0 1px 3px rgba(43,42,61,.06),0 1px 2px rgba(43,42,61,.04);
  --shadow-lg:0 8px 24px rgba(43,42,61,.09);
  --tap:44px; /* cible tactile minimale */
}
* { box-sizing:border-box; }
html,body { margin:0; padding:0; }
body {
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg); color:var(--ink); font-size:15px; line-height:1.45;
  -webkit-font-smoothing:antialiased;
}
a { color:var(--brand); text-decoration:none; }

/* Accessibilité : anneau de focus visible au clavier, invisible à la souris. */
:focus-visible { outline:2px solid var(--brand); outline-offset:2px; border-radius:6px; }
.skip-link { position:absolute; left:-9999px; }
.skip-link:focus { left:8px; top:8px; z-index:100; background:#fff; padding:10px 14px; border-radius:10px; box-shadow:var(--shadow-lg); }
/* Lisible par les lecteurs d'écran, invisible à l'œil. */
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
@media (prefers-reduced-motion:reduce) { * { transition:none !important; animation:none !important; } }

/* Coquille centrée : sur grand écran, même contenu « zoomé » (largeur constante) */
.shell {
  max-width:480px; margin:0 auto; min-height:100dvh; background:var(--bg);
  position:relative; display:flex; flex-direction:column;
}
/* ⚠️ LE FOND HORS COLONNE (Paul, 21/08 : « tout ce qui est sur les côtés doit
   avoir une autre teinte pour bien distinguer sur un desktop l'affichage mobile
   du reste », puis « accentue l'écart »). Il ne vaut QUE sur grand écran : en
   dessous de 520 px la colonne occupe tout, ce fond n'existe pas, et le poser
   quand même changerait la couleur d'une page mobile pour rien.
   ⚠️ La teinte est plus sombre que la PLUS SOMBRE des deux colonnes (la lavande
   de la connexion, #e3dff2), sinon l'écart se voyait sur une page et pas sur
   l'autre. Mesuré : 1,64 contre la lavande, 2,00 contre le blanc cassé — là où
   l'ombre seule donnait 1,00, c'est-à-dire rien. */
/* ⚠️ LA LARGEUR NE SUFFIT PAS À DIRE « BUREAU », ET UN TÉLÉPHONE EN PAYSAGE
   LE PROUVE : il fait 844 px de large, donc il passait la barre des 520 et le
   violet apparaissait — précisément ce que Paul ne veut jamais voir sur mobile
   (21/08). Agrandir le seuil ne règle rien : les plus grands téléphones
   dépassent 900 px couchés, et on finirait par exclure de vrais petits écrans
   de bureau.

   Le signal juste n'est pas la taille, c'est le POINTEUR. Un doigt rapporte
   `pointer: coarse` et `hover: none` ; une souris, `fine` et `hover`. Or ce
   cadre n'existe que pour distinguer l'application mobile de ce qui l'entoure
   sur un grand écran : un appareil tactile n'a rien autour, et n'en a donc
   jamais besoin. La condition dit désormais ce qu'elle veut vraiment dire. */
@media (min-width:520px) and (hover:hover) and (pointer:fine){
  body { background:var(--hors-app); }
  .shell { box-shadow:0 0 40px rgba(0,0,0,.10); }
  .auth-wrap { box-shadow:0 0 40px rgba(0,0,0,.10); }
}

/* ⑦⑪ — DESKTOP = COLONNE MOBILE CENTRÉE, POUR LE SHELL V1 AUSSI (Paul, 08/09 :
   « desktop = colonne mobile centrée, jamais pleine largeur » ; « le fix doit
   s'appliquer à TOUTES les pages de l'app — Mon compte, dashboard… — via une
   règle de layout globale, pas page par page »).

   Les coquilles historiques (.shell, .coquille, .accueil .ac-shell, .auth-wrap)
   se calent à 480 et se centrent depuis toujours ; le shell V1 `.v1c`, lui, NE
   BORNAIT RIEN — seul son contenu se centrait par section (.body.mid à 460, les
   cartes marketplace à 440). Résultat sur grand écran : « Mon compte » étalé sur
   toute la largeur (⑪), et sur la connexion l'en-tête `.hd` — donc le chevron
   `.bk` — collé au BORD DE L'ÉCRAN au lieu du bord de la colonne (⑦). Une SEULE
   règle, au niveau du shell, remet tout `.v1c` en colonne de 480 centrée.

   ⚠️ ELLE VIT ICI (app.css), PAS DANS v1.css — v1.css est GÉNÉRÉ par
   extract-v1c.py (« ne pas éditer les règles à la main ») ; une règle posée
   là-bas repartirait à la prochaine réextraction. app.css est servi partout où
   un `.v1c` est AUTONOME (layouts accueil / vierge) ; dans un module (.coquille)
   la coquille NE charge PAS app.css et borne déjà à 480 — cette règle ne
   l'atteint donc pas, et il n'y a aucune double contrainte.
   ⚠️ PAS D'OMBRE NI DE CADRE ICI : `body.page-publique` retire volontairement le
   cadre du bureau (Paul, 21/08 : « ces pages ne sont pas l'application ») ; le
   fond hors-colonne reste géré par contexte (blanc en public, teinté en app).
   Sur mobile (≤480) la colonne prend tout : max-width plafonne, ne force pas. */
.v1c { max-width:480px; width:100%; margin-inline:auto; }

/* En-tête */
.topbar {
  position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:8px;
  padding:10px 12px; background:#fff; border-bottom:1px solid var(--line);
}
.brand { display:flex; align-items:center; gap:8px; font-weight:700; min-width:0; }
.brand .logo { width:28px; height:28px; color:var(--brand); flex-shrink:0; }
.brand .sub { color:var(--muted); font-weight:500; }
/* ⚠️ ALIGNEMENT VERTICAL LOGO ↔ MARQUE (Paul, 01/09) — même correctif que la barre
   du module : `text-box:trim-both cap alphabetic` rogne la boîte du texte aux
   capitales/ligne de base pour que `align-items:center` le centre sur le logo,
   INDÉPENDAMMENT de la police (donc de la plateforme). Sur l'élément enveloppant
   l'élément enveloppant, jamais sur le conteneur flex `.brand` (n'y ferait rien).
   ⚠️ Classe `.brand-txt` et NON `.bt` : `.bt` est déjà le BOUTON de module.css
   (collision mesurée le 01/09 — une pastille grise apparaissait derrière le texte). */
.brand .brand-txt { min-width:0; text-box:trim-both cap alphabetic; }
/* ⚠️ SOUS 360 px, « · Immobilia » PASSE SOUS LE BOUTON. Mesuré à 320 px
   (iPhone SE) sur /formules, où la barre porte à la fois un chevron, la marque
   et « Se connecter » : le sous-titre courait jusqu'à x=230 quand le bouton
   commence à x=194 — 36 px de recouvrement, du texte lisible par-dessus un
   bouton cliquable.

   Rien ne l'attrape : `.brand` est en `overflow:visible`, donc la PAGE ne
   déborde pas et aucune mesure de largeur ne rougit. Il faut comparer les
   positions de deux éléments voisins, ou regarder l'écran.

   C'est le nom de l'UNIVERS qui s'efface, jamais celui du produit : sur un
   écran de 320 px, savoir qu'on est dans Gestineo suffit — on vient d'y entrer
   par un module qu'on a choisi soi-même. */
@media (max-width:360px){
  .brand .sub{display:none}
}
.topbar .actions { display:flex; align-items:center; gap:10px; margin-left:auto; }
.topbar .who { font-size:13px; color:var(--muted); max-width:110px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Flèche retour contextuelle */
.backlink {
  display:grid; place-items:center; width:36px; height:36px; margin-left:-4px;
  border-radius:10px; color:var(--ink); flex-shrink:0;
}
.backlink svg { width:22px; height:22px; }
.backlink:active { background:var(--bg); }

/* Bouton icône (en-tête) */
.icon-btn {
  display:grid; place-items:center; width:36px; height:36px; border:0; border-radius:10px;
  background:none; color:var(--muted); cursor:pointer; padding:0;
}
.icon-btn svg { width:20px; height:20px; }

/* 🔴 44 px DE DOIGT SANS GROSSIR L'ENCRE — et la nuance est tout le sujet.
   `.icon-btn` (« Se déconnecter », « Mon compte ») et `.backlink` (la flèche de
   retour) mesurent 36×36. Mesuré le 28/08 dans un navigateur, sur la vraie
   feuille : la zone qui RÉPOND vaut **34 px** — le bouton, pas sa boîte. Apple
   demande 44, Material 48. Ils sont sur CHAQUE écran servi par `app.css`.

   ⚠️ ON N'ÉLARGIT PAS LA BOÎTE, ET C'EST MESURÉ, PAS CRAINT. L'en-tête se
   dimensionne sur son plus haut enfant : le 19/08, un lien posé à 30 px l'a fait
   passer de 46 à 53 px — sept pixels pris au CORPS, qui est en `overflow:hidden`,
   donc sept pixels de contenu devenus injoignables. Porter ces boutons à 44×44
   ferait exactement ça. Le pseudo-élément, lui, est `absolute` : il ne participe
   pas à la mise en page, donc l'en-tête ne bouge pas — par construction, pas par
   chance.

   ⚠️ ET C'EST L'IDIOME DÉJÀ EN USAGE ICI : c'est lui qui donne 44 px à un
   rond de 14 px dans l'état des lieux, et `audit-tactile.mjs` sait le lire (il
   interroge le navigateur à 21 px du centre au lieu de croire le rectangle).

   ⚠️ `module.css` N'A PAS BESOIN DE LA RÈGLE, et je l'ai vérifié plutôt que
   de le supposer : `.icon-btn` et `.backlink` ne vivent que dans
   `views/layouts/base.php`, qui charge `app.css`. Le paquet natif passe par
   `layouts/module.php` et ne les emploie nulle part. Ce n'est donc PAS le piège
   `.small`/`.muted` du 22/08 — là, la classe ÉTAIT employée des deux côtés. */
.icon-btn, .backlink { position:relative; }
.icon-btn::after, .backlink::after {
  content:""; position:absolute; left:50%; top:50%;
  width:var(--tap, 44px); height:var(--tap, 44px);
  transform:translate(-50%, -50%);
}
.icon-btn:active { background:var(--bg); }

/* Contenu */
.content { flex:1; padding:16px 16px 90px; }
.page-title { font-size:20px; font-weight:700; margin:4px 0 14px; letter-spacing:-.2px; }
.page-title .sous { display:block; font-size:13px; font-weight:400; color:var(--muted); margin-top:2px; letter-spacing:0; }

/* Cartes */
.card { background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); padding:16px; margin-bottom:14px; }
.card h2, .section-title { font-size:15px; font-weight:700; margin:0 0 10px; }
.card-head { display:flex; align-items:center; justify-content:space-between; gap:10px; margin-bottom:10px; }
.card-head h2 { margin:0; }

/* Grille de stats */
.stat-grid { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-bottom:14px; }
.stat { background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); padding:14px; }
.stat .label { font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.3px; }
.stat .value { font-size:22px; font-weight:750; margin-top:4px; }
.stat .value.small { font-size:18px; }
.stat.brand { background:var(--brand); border-color:var(--brand); color:#fff; }
.stat.brand .label { color:rgba(255,255,255,.85); }
.stat.brand .small { color:rgba(255,255,255,.8); }

/* Listes */
.list { list-style:none; margin:0; padding:0; }
.list li { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:11px 0; border-bottom:1px solid var(--line); }
.list li:last-child { border-bottom:none; }
.list .titre { font-weight:600; }
.list .meta { font-size:13px; color:var(--muted); }

/* Liste empilée : titre puis détails, chacun sur sa ligne. Sans cela les spans
   restent en ligne et les trois informations se lisent comme une seule phrase. */
.list.empilee .titre, .list.empilee .meta { display:block; }

/* Vignette d'annonce. Taille FIXE, occupée ou non : une liste dont les lignes
   changent de hauteur selon la présence d'une photo se lit mal, et le
   remplacement par une icône dit « pas de photo » sans laisser un trou. */
.vignette {
  flex:0 0 auto; width:72px; height:72px; border-radius:10px; overflow:hidden;
  background:var(--neutral-weak); display:grid; place-items:center; color:var(--muted);
}
.vignette img { width:100%; height:100%; object-fit:cover; display:block; }
.vignette svg { width:26px; height:26px; }

/* Galerie d'une annonce : une bande qui défile horizontalement, jamais la page. */
.galerie { display:flex; gap:8px; overflow-x:auto; -webkit-overflow-scrolling:touch; padding-bottom:4px; }
.galerie figure { margin:0; flex:0 0 auto; width:min(78%, 300px); }
.galerie img { width:100%; height:200px; object-fit:cover; border-radius:12px; display:block; background:var(--neutral-weak); }
.galerie figcaption { font-size:12px; color:var(--muted); margin-top:4px; }

/* Ligne de liste cliquable : toute la ligne est la cible, avec un chevron */
.list a.row { display:flex; align-items:center; gap:10px; flex:1; min-width:0; color:inherit; min-height:var(--tap); }
.list a.row .grow { flex:1; min-width:0; }
.list a.row .chev { color:var(--chev); font-size:20px; line-height:1; flex-shrink:0; }
.list a.row:active { opacity:.7; }

/* Badges */
.badge { display:inline-block; font-size:12px; font-weight:600; padding:3px 9px; border-radius:999px; background:var(--neutral-weak); color:var(--ink-soft); white-space:nowrap; }
.badge.ok { background:var(--ok-bg); color:var(--ok-ink); }
.badge.warn { background:var(--warn-bg); color:var(--warn-ink); }
.badge.danger { background:var(--danger-bg); color:var(--danger-ink); }
.badge.brand { background:var(--brand-weak); color:var(--brand-ink); }

/* Boutons */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  min-height:var(--tap); padding:11px 16px; border-radius:12px; border:1px solid var(--line);
  background:#fff; color:var(--ink); font-size:15px; font-weight:600; cursor:pointer;
  text-align:center; transition:filter .1s ease, transform .06s ease;
}
.btn:active { transform:translateY(1px); }
.btn:disabled { opacity:.55; cursor:default; transform:none; }
.btn-primary { background:var(--brand); border-color:var(--brand); color:#fff; }
.btn-accent { background:var(--accent); border-color:var(--accent); color:#fff; }
.btn-danger { border-color:var(--danger-bg); background:var(--danger-bg); color:var(--danger-ink); }
.btn-ghost { border-color:transparent; background:transparent; color:var(--brand); }
.btn-block { width:100%; }
.btn-sm { min-height:34px; padding:7px 12px; font-size:13px; border-radius:10px; gap:5px; white-space:nowrap; }
.btn svg { width:17px; height:17px; flex-shrink:0; }

/* Rangée de boutons qui se répartissent équitablement */
.btn-row { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
.btn-row > * { flex:1; min-width:130px; }

/* Formulaires */
.field { margin-bottom:12px; }
.field label { display:block; font-size:13px; font-weight:600; color:var(--ink-soft); margin-bottom:5px; }
.field input, .field select, .field textarea {
  width:100%; min-height:var(--tap); padding:11px 12px; border:1px solid var(--line); border-radius:var(--radius-sm);
  font:inherit; color:var(--ink); background:#fff;
}
.field textarea { min-height:auto; }
.field input:focus, .field select:focus, .field textarea:focus { outline:2px solid var(--brand-ring); outline-offset:0; border-color:var(--brand); }
.field .check { display:flex; align-items:center; gap:8px; font-weight:500; min-height:var(--tap); }
.field .check input { width:auto; min-height:auto; width:18px; height:18px; }
.field .aide { font-size:12px; color:var(--muted); margin-top:4px; }
.grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:10px; }

/* Messages flash */
.flash { padding:11px 14px; border-radius:12px; margin-bottom:14px; font-size:14px; }
.flash.ok { background:var(--ok-bg); color:var(--ok-ink); }
.flash.err { background:var(--danger-bg); color:var(--danger-ink); }
/* Mode démonstration : la teinte d'avertissement, parce que c'en est un. Ni
   verte (ce n'est pas une réussite), ni rouge (rien n'a échoué) — un état de
   l'application qui ne doit pas passer inaperçu, et qui n'existe jamais en
   ligne. `.demo` et `.demo-roles` sont des noms LIBRES : vérifiés dans les
   deux feuilles avant d'être posés (le précédent `.jour`, promu sur un nom
   déjà pris, changeait l'allure d'un écran que personne n'avait touché). */
.flash.demo { background:var(--warn-bg); color:var(--warn-ink); }
.demo-roles { display:grid; grid-template-columns:repeat(2,1fr); gap:8px; margin-bottom:4px; }
.demo-roles form { margin:0; }
.demo-roles .btn { width:100%; }

/* Encadré d'information (neutre / avertissement) */
.callout { display:flex; gap:10px; padding:11px 13px; border-radius:12px; background:var(--neutral-weak); color:var(--ink-soft); font-size:13px; line-height:1.45; margin-bottom:12px; }
.callout.warn { background:var(--warn-bg); color:var(--warn-ink); }
.callout svg { width:18px; height:18px; flex-shrink:0; margin-top:1px; }

/* Tableaux (scroll interne autorisé) */
.table-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch; }
table.data { width:100%; border-collapse:collapse; font-size:14px; }
table.data th, table.data td { text-align:left; padding:9px 10px; border-bottom:1px solid var(--line); white-space:nowrap; }
table.data th { color:var(--muted); font-weight:600; font-size:12px; text-transform:uppercase; }

/* Navigation basse */
.bottomnav {
  position:fixed; bottom:0; left:50%; transform:translateX(-50%); width:100%; max-width:480px;
  display:flex; background:#fff; border-top:1px solid var(--line); z-index:30;
  padding:6px 4px calc(6px + env(safe-area-inset-bottom));
}
.bottomnav a { flex:1; display:flex; flex-direction:column; align-items:center; gap:2px; padding:6px 2px; color:var(--muted); font-size:11px; font-weight:600; }
.bottomnav a .ic { width:22px; height:22px; }
.bottomnav a.active { color:var(--brand); }

/* Écran de connexion */
/* ⚠️ LE FOND DE LA PAGE DE CONNEXION N'EST PAS `--bg` (Paul, 19/08 : « le
   contour de Gestineo et le fond de la page de connexion doivent être plus
   prononcé comme contraste »). Mesuré : `--bg` (#f8f7fc) contre la carte
   blanche donne un rapport de 1,07 — c'est-à-dire RIEN. La carte ne se
   détachait pas, elle flottait ; sur un écran de téléphone en plein jour on
   ne voyait qu'une page blanche avec des champs dessus.

   #e3dff2 donne 1,30. Ce n'est toujours pas beaucoup — et c'est voulu : la
   page d'accueil du site n'a pas à crier. Mais 1,30 dessine un bord, là où
   1,07 n'en dessinait aucun. La teinte est celle de la marque, pas un gris :
   un fond gris aurait éteint le lavande du monogramme juste au-dessus.

   Il ne touche QUE cette page — `--bg` reste ce qu'il est partout ailleurs,
   où les cartes sont nombreuses et où un fond soutenu fatiguerait. */

/* ═══════════════════════════════════════════════════════════════════════════
   LA PAGE PUBLIQUE DES FORMULES
   Promue de l'établi le 20/08, après une douzaine de passes d'arbitrage.

   ⚠️ ELLE EST ÉCRITE AVEC LES VARIABLES D'app.css, PAS CELLES DE module.css.
   L'établi rend cette grille dans la coquille du module, qui pose --acc, --l,
   --mut, --i2. La page publique, elle, vit dans le layout `base` : ces
   variables n'y existent pas, et une couleur qui n'existe pas ne se voit pas —
   elle tombe sur la valeur héritée, donc du noir sur blanc. Recopier les règles
   telles quelles aurait donné une page qui « marche » et qui est illisible.
   Correspondances : --acc → --brand · --acc-s → --brand-weak · --l → --line ·
   --mut → --muted · --i2 → --ink-soft · --surface → --card.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Le code promo, en tête : il CHANGE LES PRIX qu'on va lire, donc il ne peut
   pas arriver après la décision. Le trait le sépare de la grille — à 1 px il
   se lisait comme une bordure de champ de plus. */
.promo-haut { display:flex; gap:8px; margin:0 0 6px; padding-bottom:9px;
  border-bottom:2px solid var(--line); }
/* ⚠️ 44 px, LA CIBLE TACTILE DU DÉPÔT (`--tap`). Mesurés à 35 px sur la page
   servie : c'est un champ qu'on remplit au pouce, sur la page qui vend, et le
   bouton juste à côté était le plus petit élément cliquable de l'écran hors
   barre. La barre, elle, reste à 36 — la grandir volerait 8 px de contenu sur
   les quarante écrans de l'application, dont le corps est en overflow:hidden. */
.promo-haut input { flex:1 1 auto; min-width:0; min-height:44px; padding:0 12px;
  border:1px solid var(--line); border-radius:10px; background:var(--card);
  font:inherit; font-size:13px; color:var(--ink); }
.promo-haut button { flex:0 0 auto; min-height:44px; padding:0 16px; border:0;
  border-radius:10px; background:var(--brand); color:#fff; font:inherit;
  font-size:12.5px; font-weight:700; cursor:pointer; }

.offres { display:flex; flex-direction:column; gap:9px; }

/* ⚠️ LE FOND BLANC EST REVENU (Paul, 20/08 : « chaque offre avait un encadré
   blanc, peux-tu le remettre ? »). Il avait été retiré le matin même, sur sa
   demande — et vu en place, l'écran y a perdu : sur le fond teinté de la page,
   un simple contour ne SÉPARE pas quatre offres, il les aligne. Le blanc en
   fait des cartes qu'on compare une à une. Aller-retour assumé : c'est à cela
   que sert l'établi. */
/* ⚠️ LA CARTE N'A PLUS DE REMBOURRAGE EN HAUT : le bandeau doit aller de bord
   à bord, et un `padding` sur la carte laisserait une lisière blanche autour de
   lui — une bande sombre encadrée de blanc se lit comme une erreur, pas comme
   un en-tête. `overflow:hidden` fait suivre les coins arrondis au bandeau. */
.offre { border:1px solid var(--line); border-radius:13px; padding:0 0 12px;
  background:var(--card); box-shadow:var(--shadow); overflow:hidden; }
.offre > *:not(.haut):not(.zone):not(.choix) { margin-left:13px; margin-right:13px; }
.offre.tenue { border-color:var(--brand); box-shadow:0 0 0 1px var(--brand); }

/* ⚠️ LE COÛT PAR BIEN EST DANS LA LIGNE, PAS AU BOUT (Paul, 20/08 : « 10 biens
   loués (75 €/an/bien) — ne met pas les €/an sur cette ligne au bout »). En
   note à droite, il s'alignait sous les autres notes et se lisait comme une
   colonne de valeurs. Entre parenthèses il qualifie le nombre qu'il précède :
   c'est la même phrase, et elle se lit d'un trait. Plus discret que le nombre,
   parce qu'il l'explique — il ne le concurrence pas. */
/* ⚠️ `.par-b` et `.offre li em` ONT ÉTÉ RETIRÉES LE 20/08, avec la seule ligne
   qui les rendait : « (un bien vide ne compte pas) ». Une règle qui ne désigne
   plus rien n'est pas neutre — elle décrit une mise en page que le produit ne
   rend pas, et la prochaine session la lit comme une intention à respecter. */

/* ⚠️ CENTRÉ EN HAUTEUR, pas sur la ligne de base : le bloc de prix fait trois
   lignes quand le nom n'en fait qu'une, et calés sur la même base ils se
   lisaient comme deux blocs sans rapport. */
/* ═══ LE BANDEAU DE FORMULE ════════════════════════════════════════════════
   Paul, 21/08 : « fais un bandeau pour Free 0 %, Starter 2 % 190 € min/an, etc.
   des bandeaux un peu foncés et du coup le texte en blanc et bleu clair ».

   ⚠️ IL PORTE LE NOM ET LE PRIX, ET RIEN D'AUTRE. C'est la ligne qu'on compare
   d'une carte à l'autre : tout ce qu'on y ajoute se paie en temps de lecture
   sur QUATRE cartes à la fois.

   ⚠️ ET LE FOND EST CELUI DU HÉROS DE L'ACCUEIL, pas un gris. Les deux pages
   se suivent dans le parcours : un bandeau d'une autre famille de sombre
   donnerait l'impression d'avoir changé de site entre l'accueil et les prix. */
.offre .haut {
  display:flex; align-items:center; gap:7px;
  padding:11px 13px; margin:0 0 12px;
  background:linear-gradient(168deg,#171430 0%,#241f45 100%);
}
.offre .nom { font-size:16px; font-weight:800; letter-spacing:-.03em; color:#fff; }
/* ⚠️ `.nom-module` A ÉTÉ RETIRÉE (Paul, 22/08 : « écris-les de la même taille »).
   Elle ne portait qu'un rapetissement, et son ordre : le module passait APRÈS la
   formule, en plus petit. Les deux se lisent maintenant d'un poids égal, et c'est
   `Immobilia` qui ouvre - il nomme le produit, la formule n'en est qu'un palier. */
/* ⚠️ VERT, ET SANS VARIANTE (Paul, 20/08). Il n'y a plus qu'UN macaron sur la
   grille — « Conseillé », sur Pro — donc plus rien à distinguer : `.eti.val`
   n'existait que pour teinter le second, « Best value », et sa classe se
   choisissait dans la vue en comparant le LIBELLÉ. Renommer l'étiquette au
   catalogue lui aurait fait perdre sa couleur en silence. La couleur appartient
   maintenant au macaron lui-même.
   ⚠️ LE VERT PLUTÔT QUE LA COULEUR DE MARQUE : le violet est celui des boutons
   « S'abonner » juste en dessous, et le macaron s'y fondait — il désignait la
   formule recommandée avec exactement la teinte que porte chaque carte. */
/* ⚠️ 9 px NE SE LIT PAS SUR UN TÉLÉPHONE, et c'est le macaron qui ORIENTE le
   choix — « Conseillé », sur Pro. Une recommandation qu'on ne déchiffre pas ne
   recommande rien. À 10,5 px elle reste plus petite que tout ce qui l'entoure,
   donc toujours un macaron, mais lisible. */
.offre .eti { font-size:11px; font-weight:800; letter-spacing:.04em;
  text-transform:uppercase; padding:2px 7px; border-radius:999px;
  background:var(--ok-bg); color:var(--ok-ink); }

/* ⚠️ « 49 € PAR MOIS » SUR UNE SEULE LIGNE : sur deux, l'œil devait descendre
   pour savoir de quoi on parlait — et « 49 » seul, gros et coloré, se lit une
   fraction de seconde comme le prix annuel. */
.offre .prix { margin-left:auto; text-align:right; white-space:nowrap; line-height:1.2; }
.offre .prix b { display:inline; font-size:18px; font-weight:800;
  letter-spacing:-.04em; color:var(--brand); }
/* ⚠️ L'ESPACE ENTRE LE NOMBRE ET SON UNITÉ (Paul, 20/08 : « met de l'espace
   entre 49 € et "par mois" · idem pour toutes les formules »). 3 px, c'est le
   crénage d'un caractère : les deux se lisaient comme un seul mot. 7 px les
   sépare sans les éloigner — et c'est ici, une fois, pour les quatre formules.
   Une espace insécable écrite dans le gabarit aurait fait la même chose une
   fois sur quatre, et disparu au premier copier-coller. */
.offre .prix i { display:inline; font-style:normal; font-size:11px;
  color:var(--muted); margin-left:7px; }
.offre .prix s { display:block; font-size:11px; color:var(--muted); }
.offre .prix u { display:block; text-decoration:none; margin-top:3px;
  font-size:11px; font-weight:700; color:var(--ink-soft); }
.offre .prix em { font-style:normal; font-weight:800; color:var(--ok-ink); }

/* Le trait à MI-LARGEUR : il sépare le prix de ce qu'on gagne en plus, sans
   fermer la carte comme le ferait un filet pleine largeur. */
.offre .en-plus { margin:10px 0 6px; font-size:11px; font-weight:700;
  color:var(--muted); position:relative; padding-bottom:7px; }
.offre .en-plus::after { content:""; position:absolute; left:0; bottom:0;
  width:50%; height:1px; background:var(--line); }

.offre ul { list-style:none; margin:8px 0 12px; padding:0; }
/* ⚠️ PLUS AUCUNE CROIX (Paul, 20/08). Une croix rouge sur une carte qu'on
   essaie de vendre dit d'abord ce qu'on n'a PAS : sur Starter, trois lignes
   barrées pesaient plus que les deux acquises. Ce qui n'est pas dans le palier
   n'y figure plus, et se retrouve en positif sur celui qui l'apporte. */
.offre li { display:flex; align-items:flex-start; gap:7px; padding:3px 0;
  font-size:12.5px; line-height:1.4; color:var(--ink-soft); }
.offre li::before { content:"✓"; flex:0 0 auto; font-weight:800;
  color:var(--ok-ink); font-size:12px; line-height:1.5; }
.offre li span { flex:1 1 auto; min-width:0; }
.offre li span b { color:var(--ink); font-weight:700; }
.offre li span i { font-style:italic; color:var(--muted); }

/* ═══ LA PROTECTION FAIBLES LOYERS - UNE LIGNE, TOUJOURS ═══════════════════
   Paul, 22/08 : « "Protection faibles loyers : Abonnement plafonné à 10% des
   loyers CC" sur une seule ligne ».

   ⚠️ LA PHRASE FAIT 390 px À LA TAILLE DES AUTRES PUCES, et la carte n'en offre
   que 280 sur un téléphone de 360. Aucun réglage fixe ne pouvait donc tenir :
   à 12,5 px elle passait en DEUX lignes sous 480 px, c'est-à-dire exactement là
   où on la lit. La police suit donc la largeur - mesurée, pas devinée : la
   phrase occupe 390 px à 12,5 px, elle tient donc sous « 12,5 × largeur / 390 ».
   D'où le calc ci-dessous, qui reste sous cette courbe de 360 à 520 px, et les
   deux bornes qui l'arrêtent : 12,5 px quand la place ne manque plus, 7 px
   quand elle manque tout à fait.

   ⚠️ ET LE nowrap SEUL AURAIT ÉTÉ UN PIÈGE : sous 340 px, même 7,5 px ne suffit
   plus - et une ligne insécable qui ne rentre pas ne se replie pas, elle POUSSE
   la carte et fait glisser la page entière de travers. Le triplet min-width:0 +
   overflow:hidden + text-overflow:ellipsis fait qu'au pire la phrase se termine
   par des points de suspension : ça se voit, donc ça se corrige. Une page qui
   défile latéralement, on ne sait jamais d'où ça vient.

   ⚠️ LA COCHE SUIT (font-size:1em). Figée à 12 px devant un texte à 9, elle
   aurait pris l'allure d'une puce de titre : c'est le RAPPORT entre les deux
   qui fait lire « un item de liste » plutôt que « deux éléments côte à côte ».

   ⚠️ L'ÉTABLI NE VERRA RIEN DE TOUT ÇA : son écran des tarifs est rendu avec
   module.css + SUP_TARIFS, pas avec cette feuille. Piège déjà au journal (le
   plancher tarifaire du 20/08). À reporter quand Paul demandera la mise à jour. */
.offre li.protection { font-size:clamp(7px, calc(3.1vw - 2.6px), 12.5px); }
.offre li.protection::before { font-size:1em; }
.offre li.protection .une-ligne {
  white-space:nowrap; min-width:0; overflow:hidden; text-overflow:ellipsis;
}
/* Le coût par bien, à droite et discret : c'est une lecture, pas la promesse.
   ⚠️ EN COLONNE À DROITE et non à la suite du libellé — collé, il se lirait
   comme un prix par bien À PAYER en plus de l'abonnement. */

/* ⚠️ PAS DE `width:100%` ICI - C'EST CE QUI LE FAISAIT DÉPASSER (Paul, 22/08,
   capture à l'appui). La carte donne 13 px de marge à gauche et à droite via
   `.offre > *:not(.haut)…` ; `width:100%` valant 100 % du contenu du PARENT, le
   bouton mesurait la largeur entière PLUS ses 26 px de marge, et sortait des
   deux côtés. Un élément `display:block` remplit déjà la place disponible en
   retranchant ses marges : la largeur imposée ne servait à rien, elle ne faisait
   que casser le calcul. `box-sizing` n'y pouvait rien - il gère le rembourrage
   et la bordure, jamais la marge. */
.go-offre { display:block; padding:10px; border-radius:11px;
  background:var(--brand); color:#fff; font-size:13px; font-weight:700;
  text-align:center; text-decoration:none; box-sizing:border-box; }
.go-offre.doux { background:var(--brand-weak); color:var(--brand-ink); }

/* ═══ LA BANDE HAUTE DE LA PAGE PUBLIQUE ═══════════════════════════════
   Promue de l'établi le 20/08, après deux passes d'arbitrage de Paul.
   ⚠️ LE BOUTON EST PLEIN, PAS FANTÔME : c'est la seule autre chose à faire sur
   cette page que de se connecter, et un contour vide sur un fond teinté se
   serait lu comme une zone désactivée.
   ⚠️ LE FOND ET LE FILET FONT LA BARRE. Sans eux la bande est transparente et
   le bouton flotte : rien ne dit où commence le contenu. */
.entete-pub { position:absolute; top:0; left:0; right:0; height:60px;
  display:flex; align-items:center; justify-content:flex-end;
  /* ⚠️ AUCUN REMBOURRAGE À GAUCHE, ET C'EST LA MESURE QUI L'A IMPOSÉ (Paul,
     20/08 : « centre sur l'espace entre le BORD GAUCHE et le bouton »). Avec
     20 px à gauche, la zone libre commençait à 20 et non à 0 : le mot tombait
     à 135 là où le milieu réel est 125 — dix pixels, invisibles à l'œil nu,
     mais exactement ce qui fait qu'un centrage sonne faux. Le bord droit garde
     ses 20 px : c'est la marge du bouton. */
  padding:0 20px 0 0; box-sizing:border-box;
  background:var(--card); border-bottom:1px solid #c4bddd; }
/* ⚠️ « BIENVENUE » EST CENTRÉ DANS L'ESPACE LIBRE, PAS DANS LA BANDE (Paul,
   20/08). Centré sur la bande entière, il paraîtrait décalé à gauche, le bouton
   poussant tout l'équilibre à droite. Et le centrage vient du FLEX, jamais d'un
   calage en dur : `flex:1` lui donne tout l'espace restant, son `text-align`
   EN EST le milieu. Un `padding-left` calculé ne vaudrait que pour CE libellé
   et CETTE largeur de bouton.
   ⚠️ EN CAPITALES, NI GROS NI GRAS (Paul : « ne met pas en gras le Bienvenue
   et fais ça moins gros »). C'est un ACCUEIL, pas un titre — le titre de cette
   page est la marque, juste en dessous. À 24 px et en 800 il lui disputait le
   regard. 17 px en graisse normale : l'interlettrage suffit à le poser. */
.entete-pub .bienvenue { flex:1 1 auto; min-width:0; text-align:center;
  font-size:17px; line-height:1; font-weight:400; letter-spacing:.18em;
  color:var(--muted); box-sizing:border-box; }
/* ⚠️ `justify-content:center` ET `line-height:1` EN PLUS d'`align-items` :
   sans line-height explicite, la boîte du texte hérite de celle du corps (1.5),
   et le centrage vertical porte alors sur une boîte plus haute que les lettres
   — le mot descend d'un à deux pixels. Un décalage qu'on ne sait pas nommer,
   mais qu'on voit. */
.entete-pub .sabonner { display:inline-flex; align-items:center;
  justify-content:center; height:36px; line-height:1;
  padding:0 16px; border:0; border-radius:999px; background:var(--brand);
  color:#fff; font:inherit; font-size:14px; font-weight:650;
  letter-spacing:-.01em; text-decoration:none; cursor:pointer; }
.auth-wrap.avec-entete { padding-top:84px; }
/* ✅ POSÉE DANS `views/auth/login.php` LE 21/08/2026. Cette bande avait été
   retenue tant que `/formules` n'existait pas : livrer un bouton qui répond 404
   est ce que le dépôt interdit (« un bouton mort et silencieux se prend pour un
   bug de l'application »). La page des formules est arrivée avec la vague du
   20/08 et répond 200 en production — la condition est levée, le balisage suit.
   ⚠️ Si `/formules` disparaissait un jour, c'est CE bouton qu'il faudrait
   retirer d'abord, pas la route. */

/* ⚠️ GESTINEO EST UNE APP MOBILE, ET L'ÉCRAN DE CONNEXION AUSSI (Paul, 21/08 :
   « je veux que le header soit sur une largeur mobile uniquement »). Sans cette
   largeur, la bande d'accueil s'étirait sur 1280 px pendant que le reste de
   l'app tenait dans 480 : la page de connexion était le seul écran du produit
   qui ne ressemblait pas au produit.
   ⚠️ ET C'EST `.auth-wrap` QU'ON BORNE, PAS UNE COQUILLE AJOUTÉE AUTOUR : la
   bande est en `position:absolute` et se cale sur le premier parent positionné
   — celui-ci. Emboîter une coquille de plus l'aurait laissée sur l'ancien
   repère, donc pleine largeur, sans que rien ne le dise. */
.auth-wrap { position:relative; min-height:100dvh; max-width:var(--app-large); margin:0 auto;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  padding:24px; background:#e3dff2; }
/* La carte respire : 26 px de padding pour un écran qui ne porte que trois
   éléments, c'était une boîte serrée autour d'un formulaire. 34 px en haut et
   en bas la posent comme une page, ce qu'elle est devenue. */
/* Le contour suit le même raisonnement : `--line` sur du blanc valait 1,19,
   soit un trait qu'on devine plus qu'on ne le voit. #c4bddd donne 1,80, et
   l'ombre passe de `--shadow` (2 % d'opacité, invisible sur un fond teinté) à
   une ombre portée franche — c'est elle qui pose la carte SUR la page au lieu
   de la laisser dedans. */
.auth-card { width:100%; max-width:380px; background:#fff; border:1px solid #c4bddd; border-radius:18px; box-shadow:0 10px 30px rgba(43,42,61,.10),0 2px 6px rgba(43,42,61,.06); padding:34px 26px; }
/* LA MARQUE, DEUX FOIS PLUS GRANDE (Paul, 19/08). Cette page est devenue
   l'accueil du site : le monogramme et le nom y sont la première chose lue, et
   la seule avant le formulaire. Le sous-titre a disparu — il décrivait deux
   champs et une flèche. */
/* ⚠️ L'ÉCART SOUS LA MARQUE VAUT LA HAUTEUR DE LA MARQUE (Paul, 19/08 :
   « un espace équivalent à la hauteur de Gestineo »). Le bloc mesure 55 px —
   c'est la taille du monogramme, plus haut que la ligne de texte. La marge est
   donc écrite `54px` et non `1em` ou `3rem` : elle suit une hauteur mesurée,
   pas une taille de police. Si le logo change de taille, les deux se règlent
   au même endroit, quelques lignes plus bas. */
.auth-card .brand { justify-content:center; font-size:38px; letter-spacing:-.03em; gap:12px; margin-bottom:55px; }
.auth-card .tagline { text-align:center; color:var(--muted); margin-bottom:20px; font-size:14px; }

/* ── Les deux champs et la flèche ──────────────────────────────────────
   Le libellé est DANS le champ, et l'action longe les deux sur toute leur
   hauteur. Trois règles seulement, parce qu'il n'y a que trois éléments.
   `align-items:stretch` (par défaut sur un flex) est ce qui donne au bouton
   la hauteur des deux champs plus leur écart : la fixer en pixels la
   désaccorderait au premier changement de `--tap`. */
.connexion { display:flex; gap:10px; }
.connexion .champs { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:10px; }
/* ⚠️ ET LE BORD DES CHAMPS AVEC, PARCE QUE CELUI-LÀ EST UNE RÈGLE, PAS UN
   GOÛT. Un contour de champ de saisie doit atteindre 3:1 (WCAG 1.4.11) : c'est
   lui qui dit OÙ l'on tape. `--line` donnait 1,19 — deux rectangles blancs sur
   du blanc, sans bord perceptible. #928cb2 donne 3,17.
   C'est la seule page où le réglage vaut d'être poussé : elle n'a que deux
   champs, tout le monde y passe, et personne n'y est encore connecté pour
   demander de l'aide. */
.connexion .champs input {
  width:100%; min-height:var(--tap); padding:11px 12px; border:1px solid #928cb2;
  border-radius:var(--radius-sm); font:inherit; color:var(--ink); background:#fff;
}
.connexion .champs input:focus { outline:2px solid var(--brand-ring); outline-offset:0; border-color:var(--brand); }
.connexion .entrer {
  flex:0 0 auto; width:56px; border:0; border-radius:var(--radius-sm);
  background:var(--brand); color:#fff; cursor:pointer;
  display:grid; place-items:center;
}
.connexion .entrer svg { width:26px; height:26px; }
.connexion .entrer:focus-visible { outline:2px solid var(--brand-ring); outline-offset:2px; }
/* Le lien de secours, juste sous le mot de passe : c'est là qu'on le cherche,
   pas en bas de carte. Discret — il ne concurrence pas la flèche d'entrée —
   mais aligné à droite, sous le champ qu'il secourt. */
/* ⚠️ À GAUCHE (Paul, 20/08). À droite, le lien se rangeait sous le bouton
   d'entrée et se lisait comme une suite de CE bouton — une variante de « se
   connecter ». À gauche, il s'aligne sur les champs de saisie, donc sur ce à
   quoi il se rapporte : le mot de passe qu'on vient de ne pas retrouver. */
.oubli { margin:7px 2px 0; text-align:left; font-size:12.5px; }
.oubli a { color:var(--muted); }

/* Séparateur « ou » : un trait que le mot interrompt, sans image ni pseudo-hack. */
/* Le « ou » sépare deux façons d'entrer : il lui faut l'air de séparer.
   16/12 px le collaient au champ du dessus. */
.auth-sep { display:flex; align-items:center; gap:10px; margin:28px 0 26px; color:var(--muted); font-size:13px; }
.auth-sep::before, .auth-sep::after { content:""; flex:1; height:1px; background:var(--line); }
/* Bouton Google : blanc à liseré, conformément aux règles d'usage de la marque. */
.btn-google { background:#fff; color:#3c4043; border-color:#dadce0; font-weight:600; }
.btn-google svg { width:18px; height:18px; }

/* États vides : un message + une action, jamais un cul-de-sac */
.empty { text-align:center; color:var(--muted); padding:24px 8px; }
.empty .ic { width:44px; height:44px; margin:0 auto 10px; border-radius:14px; display:grid; place-items:center; background:var(--brand-weak); color:var(--muted); }
.empty .ic svg { width:22px; height:22px; }
.empty p { margin:0 0 14px; font-size:14px; }
.empty .btn { display:inline-flex; width:auto; }

.mt0{margin-top:0}.mb0{margin-bottom:0}.muted{color:var(--muted)}.small{font-size:13px}
.right{text-align:right}.strong{font-weight:700}
.row-between{display:flex;align-items:center;justify-content:space-between;gap:10px}
.stack{display:flex;flex-direction:column;gap:8px}

/* ===== Épuration UX ===== */
/* Titre de section hors carte */
.section-h { font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.5px; color:var(--muted); margin:20px 2px 10px; }
.section-h:first-child { margin-top:4px; }

/* Tuiles d'accès (dashboard) */
.tiles { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.tile { display:flex; flex-direction:column; gap:9px; padding:14px; background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); color:var(--ink); transition:transform .08s ease; position:relative; }
.tile:active { transform:scale(.98); }
.tile .ic { width:40px; height:40px; border-radius:12px; display:grid; place-items:center; background:var(--brand-weak); color:var(--brand); }
.tile .ic svg { width:21px; height:21px; }
.tile .tl { font-weight:650; font-size:14px; letter-spacing:-.2px; }
.tile .ts { font-size:11.5px; color:var(--muted); line-height:1.35; }
/* Pastille de comptage sur une tuile (ex : 3 documents à signer) */
.tile .pastille { position:absolute; top:10px; right:10px; min-width:20px; height:20px; padding:0 6px; border-radius:999px; background:var(--danger); color:#fff; font-size:11px; font-weight:700; display:grid; place-items:center; }

/* Menu (page « Plus ») */
.menu { list-style:none; margin:0 0 14px; padding:0; background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); overflow:hidden; }
/* Un <form> n'est qu'un conteneur : c'est son <button> qui doit être la ligne cliquable. */
.menu li > form { display:contents; }
.menu li > a, .menu li > button, .menu li > form > button {
  display:flex; align-items:center; gap:13px; width:100%; padding:14px 16px; border:0;
  border-bottom:1px solid var(--line); background:none; color:var(--ink); font:inherit;
  text-align:left; cursor:pointer; min-height:var(--tap);
}
.menu li:last-child > a, .menu li:last-child > button, .menu li:last-child > form > button { border-bottom:none; }
.menu li > a:active, .menu li > button:active, .menu li > form > button:active { background:var(--bg); }
.menu .ic { width:34px; height:34px; border-radius:10px; display:grid; place-items:center; background:var(--brand-weak); color:var(--brand); flex-shrink:0; }
.menu .ic svg { width:18px; height:18px; }
.menu .mt { flex:1; font-weight:600; }
.menu .mt small { display:block; font-weight:500; color:var(--muted); font-size:12px; margin-top:1px; }
.menu .chev { color:var(--chev); font-size:20px; line-height:1; }

/* Boutons : état hover discret (desktop) */
@media (hover:hover){ .btn:hover{ filter:brightness(.98); } .tile:hover{ box-shadow:var(--shadow-lg); } }

/* ===== À faire (tableau de bord) ===== */
.todo { list-style:none; margin:0; padding:0; }
.todo li { display:flex; align-items:center; gap:11px; padding:11px 0; border-bottom:1px solid var(--line); }
.todo li:last-child { border-bottom:none; }
.todo .ic { width:32px; height:32px; border-radius:10px; display:grid; place-items:center; flex-shrink:0; }
.todo .ic svg { width:17px; height:17px; }
/* ⚠️ LES VARIANTES `-ink` EXISTENT POUR ÇA, ET CES DEUX RÈGLES NE S'EN
   SERVAIENT PAS. `--danger` et `--warn` sont les couleurs PLEINES — celles
   d'un fond de pastille, avec du blanc dessus. Posées comme ENCRE sur leur
   propre fond pâle, elles rendaient 3,12:1 : sous le seuil AA, et c'est
   l'icône qui dit à quel point une tâche presse. Les six autres règles du
   fichier (`.badge`, `.flash`, `.btn-danger`) emploient déjà `-ink` ;
   celles-ci étaient les deux exceptions. Mesuré le 24/08 — 5,06:1. */
.todo .ic.danger { background:var(--danger-bg); color:var(--danger-ink); }
.todo .ic.warn { background:var(--warn-bg); color:var(--warn-ink); }
.todo .ic.brand { background:var(--brand-weak); color:var(--brand); }
.todo .txt { flex:1; min-width:0; }
.todo .txt .t { font-weight:600; font-size:14px; }
.todo .txt .s { font-size:12.5px; color:var(--muted); }

/* ===== Éditeur de modèles ===== */
.editeur { font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace; font-size:12.5px; line-height:1.6;
  min-height:340px; tab-size:2; white-space:pre; overflow-wrap:normal; overflow-x:auto; }
.editeur-barre { display:flex; align-items:center; justify-content:space-between; gap:8px; font-size:12px; color:var(--muted); margin:-6px 0 8px; }

/* Palette de variables : puces insérables */
.palette { margin-bottom:14px; }
.palette > summary { cursor:pointer; font-size:13px; font-weight:600; color:var(--ink-soft); padding:6px 0; list-style:none; display:flex; align-items:center; gap:6px; }
.palette > summary::-webkit-details-marker { display:none; }
.palette > summary::before { content:'▸'; color:var(--muted); transition:transform .12s ease; display:inline-block; }
.palette[open] > summary::before { transform:rotate(90deg); }
.palette .groupe { margin-top:10px; }
.palette .groupe-nom { font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.4px; color:var(--muted); margin-bottom:5px; }
.chips { display:flex; flex-wrap:wrap; gap:6px; }
.chip {
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:11.5px;
  padding:5px 9px; border-radius:8px; border:1px solid var(--line); background:#fff;
  color:var(--ink-soft); cursor:pointer; white-space:nowrap;
}
.chip:active { background:var(--brand-weak); border-color:var(--brand); color:var(--brand); }
@media (hover:hover){ .chip:hover { border-color:var(--brand); color:var(--brand); } }

/* Aide syntaxe */
.syntaxe { font-size:12px; color:var(--muted); line-height:1.7; }
.syntaxe code { font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; background:var(--bg); padding:1px 5px; border-radius:5px; color:var(--ink-soft); }

/* Barre d'actions collée en bas du formulaire d'édition */
.form-actions { position:sticky; bottom:calc(60px + env(safe-area-inset-bottom)); z-index:10;
  display:flex; gap:8px; padding:10px; margin:14px -4px 0; background:rgba(248,247,252,.92);
  backdrop-filter:blur(6px); border-radius:14px; }
.form-actions > * { flex:1; margin:0; }

/* ===== Bascule entre les deux univers du propriétaire (Mon Immo / Patrimonia) ===== */
.univers {
  display:flex; gap:4px; padding:4px; margin:0 0 16px;
  background:var(--neutral-weak); border-radius:12px;
}
.univers a {
  flex:1; display:flex; align-items:center; justify-content:center; gap:7px;
  min-height:38px; border-radius:9px; font-size:13.5px; font-weight:650;
  color:var(--muted); background:transparent;
}
.univers a svg { width:16px; height:16px; }
.univers a.on { background:#fff; box-shadow:var(--shadow); }
.univers a.on.immo  { color:var(--brand-ink); }
.univers a.on.patri { color:var(--patri-ink); }

/* ===== Patrimonia : bilan ===== */
/* Bandeau de synthèse : actif, passif, et le net qui en découle. */
.bilan { background:var(--patri-weak); border:1px solid var(--line); border-radius:var(--radius); padding:16px; margin-bottom:14px; }
.bilan .net { font-size:28px; font-weight:750; letter-spacing:-.5px; color:var(--ink); }
.bilan .net-label { font-size:12px; text-transform:uppercase; letter-spacing:.3px; color:var(--muted); }
.bilan .repart { display:flex; gap:14px; margin-top:12px; }
.bilan .repart > div { flex:1; }
.bilan .repart .l { font-size:11.5px; color:var(--muted); text-transform:uppercase; letter-spacing:.3px; }
.bilan .repart .v { font-size:16px; font-weight:700; margin-top:1px; }
.bilan .repart .v.actif  { color:var(--ok); }
.bilan .repart .v.passif { color:var(--danger); }

/* Barre de répartition actif/passif : une lecture d'un coup d'œil. */
.jauge { display:flex; height:8px; border-radius:999px; overflow:hidden; background:#fff; margin-top:12px; }
.jauge span { display:block; height:100%; }

/* Section de bilan : en-tête + postes */
.psection { background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); margin-bottom:12px; overflow:hidden; }
.psection > summary { display:flex; align-items:center; gap:10px; padding:13px 14px; cursor:pointer; list-style:none; min-height:var(--tap); }
.psection > summary::-webkit-details-marker { display:none; }
.psection > summary::after { content:'▸'; color:var(--muted); margin-left:auto; transition:transform .12s ease; }
.psection[open] > summary::after { transform:rotate(90deg); }
.psection .pastille-couleur { width:10px; height:10px; border-radius:3px; flex-shrink:0; }
.psection .snom { font-weight:650; font-size:14.5px; }
.psection .stotal { font-weight:700; font-size:14.5px; margin-left:auto; }
.psection .corps { padding:0 14px 12px; border-top:1px solid var(--line); }

.poste { display:flex; align-items:center; gap:10px; padding:10px 0; border-bottom:1px solid var(--line); }
.poste:last-of-type { border-bottom:none; }
.poste .pl { flex:1; min-width:0; }
.poste .pl .t { font-weight:600; font-size:14px; }
.poste .pl .d { font-size:12px; color:var(--muted); }
.poste .pm { font-weight:650; font-size:14px; white-space:nowrap; }

/* Formulaire compact en ligne (ajout / édition d'un poste) */
.inline-form { display:flex; flex-wrap:wrap; gap:6px; padding:10px 0 2px; }
.inline-form input { flex:1; min-width:110px; min-height:38px; padding:8px 10px; border:1px solid var(--line); border-radius:9px; font:inherit; background:#fff; color:var(--ink); }
.inline-form input.montant { max-width:110px; text-align:right; }
.inline-form button { min-height:38px; padding:8px 14px; }

/* ===== Graphique de suivi (SVG servi par le serveur, sans dépendance) ===== */
.chart { background:var(--card); border:1px solid var(--line); border-radius:var(--radius); box-shadow:var(--shadow); padding:14px; margin-bottom:14px; }
.chart svg { width:100%; height:auto; display:block; }
.chart .legende { display:flex; flex-wrap:wrap; gap:10px; margin-top:10px; font-size:12px; color:var(--muted); }
.chart .legende span { display:inline-flex; align-items:center; gap:5px; }
.chart .legende i { width:9px; height:9px; border-radius:3px; display:inline-block; }
.chart-vide { text-align:center; color:var(--muted); font-size:13px; padding:26px 8px; }

/* Sélecteur de série : puces horizontales défilables */
.series { display:flex; gap:6px; overflow-x:auto; padding-bottom:4px; margin-bottom:12px; -webkit-overflow-scrolling:touch; }
.series a {
  flex-shrink:0; padding:7px 12px; border-radius:999px; border:1px solid var(--line);
  background:#fff; color:var(--ink-soft); font-size:12.5px; font-weight:600; white-space:nowrap;
}
.series a.on { background:var(--patri-weak); border-color:var(--patri); color:var(--patri-ink); }
/* Le même sélecteur, côté Immobilia : seul l'accent change. La règle est posée en
   VARIANTE plutôt qu'en remplacement — l'évolution du patrimoine s'en sert déjà
   avec l'accent patri, et deux écrans ne doivent pas se disputer une classe. */
.series.immo a.on { background:var(--brand-weak); border-color:var(--brand); color:var(--brand-ink); }

/* ===== Historique locatif (frise des baux d'un bien) ===== */
.frise { list-style:none; margin:0; padding:0 0 0 20px; position:relative; }
.frise::before { content:''; position:absolute; left:5px; top:6px; bottom:6px; width:2px; background:var(--line); border-radius:1px; }
.frise > li { position:relative; padding:0 0 16px; }
.frise > li:last-child { padding-bottom:0; }
.frise > li::before {
  content:''; position:absolute; left:-19px; top:5px; width:12px; height:12px;
  border-radius:50%; background:#fff; border:2px solid var(--chev);
}
.frise > li.en-cours::before { border-color:var(--ok); background:var(--ok-bg); }
.frise .periode { font-size:12px; color:var(--muted); font-weight:600; }
.frise .qui { font-weight:650; font-size:14.5px; margin:1px 0 2px; }
.frise .cond { font-size:13px; color:var(--ink-soft); }
.frise .note { font-size:12px; color:var(--muted); margin-top:3px; }
.frise .liens { display:flex; flex-wrap:wrap; gap:6px; margin-top:7px; }

/* Connexion depuis la barre du haut. Une seule adresse sert désormais la vitrine
   publique et les espaces : le visiteur non connecté doit toujours voir sa porte. */
/* ⚠️ LE MÊME BOUTON QUE SUR LA LANDING (Paul, 22/08 : « dans la page des
   formules, je veux le même bouton pour se connecter que sur la landing page »).
   Il était en `--accent`, c'est-à-dire ORANGE : la seule touche de cette teinte
   des deux pages publiques, sur le geste qu'on répète le plus. Deux écrans qui
   se suivent et dont le même bouton change de couleur ET de taille donnent
   l'impression d'avoir changé de site - c'est le défaut qu'on vient de corriger
   sur la barre, et il vivait aussi ici.
   Ces valeurs sont celles de `.v-btn.creux` de vitrine.css, à la lettre. */
.btn-connexion{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;padding:0 16px;border-radius:11px;
  background:var(--card);color:var(--ink-soft);border:1px solid var(--line);
  font-size:12.5px;font-weight:650;text-decoration:none;white-space:nowrap;
}
.btn-connexion:hover{border-color:var(--brand);color:var(--brand)}
.btn-connexion:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* --- LES CRÉNEAUX DE VISITE (Paul, 19/08) ---
   Promu de l'établi avec l'écran : une vue qui part en code emporte son CSS,
   ou elle ne part pas — la messagerie était partie sans le sien le 18/08, et
   ses deux bulles sortaient identiques.

   ⚠️ `.jour-plage` et NON `.jour` : ce nom est déjà pris deux fois ailleurs —
   l'intertitre collant de l'agenda des visites dans `module.css`, et le fil de
   messagerie qui s'est fait renommer `.jour-fil` pour cette raison. Trois
   écrans sans rapport, un même mot : c'est le nom qui cède. */
.jour-plage{
  margin:14px 0 4px; font-size:11px; font-weight:700; letter-spacing:.04em;
  text-transform:uppercase; color:var(--muted);
}
.jour-plage:first-of-type{margin-top:4px}

/* La LIGNE d'un créneau. ⚠️ Elle manquait, et l'en-tête six lignes plus haut
   dit pourtant « une vue qui part en code emporte son CSS, ou elle ne part
   pas » : `.jour-plage` est bien partie, `.ligne`, `.carte-h`, `.vide` et
   `.go` sont restées derrière, dans `module.css`. Mesuré le 25/08 : sans
   `display:flex`, le bouton « Retirer » tombait SOUS l'heure — un créneau par
   ligne devenait deux, et l'écran doublait de hauteur.
   ⚠️ `.creneau` et NON `.ligne` : `.ligne-form` occupe déjà le préfixe dans
   cette feuille, et `.ligne` nue est le mot du MODULE. Nom vérifié libre dans
   les deux feuilles ET dans l'établi avant d'être posé — c'est ce qui avait
   manqué à `.jour`, pris trois fois. */
.creneau{
  display:flex; align-items:center; gap:10px;
  padding:9px 0; border-top:1px solid var(--line);
}
.creneau:first-of-type{border-top:0}
.creneau .txt{flex:1 1 auto; min-width:0}
.creneau .t{display:block; font-size:14px; font-weight:600; font-variant-numeric:tabular-nums}
.creneau .s{display:block; font-size:12.5px; color:var(--muted); margin-top:1px}
.creneau form{flex:0 0 auto}

/* Le récapitulatif de découpe : ce que la plage va RÉELLEMENT produire.
   Mis en avant parce que c'est la seule information que le propriétaire ne
   peut pas déduire lui-même sans compter. Rempli par app.js ; le contenu
   de repli, écrit dans la vue, reste juste sans JavaScript. */
.decoupe{
  background:var(--brand-weak); border-radius:12px; padding:10px 12px; margin:4px 0 12px;
}
.decoupe b{display:block; font-size:14px; color:var(--brand-ink); margin-bottom:2px}
.decoupe span{font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums}

/* ═══ LE « i » QUI PORTE L'EXPLICATION — jumeau de celui de module.css ═══
   Paul, 20/08 : les phrases grises se replient dans un « i » posé sur leur
   titre. La règle existe dans `module.css` ; elle est reprise ICI parce que les
   pages publiques (connexion, /formules, annonce, vitrine) tournent sur
   `app.css` — et une vue qui part sans sa règle sort sans style, en silence.
   C'est le défaut qui a récidivé dix fois sur ce dépôt.

   Les valeurs sont les mêmes ; seuls les jetons changent de nom d'une feuille
   à l'autre (--acc → --brand, --l2 → --line, --faint → --muted, --i → --ink).
   `<details>` et non un script : la CSP du site est `script-src 'self'`. */
.info{position:static;flex:0 0 auto;margin-right:auto;display:inline-block}
.info>summary{list-style:none;width:14px;height:14px;border-radius:50%;
  border:1px solid var(--line);background:var(--card);color:var(--muted);
  font-size:11px;font-weight:800;font-style:italic;line-height:1;
  display:grid;place-items:center;cursor:pointer;user-select:none}
.info>summary::-webkit-details-marker{display:none}
/* ⚠️ LE « i » EST UNE PASTILLE DE 14 px — DONC UNE CIBLE DE 14 px, LE TIERS DU
   MINIMUM TACTILE. Mesuré le 23/08 dans un navigateur : toutes les occurrences,
   sur les deux feuilles. Et ce n'est pas un détail d'accessibilité : depuis que
   l'aide vit derrière le « i » plutôt qu'en gris sous le titre (Paul, 20/08),
   c'est LE geste par lequel on obtient l'explication. Une aide qu'on n'arrive
   pas à toucher n'est pas une aide.
   Le disque reste à 14 px — il doit rester discret ; c'est la ZONE SENSIBLE qui
   passe à 44, par un pseudo-élément invisible. Agrandir le disque aurait fait
   du « i » un bouton, et un bouton à côté de chaque titre reprend l'écran. */
.info>summary{position:relative}
.info>summary::after{content:'';position:absolute;top:50%;left:50%;
  width:var(--tap);height:var(--tap);transform:translate(-50%,-50%)}
.info[open]>summary{background:var(--brand);border-color:var(--brand);color:#fff}
.info>p{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:6;
  margin:0;padding:8px 10px;border-radius:10px;background:var(--ink);color:#fff;
  font-size:11px;line-height:1.5;box-shadow:0 8px 22px rgba(43,42,61,.26);
  text-align:left;font-weight:400}
.info>p b{color:#fff;font-weight:700}

/* ═══ LA VITRINE D'UN BAILLEUR — /p/{jeton} ═══════════════════════════
   Paul, 20/08 : « oui, fais la vitrine par jeton /p/{jeton} ».

   Elle n'est référencée nulle part : elle n'existe que par le lien que le
   bailleur envoie. Elle montre TOUT son parc locatif — un logement loué reste
   visible, ses photos et sa description lui appartiennent (15/08) — et ne
   propose de candidater que là où une annonce est en ligne.

   ⚠️ AUCUN NOM SUR CETTE PAGE, ET AUCUN DANS SON ADRESSE. Le bandeau dit
   « bailleur particulier » et les villes : de quoi savoir qu'on traite avec un
   particulier et non une agence, sans désigner personne.

   Ces règles viennent de la constante SUP_VITRINE de l'établi, où l'écran a été
   arbitré. Elles la quittent EN MÊME TEMPS que le balisage part en PHP : une
   vue qui part sans sa règle sort sans style, en silence — dix fois sur ce
   dépôt, et jamais vu autrement qu'en mesurant. */
.bandeau{display:flex;align-items:center;gap:12px;padding:12px 0 10px}
.bandeau .rond{width:44px;height:44px;border-radius:14px;background:var(--brand-weak);
  color:var(--brand-ink);display:grid;place-items:center;font-weight:700;font-size:16px;flex:0 0 auto}
/* Le rond portait deux initiales ; il porte une maison depuis le 18/08, et un
   SVG sans dimension prend la place qu'il trouve — ici 21 px de plus que le
   rond qui le contient, donc le débordement de la page entière. */
.bandeau .rond svg{width:21px;height:21px}
.bandeau b{display:block;font-size:16.5px;letter-spacing:-.01em}
.bandeau span{display:block;font-size:12px;color:var(--muted)}
.lot{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:10px;margin-bottom:9px;display:flex;gap:10px;flex-wrap:wrap}
/* Le pied de mentions prend TOUTE la largeur, sous la vignette et le texte.
   `flex-wrap` ne change rien à la ligne existante — `.vue` est fixe à 92 px et
   `.txt` a `min-width:0`, donc les deux ne peuvent pas se renvoyer à la ligne
   d'eux-mêmes ; seul un enfant à `flex-basis:100%` descend. Mesuré. */
.lot .mentions{flex:0 0 100%;margin:9px 0 0;padding-top:9px}
.lot .vue{flex:0 0 92px;height:78px;border-radius:10px;
  background:linear-gradient(135deg,#dfe3ec,#c9d0de);display:grid;place-items:center;
  /* ⚠️ 2,4:1 SUR SON PROPRE DÉGRADÉ. Ce cartouche porte un MOT quand la photo
     manque : c'est donc du texte, et il se lisait à peine. Mesuré sur le stop
     le plus clair du dégradé, #dfe3ec — le pire cas. 4,73:1 désormais. */
  color:#585f75;font-size:11px;text-align:center;overflow:hidden}
.lot .vue img{width:100%;height:100%;object-fit:cover;display:block}
.lot .txt{flex:1;min-width:0;display:flex;flex-direction:column}
.lot .n{font-size:13.5px;font-weight:700;line-height:1.25;letter-spacing:-.01em}
.lot .d{font-size:11.5px;color:var(--muted);margin-top:1px}
.lot .p{font-size:12.5px;font-weight:700;margin-top:2px}
.lot .p em{font-style:normal;font-weight:600;color:var(--muted)}
/* Les deux gestes côte à côte : visiter d'abord, candidater ensuite. Le second
   disparaît quand aucune annonce n'est en ligne — pas grisé : ABSENT, pour ne
   pas faire espérer. */
.gestes{display:flex;gap:6px;margin-top:auto;padding-top:7px}
.gestes a{flex:1;text-align:center;font-size:11.5px;font-weight:700;padding:6px 8px;
  border-radius:9px;border:1px solid var(--line);color:var(--ink-soft);background:var(--bg)}
.gestes a.fort{background:var(--brand);border-color:var(--brand);color:#fff}
.apercu{display:flex;align-items:center;gap:9px;background:var(--warn-bg);color:var(--warn-ink);
  border-radius:12px;padding:9px 12px;font-size:12px;margin-bottom:10px}
.apercu svg{width:17px;height:17px;flex-shrink:0}
.lien{background:var(--neutral-weak);border-radius:12px;padding:10px 12px;margin-top:4px}
.lien b{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.3px;
  color:var(--muted);margin-bottom:3px}
.lien code{font-size:12.5px;font-weight:600;color:var(--ink);word-break:break-all}

/* ─── Les mentions obligatoires de l'annonce ────────────────────────────────
   Tout en bas et discrètes (Paul, 21/08) — SAUF les deux étiquettes.
   CCH R126-22 exige les classements « de manière lisible et en couleur » ; il
   n'impose AUCUNE position. C'est ce qui permet de descendre le bloc, et c'est
   aussi ce qui interdit de teindre ces deux-là en gris 11 px comme le reste.
   Les couleurs sont celles de l'étiquette officielle (arrêté DPE) ; le ton du
   texte change avec la classe parce que du blanc sur le jaune D ne se lit pas. */
.mentions { margin:18px 0 4px; padding-top:12px; border-top:1px solid var(--line); }
.mentions h2 {
  font-size:11px; font-weight:800; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); margin:0 0 8px;
}
.mentions p { font-size:11px; line-height:1.5; color:var(--muted); margin:0 0 5px; }
.mentions p:last-child { margin-bottom:0; }

.mentions .etiquettes { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:9px; }
.mentions .etq {
  display:inline-flex; align-items:center; gap:6px;
  padding:3px 9px 3px 8px; border-radius:7px;
  font-size:11px; font-weight:700; letter-spacing:.02em;
  background:var(--c); color:var(--t);
}
.mentions .etq b {
  display:inline-grid; place-items:center; min-width:16px; height:16px;
  padding:0 3px; border-radius:4px; font-size:11px; font-weight:800;
  background:rgba(255,255,255,.55); color:inherit;
}
/* Énergie — l'échelle officielle du DPE. Trois teintes (A, G, et F du climat)
   sont assombries d'un cran par rapport à l'arrêté : MESURÉ dans un navigateur,
   le blanc sur l'original tombait à 3,62 / 4,08 / 4,08 pour 1, sous le seuil AA
   à 11 px. Or R126-22 exige « lisible ET en couleur » : la couleur qui ne se lit
   pas ne satisfait ni l'un ni l'autre. Les valeurs retenues rendent 4,80 / 4,80
   / 4,73 — le plus petit écart qui passe. */
.mentions .dpe-a { --c:#2a832a; --t:#ffffff; }
.mentions .dpe-b { --c:#52c41a; --t:#173d05; }
.mentions .dpe-c { --c:#cbfc34; --t:#33430a; }
.mentions .dpe-d { --c:#fbfe06; --t:#4a4a05; }
.mentions .dpe-e { --c:#fbcc05; --t:#4a3b02; }
.mentions .dpe-f { --c:#fc9935; --t:#5a2f04; }
.mentions .dpe-g { --c:#e60205; --t:#ffffff; }
/* Climat — l'échelle GES, violette. */
.mentions .ges-a { --c:#ebeaf7; --t:#3b2a72; }
.mentions .ges-b { --c:#d7d3ef; --t:#3b2a72; }
.mentions .ges-c { --c:#c2bbe6; --t:#33246a; }
.mentions .ges-d { --c:#aca3dd; --t:#2b1d5c; }
.mentions .ges-e { --c:#968ad4; --t:#231650; }
.mentions .ges-f { --c:#7566c2; --t:#ffffff; }
.mentions .ges-g { --c:#6a58c2; --t:#ffffff; }
/* Classe absente : neutre, et le tiret le dit — jamais une couleur inventée,
   qui ferait croire à un classement qu'aucun diagnostic n'a établi. */
.mentions .dpe-na, .mentions .ges-na { --c:var(--neutral-weak); --t:var(--ink-soft); }

/* ─── « Comment le prix se calcule » — replié, en pied de grille ──────────────
   Un `<details>` natif et non un script : la CSP du site est `script-src 'self'`
   sans nonce, un repli en JavaScript n'y fonctionnerait pas. Même famille que
   `.psection` et `.info`, déjà dans cette feuille. */
.calcul { background:var(--card); border:1px solid var(--line); border-radius:var(--radius);
  margin-top:16px; overflow:hidden; }
.calcul > summary {
  display:flex; align-items:center; gap:10px; padding:13px 15px;
  cursor:pointer; list-style:none; min-height:var(--tap);
  font-size:14px; font-weight:700; letter-spacing:-.01em; color:var(--ink);
}
.calcul > summary::-webkit-details-marker { display:none; }
/* Le chevron à DROITE : c'est le bord qu'on suit quand on parcourt une liste
   d'entrées repliables, et `.psection` fait déjà ce choix dans cette feuille. */
.calcul > summary::after { content:'▸'; color:var(--muted); margin-left:auto;
  transition:transform .12s ease; }
.calcul[open] > summary::after { transform:rotate(90deg); }
.calcul > p { font-size:12.5px; line-height:1.55; color:var(--ink-soft);
  margin:0; padding:0 15px 12px; }
.calcul > p:first-of-type { padding-top:2px; }
.calcul > p b { color:var(--ink); font-weight:700; }
@media (prefers-reduced-motion:reduce) { .calcul > summary::after { transition:none; } }

/* ─── Choisir une formule : le bouton n'apparaît qu'au clic ───────────────────
   Paul, 21/08 : « les boutons s'abonner ne doivent apparaître que lorsqu'on
   clique sur le rectangle de l'abonnement ». Quatre appels à l'action allumés
   sur un écran où l'on n'a rien décidé, c'était quatre recommandations qui se
   contredisaient.
   ⚠️ SANS SCRIPT : la CSP du site est `script-src 'self'` sans nonce. Un radio
   caché porte l'état et le focus clavier, un label couvre la carte, `:has()`
   allume le bouton. C'est le même mécanisme que l'établi avait retenu. */
.offre { position:relative; }
.offre .choix { position:absolute; width:1px; height:1px; opacity:0;
  margin:0; pointer-events:none; }
/* Le label couvre la carte ENTIÈRE — « le rectangle », au mot près. */
/* ⚠️ LE LABEL PASSE AU-DESSUS, ET C'ÉTAIT TOUT LE DÉFAUT (Paul, 21/08 :
   « la main ne s'affiche qu'à un petit endroit du rectangle »). Il était en
   `z-index:0` pendant que TOUT le contenu passait en `z-index:1` : on ne
   pouvait cliquer que dans les interstices entre deux éléments — quelques
   bandes de deux pixels. Le curseur main n'y paraissait donc presque jamais,
   et la carte semblait morte.
   Le label couvre maintenant la carte entière. Le texte n'est plus
   sélectionnable — c'est le prix à payer, et il est juste : sur une carte de
   prix, on clique, on ne copie pas. */
.offre .zone { position:absolute; inset:0; border-radius:13px; cursor:pointer; z-index:2; }
/* Le contenu passe AU-DESSUS du label : sans ça, le bouton serait couvert par
   lui et le premier clic sur « S'abonner » ne ferait que cocher la carte. */
/* ⚠️ LE BOUTON EST EXCLU ICI, PAS RATTRAPÉ PLUS BAS — et la nuance a coûté
   un bouton mort en production. Première version : une règle `.offre .go-offre`
   posée après, avec `pointer-events:auto`. Elle PERDAIT la cascade — `.offre >
   *:not(.zone):not(.choix)` pèse trois classes, `.offre .go-offre` deux — et
   « S'abonner » restait intraversable : on cliquait, la formule se cochait, et
   rien d'autre. Sur le seul élément de la page qui doit marcher.
   L'exclusion dans le `:not()` ne se contredit pas : elle ne peut pas être
   perdue par une règle écrite ailleurs. */
.offre > *:not(.zone):not(.choix):not(.go-offre) { position:relative; z-index:1; pointer-events:none; }
/* ⚠️ MAIS LE BOUTON RESTE CLIQUABLE, au-dessus du label. Sans cette ligne,
   « S'abonner » serait recouvert par la zone de sélection : le clic
   cocherait la formule au lieu de suivre le lien, et le bouton paraîtrait
   cassé — sur le seul élément de la page qui doit marcher. */
.offre > .go-offre { position:relative; z-index:3; }
.offre .go-offre { display:none; }
.offre:has(.choix:checked) .go-offre { display:block; }
/* La carte choisie se voit, sinon le bouton paraît sans cause. */
.offre:has(.choix:checked) { border-color:var(--brand); box-shadow:0 0 0 1px var(--brand); }
/* Le focus clavier vit sur le radio, donc il faut le rendre visible sur la CARTE. */
.offre:has(.choix:focus-visible) { outline:2px solid var(--brand); outline-offset:2px; }
.sr-seulement { position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }

/* ═══ LE CHOIX DE LA CASQUETTE — une adresse, plusieurs espaces (lot L7) ═══
   Paul, 21/08 : « quelle vue de compte il souhaite […] Si la personne n'a
   qu'une vue possible, n'affiche pas l'overlay concerné ».

   ⚠️ LA CLASSE NE S'APPELLE PAS `.vue`. Ce nom-là est déjà pris par la vignette
   photo d'un lot (`.lot .vue`, 92x78, object-fit:cover). Deux sens pour un mot
   dans la même feuille, c'est l'agenda des visites qui change d'allure le jour
   où quelqu'un touche à l'autre. */
.choix-titre { font-size:20px; line-height:1.25; text-align:center; margin:0 0 6px;
               letter-spacing:-.01em; color:var(--ink); }
.choix-sous  { font-size:13px; line-height:1.45; text-align:center; color:var(--muted);
               margin:0 0 18px; }

.casquettes { display:flex; flex-direction:column; gap:9px; }

/* ⚠️ C'EST UN <button>, DONC IL FAUT TOUT REPRENDRE. Un bouton hérite de la
   police du navigateur, pas de la page : sans `font:inherit` il sort en
   13px system-ui au milieu d'une carte qui est en Inter, et l'écart se voit. */
.casquette { font:inherit; text-align:left; cursor:pointer; width:100%;
             display:flex; flex-direction:column; gap:2px;
             min-height:var(--tap); padding:12px 14px;
             background:var(--card); color:var(--ink);
             border:1px solid var(--line); border-radius:var(--radius-sm);
             transition:border-color .12s, background .12s, box-shadow .12s; }
.casquette:hover  { border-color:var(--brand); background:var(--brand-weak); }
.casquette:focus-visible { outline:2px solid var(--brand); outline-offset:2px; }
.casquette-nom  { font-weight:650; font-size:15px; line-height:1.3; }
.casquette-quoi { font-size:12.5px; line-height:1.4; color:var(--muted); }

/* La vue d'où l'on vient reste désignée : revenir sur cet écran sans savoir
   où l'on était oblige à re-choisir au hasard. */
.casquette-active { border-color:var(--brand); background:var(--brand-weak); }
.casquette-active .casquette-nom { color:var(--brand-ink); }

.choix-sortie { text-align:center; margin:16px 0 0; font-size:13px; }
.choix-sortie a { color:var(--muted); }

/* ═══ L'ÉCRAN DES PROPRIÉTAIRES, CÔTÉ GESTIONNAIRE (lot L5) ══════════════ */

/* Une action secondaire qui ne doit pas peser autant qu'un bouton plein :
   « Détacher », « Refermer l'accès ». C'est un <button>, donc tout est à
   remettre — un bouton n'hérite ni de la police ni de la couleur de la page. */
.btn-lien{font:inherit;font-size:12.5px;background:none;border:0;padding:2px 0;
  color:var(--muted);text-decoration:underline;text-underline-offset:2px;cursor:pointer}
.btn-lien:hover{color:var(--danger-ink)}
.btn-lien:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:3px}

.liens-biens{list-style:none;margin:8px 0;padding:0}
.liens-biens li{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:7px 0;border-bottom:1px solid var(--line)}
.liens-biens li:last-child{border-bottom:none}
.lb-bien{flex:1 1 140px;font-size:13.5px;font-weight:600;color:var(--ink)}
.lb-part{font-size:12.5px;font-weight:700;color:var(--ink-soft);
  font-variant-numeric:tabular-nums}
.lb-titre{font-size:11px;font-weight:600;color:var(--muted);
  background:var(--neutral-weak);padding:2px 7px;border-radius:999px}
.lb-detacher{margin:0}

/* Une ligne de formulaire : les champs côte à côte, et ils passent à la ligne
   plutôt que de déborder — la page est en largeur mobile. */
.ligne-form{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin:10px 0 0}
.ligne-form select,.ligne-form input{flex:1 1 130px;min-width:0}
.ligne-form input[type="number"]{flex:0 0 88px}
.ligne-form .btn{flex:0 0 auto}

/* ═══ MES FACTURES (lot L14) ═══════════════════════════════════════════════ */
.facture{padding:12px 14px}
.fa-tete{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.fa-tete b{font-size:14.5px;font-weight:700;color:var(--ink);text-transform:capitalize}
.fa-montant{font-size:16px;font-weight:750;color:var(--ink);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em}

/* ⚠️ CETTE LIGNE EST LA JUSTIFICATION DU MONTANT, pas une légende. C'est elle
   qu'on relit quand on ne comprend pas sa facture — elle doit rester lisible,
   donc pas de gris pâle : var(--ink-soft) et non var(--muted). */
.fa-quoi{margin:5px 0 0;font-size:12.5px;line-height:1.45;color:var(--ink-soft)}
.fa-etat{margin:8px 0 0;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.fa-badge{font-size:11px;font-weight:700;letter-spacing:.02em;text-transform:uppercase;
  padding:3px 8px;border-radius:999px}
.fa-due{background:var(--warn-bg);color:var(--warn-ink)}
.fa-payee{background:var(--ok-bg);color:var(--ok-ink)}
.fa-echouee{background:var(--danger-bg);color:var(--danger-ink)}
.fa-annulee{background:var(--neutral-weak);color:var(--muted)}

/* Les mentions légales : discrètes mais PRÉSENTES. La 293 B est une obligation,
   pas une note de bas de page — d'où le fond neutre plutôt que rien du tout. */
.mentions-facture{background:var(--neutral-weak);border:1px solid var(--line)}
.mentions-facture p{margin:0 0 6px}
.mentions-facture p:last-child{margin-bottom:0}

/* ═══ /formules — le minimum annuel et les exemples (Paul, 21/08) ═════════ */

/* ⚠️ LE MINIMUM ANNUEL SOUS LE TAUX. Il ne paraissait pas jusqu'ici, et le
   motif a changé avec la grille : ce qui était « de la mécanique
   d'encaissement » quand le socle était MENSUEL devient un vrai prix quand
   l'abonnement est ANNUEL. Discret, mais lisible — c'est un prix, pas une note. */
.offre .prix .mini{display:block;font-size:11px;font-weight:600;color:var(--muted);
  margin-top:3px;letter-spacing:0;line-height:1.3}

/* Les exemples chiffrés : deux colonnes, la somme à droite. */


/* ⚠️ LE LOGO EST UN <a> DEPUIS LE 21/08 : sans ces deux lignes il sortirait
   souligné et en bleu de lien, sur toutes les pages du site. */
a.brand{text-decoration:none;color:inherit}
a.brand:hover .sub{color:var(--brand)}

/* ═══ LA LANDING PAGE — en-tête, KPI, vidéo, le cap (Paul, 21/08) ════════ */

/* L'en-tête : la marque à gauche, deux boutons à droite. */
/* ═══ LA BARRE DE CONNEXION DEVIENT CELLE DES DEUX AUTRES ══════════════════
   Paul, 22/08 : « le header dans la page de connexion n'est pas le même. Peux-tu
   harmoniser tous les headers et conserver celui de la landing page et des
   formules ? »

   Mesuré côte à côte, elle divergeait sur SIX points d'un coup - 60 px de haut
   contre 67, `position:absolute` contre `sticky`, rembourrage 0/14 contre 11/20,
   logo 26 contre 28, marque 14 px contre 17, bouton 40 px et rayon 10 contre 44
   et 11. Aucun de ces écarts n'est visible seul ; ensemble ils font une autre
   barre, et c'est ce qu'on voit en passant d'une page à l'autre.

   ⚠️ ELLE PASSE DANS LE FLUX. Elle était en `position:absolute`, et
   `.auth-wrap.avec-entete` lui réservait 84 px de rembourrage haut : sortie du
   flux, elle ne poussait rien, il fallait lui creuser sa place à la main. Deux
   nombres à accorder de plus - exactement le couplage qui avait fait passer le
   titre sur le logo dans le héros. En `sticky`, elle occupe sa place et le
   rembourrage disparaît. */
.entete-pub{
  position:sticky; top:0; left:auto; right:auto; height:auto;
  justify-content:space-between; padding:11px 20px;
  border-bottom:1px solid var(--line);
}
.auth-wrap.avec-entete{ padding-top:0; }

/* ⚠️ LA BANDE ÉTAIT DESCENDUE AU MILIEU DE L'ÉCRAN, à 189 px du haut (Paul,
   22/08 : « la page de connexion n'a plus le header fonctionnel »). Personne ne
   l'avait déplacée : c'est le passage de `absolute` à `sticky`, juste au-dessus,
   qui l'a mise DANS LE FLUX - et le flux ici est une colonne flex en
   `justify-content:center`, qui centre TOUT ce qu'elle contient. Hors du flux,
   la bande ignorait ce centrage ; dans le flux, elle le subit.

   ⚠️ ET `position:sticky` N'Y POUVAIT RIEN. Un élément collant se colle au bord
   de son conteneur de défilement UNE FOIS QU'IL Y ARRIVE : il ne remonte pas de
   lui-même à la place que la mise en page ne lui a pas donnée. On lit `sticky`
   comme « il reste en haut », alors qu'il dit « il ne descend pas plus bas que
   le haut quand on défile ». La nuance est exactement ce qui manquait ici.

   La bande reprend donc le haut, et c'est la CARTE qui est centrée dans ce qui
   reste (`margin-block:auto`) - ce que le centrage du parent faisait jusqu'ici
   pour les deux à la fois. `align-self:stretch` lui rend la pleine largeur, que
   le `align-items:center` du parent lui retirait. */
.auth-wrap.avec-entete{ justify-content:flex-start; }
/* ⚠️ ET ELLE REPREND LA PLEINE LARGEUR. `.auth-wrap` porte 24 px de
   rembourrage pour la carte ; la bande s'y trouvait rentrée de 24 px de chaque
   côté, soit 338 px de blanc sur 386 - un bandeau qui ne touche pas les bords
   ne se lit plus comme une barre, il se lit comme un encadré. Les marges
   négatives annulent le rembourrage du parent pour ELLE SEULE : la carte garde
   le sien, et on n'a pas eu à déplacer le rembourrage sur chaque enfant.
   (Paul, 21/08 : « garde le bandeau blanc sur toute la longueur ».) */
.auth-wrap.avec-entete > .entete-pub{ align-self:stretch; margin-inline:-24px; }
.auth-wrap.avec-entete > .auth-card{ margin-block:auto; }
.marque-pub { display:flex; align-items:center; gap:9px; text-decoration:none;
  color:var(--ink); font-weight:700; font-size:clamp(13px,3.6vw,17px);
  letter-spacing:normal; white-space:nowrap; }
.marque-pub .logo { width:28px; height:28px; color:var(--brand); flex-shrink:0; }
.actions-pub { display:flex; align-items:center; gap:7px; }

/* ⚠️ DEUX COULEURS, ET LA HIÉRARCHIE EST DÉLIBÉRÉE : le plein appelle, le creux
   attend. Deux boutons pleins côte à côte ne disent pas lequel est le geste
   principal — et celui qui hésite clique au hasard. */
.btn-pub { display:inline-flex; align-items:center; justify-content:center;
  /* ⚠️ 32 px ÉTAIT LE PLUS PETIT DE TOUT LE SITE, sur la barre d'une page
     publique — la première que voit un visiteur. `--tap:44px` est la règle du
     dépôt ; 40 px est le compromis retenu ici parce que cette barre est mince
     par nature et qu'un enfant plus haut lui volerait des pixels de contenu
     (le corps est en overflow:hidden). Mesuré après coup : la barre ne grandit
     pas. */
  min-height:44px; padding:0 16px; border-radius:11px; font-size:12.5px;
  font-weight:700; text-decoration:none; white-space:nowrap;
  transition:background .13s, color .13s, border-color .13s; }
.btn-pub.plein { background:var(--brand); color:#fff; border:1px solid var(--brand); }
.btn-pub.plein:hover { background:var(--brand-dark); border-color:var(--brand-dark); }
.btn-pub.creux { background:transparent; color:var(--brand-ink); border:1px solid #c4bddd; }
.btn-pub.creux:hover { background:var(--brand-weak); border-color:var(--brand); }

/* Les quatre chiffres. Deux colonnes : à une seule, la page devient une liste
   qu'on fait défiler ; à quatre, chaque chiffre devient illisible en mobile. */
.kpis { display:grid; grid-template-columns:1fr 1fr; gap:9px; width:100%;
  max-width:380px; margin:22px auto 0; }
.kpi { background:var(--card); border:1px solid #c4bddd; border-radius:13px;
  padding:13px 12px; text-align:center; }
.kpi b { display:block; font-size:26px; font-weight:800; letter-spacing:-.03em;
  color:var(--brand-ink); line-height:1.05; font-variant-numeric:tabular-nums; }
.kpi span { display:block; font-size:11px; line-height:1.4; color:var(--ink-soft);
  margin-top:5px; }

/* La vidéo et le cap. */
.presentation { width:100%; max-width:380px; margin:20px auto 0; }
.video-pres { width:100%; display:block; border-radius:13px; background:#000;
  border:1px solid #c4bddd; }

/* ⚠️ L'ATTENTE SE DIT, elle ne se montre pas en cadre noir : un lecteur qui ne
   lit rien passe pour une panne, sur la première page que voit un visiteur. */
.video-attente { display:flex; flex-direction:column; justify-content:center;
  align-items:center; gap:5px; aspect-ratio:16/9; border-radius:13px;
  background:var(--brand-weak); border:1px dashed #b7ace0; text-align:center;
  padding:16px; }
.va-titre { font-size:13.5px; font-weight:700; color:var(--brand-ink); }
.va-note  { font-size:11.5px; color:var(--muted); line-height:1.4; }

.cap { margin:16px 0 0; padding:0; border:0; }
.cap p { font-size:13px; line-height:1.55; color:var(--ink-soft); margin:0 0 9px;
  text-align:center; }
.cap p:last-child { margin-bottom:0; }
.cap strong { color:var(--ink); }

/* La landing respire en bas : sans cela le cap colle au bord de l'écran. */
.auth-wrap.avec-entete { padding-bottom:34px; }

/* ═══ L'ASSISTANCE VUE DU COCKPIT (lot L10) ══════════════════════════════
   ⚠️ LES BULLES SONT RECOPIÉES ICI, ET C'EST DÉLIBÉRÉ. `.bul` vit dans
   module.css — la feuille du patron B3 — et le Cockpit tourne sur `layouts/base`,
   donc sur app.css. Une vue qui part en code emporte son CSS ou elle ne part
   pas : sans ces règles, le fil sortirait en paragraphes nus, sans qu'on voie
   qui a écrit quoi. C'est exactement ce qui est arrivé à la messagerie le 18/08.

   ⚠️ ET ELLES SONT SCOPÉES SOUS `.fil-admin`, pas posées à la racine : `.bul`
   existe déjà ailleurs, et deux définitions du même nom dans deux feuilles se
   rejoindraient le jour où quelqu'un charge les deux. */
.fil-admin { display:flex; flex-direction:column; gap:7px; margin:6px 0 14px;
  max-height:420px; overflow-y:auto; padding:2px; }
.fil-admin .bul { max-width:82%; padding:8px 11px; border-radius:13px;
  font-size:13.5px; line-height:1.45; position:relative; }
.fil-admin .bul p { margin:0; }
.fil-admin .bul.lui { align-self:flex-start; background:var(--neutral-weak);
  color:var(--ink); border-bottom-left-radius:4px; }
.fil-admin .bul.moi { align-self:flex-end; background:var(--brand-weak);
  color:var(--ink); border-bottom-right-radius:4px; }
.fil-admin .quand { display:block; font-size:11px; color:var(--muted);
  margin-top:3px; text-align:right; font-variant-numeric:tabular-nums; }

/* La liste des conversations reprend `.liens-biens` : même forme, même règle. */
.liens-biens a.lb-bien { color:var(--brand-ink); text-decoration:none; }
.liens-biens a.lb-bien:hover { text-decoration:underline; }

/* Le titre de la carte de connexion, depuis que la marque en est partie
   (Paul, 21/08). Elle est dans l'en-tête ; la répéter ici repoussait le
   formulaire vers le bas de l'écran pour ne rien apprendre. */
.auth-titre { font-size:20px; line-height:1.25; font-weight:700; text-align:center;
              margin:0 0 20px; letter-spacing:-.01em; color:var(--ink); }


/* ═══ « COMMENT LE PRIX SE CALCULE » ════════════════════════════
   ⚠️ LE CONTENU TOUCHAIT LE CADRE (Paul, 21/08 : « il n'a pas de marge avec le
   contour »). Le `<details>` portait un remplissage, mais le `<summary>` et les
   paragraphes héritaient chacun de leurs marges par défaut, qui se
   chevauchaient avec lui : en haut la marge du premier titre sortait du bloc
   (effondrement de marges), en bas la dernière puce collait au bord. On isole
   donc le contenu dans un conteneur qui porte SES marges, et le `<details>` ne
   porte plus que le cadre. */
.calcul-in { padding:4px 16px 18px; }
.calcul-in h3 { font-size:13px; font-weight:750; letter-spacing:.01em;
  color:var(--ink); margin:16px 0 8px; }
.calcul-in h3:first-child { margin-top:6px; }
.calcul-in ul { list-style:none; margin:0; padding:0;
  display:flex; flex-direction:column; gap:9px; }
.calcul-in li { position:relative; padding-left:15px; font-size:13px;
  line-height:1.5; color:var(--ink-soft); }
.calcul-in li::before { content:""; position:absolute; left:0; top:8px;
  width:5px; height:5px; border-radius:50%; background:var(--brand); }
.calcul-in b { color:var(--ink); font-weight:700; }

/* ═══ LE TAUX EN HAUT À DROITE DE CHAQUE FORMULE (Paul, 21/08) ════════
   Aligné à droite sur toutes les cartes, il se compare d'une seule descente de
   l'œil — ce que le corps de carte ne permettait pas, chaque bloc commençant à
   une hauteur différente. Le minimum le suit dans le MÊME bleu, plus petit :
   c'est le second prix, pas une note. */
/* ⚠️ LE TAUX EST DANS UNE BULLE (Paul, 22/08 : « met le tarif et le % dans une
   bulle »). Posés à nu sur le dégradé, le pourcentage et son minimum flottaient
   sans rien qui les tienne ensemble - on lisait deux nombres, pas un prix. La
   bulle en fait UN objet, et c'est ce que l'œil compare d'une carte à l'autre.
   ⚠️ FOND EN BLANC TRANSPARENT, PAS EN COULEUR : le bandeau est un dégradé qui
   change de ton du haut vers le bas ; une teinte opaque irait avec l'un des deux
   bouts et jurerait avec l'autre. Un voile laisse le dégradé passer dessous. */
.offre .taux-haut { margin-left:auto; text-align:right; line-height:1.1;
  flex:0 0 auto; padding:5px 10px; border-radius:11px;
  background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.14); }
/* ⚠️ BLEU CLAIR SUR LE SOMBRE, PAS `--brand-ink`. Ce jeton est un bleu
   d'ENCRE, fait pour du texte sur fond blanc : posé sur le bandeau, il tombait
   à un contraste illisible. Les deux teintes ci-dessous sont choisies POUR ce
   fond-là — c'est la leçon du `.auth-wrap` resté violet : une couleur ne se
   déplace pas d'un fond à l'autre sans être revérifiée. */
.offre .taux-haut b { display:block; font-size:19px; font-weight:800;
  letter-spacing:-.03em; color:#a9b6f5; font-variant-numeric:tabular-nums; }
.offre .taux-haut i { display:block; font-style:normal; font-size:11px;
  font-weight:650; color:#a9b6f5; opacity:.78; margin-top:2px;
  font-variant-numeric:tabular-nums; }


/* ═══ LES PAGES PUBLIQUES PRENNENT LA PALETTE DE L'ACCUEIL ═════════════
   Paul, 21/08 : « harmonise les couleurs de la page d'accueil, de connexion et
   d'abonnement. Je préfère les couleurs de l'accueil. »

   ⚠️ L'ACCENT ÉTAIT DÉJÀ LE MÊME des deux côtés (#5f6fc9) : ce qui distinguait
   l'accueil, c'était son ENCRE plus sombre et son fond BLANC. Ce sont donc les
   deux seules choses qu'on reprend ici.

   ⚠️ ET C'EST SCOPÉ, PAS GLOBAL. `app.css` sert les quarante écrans de
   l'application : y basculer `--bg` en blanc effacerait partout la distinction
   entre la page et les cartes qui s'y posent — ce fond légèrement teinté est
   exactement ce qui les fait exister. Une harmonisation demandée sur trois
   pages ne se paie pas sur quarante. */
body.page-publique{
  --bg:#ffffff;
  --ink:#12101c;
  --ink-soft:#3b3752;
  --muted:#6a6584;
  --line:#e8e5f0;
  --neutral-weak:#faf9fd;
  background:var(--bg);
}
/* Le cadre violet du bureau n'a plus lieu d'être sur une page publique : il
   distingue l'APPLICATION de ce qui l'entoure, or ces pages-là ne sont pas
   l'application — elles y mènent. */
/* ⚠️ LE FOND AUSSI, PAS SEULEMENT L'OMBRE — et c'était le violet qui restait.
   `.auth-wrap` porte son propre `background:#e3dff2` : basculer `--bg` en blanc
   sur le corps ne l'atteignait pas, puisqu'elle ne lit pas le jeton. Mesuré en
   ligne le 21/08 : corps et carte à #ffffff, cadre à rgb(227,223,242) — le
   lavande occupait tout l'espace autour de la carte, c'est-à-dire l'essentiel
   de l'écran (Paul : « c'est tout violet »). Une palette ne s'harmonise pas en
   changeant les jetons : il faut aussi trouver ce qui écrit une couleur EN DUR. */
body.page-publique .auth-wrap{box-shadow:none; background:var(--bg)}
@media (min-width:520px) and (hover:hover) and (pointer:fine){
  body.page-publique{background:#ffffff}
}
/* La carte de connexion suit le trait de l'accueil, plus fin et plus froid que
   le lavande d'origine. */
body.page-publique .auth-card{
  border-color:var(--line);
  box-shadow:0 8px 28px rgba(23,20,48,.08), 0 1px 2px rgba(23,20,48,.04);
}
/* ⚠️ OPAQUE, COMME LA BARRE DE /formules (Paul, 22/08 : « on doit avoir le même
   fond que pour la page des formules »). Elle était à 88 % : sur une page dont
   le fond est déjà blanc, la transparence ne se voit pas au repos mais laisse
   le contenu transparaître au défilement - deux pages voisines, deux
   comportements, pour un gain nul. */
body.page-publique .entete-pub{
  background:var(--bg); border-bottom-color:var(--line); backdrop-filter:none;
}
body.page-publique .offre{border-color:var(--line)}

/* ═══ LA BARRE PUBLIQUE EST LA MÊME QUE CELLE DE LA LANDING ════════════════
   Paul, 22/08 : « tu vois la différence de header entre la landing page et la
   page des formules ? tu ne résous pas ma demande ». Il avait raison - je
   corrigeais des couleurs et des tailles de bouton, pas la DISPOSITION. Mesuré
   côte à côte : 65 px de haut contre 59, rembourrage 10/12 contre 7/15, la
   marque à x=52 contre x=15, et « · Immobilia » d'un seul côté.

   ⚠️ LE NOM DU MODULE N'A RIEN À FAIRE SUR UNE PAGE PUBLIQUE. Il dit dans quel
   univers on se trouve - c'est utile DANS l'application, où l'on passe de
   Patrimonia à Immobilia. Un visiteur qui compare des tarifs n'a pas encore
   choisi de module : le lui montrer ne le renseigne pas, ça le distingue de la
   page d'à côté sans raison.

   ⚠️ LE CHEVRON, LUI, RESTE - et c'est la seule différence qui subsiste. Il ne
   paraît que s'il y a où revenir : sur l'accueil il n'y en a pas. Une barre
   n'est pas identique parce qu'elle porte les mêmes éléments, elle l'est parce
   qu'elle les pose au même endroit quand ils sont là. */
/* ⚠️ LE NOM DU MODULE REVIENT, ET IL EST ORANGE (Paul, 22/08 : « Immobilia
   doit avoir sa couleur orange pastel et en gras »). Je l'avais masqué en
   alignant les deux barres - alignement qui était juste sur la géométrie et
   faux sur le contenu : ce n'est pas un doublon technique, c'est le nom du
   produit qu'on vend sur cette page.

   ⚠️ `--accent` (#a75f38), PAS `--immo`. Le second est un bleu lavande - le
   catalogue de jetons le nomme « Mon Immo » mais il n'est employé NULLE PART,
   et il ne correspond pas à la teinte demandée. `--accent` est le terracotta du
   dépôt, la seule teinte chaude qu'il possède.

   ⚠️ ET LA RÈGLE VIT DANS app.css, que les DEUX pages chargent : la landing
   ajoute vitrine.css par-dessus, elle n'en fait pas l'économie. Une teinte de
   marque écrite deux fois finit par diverger. */
body.page-publique .brand .sub,
.nom-immo{ color:var(--accent); font-weight:700; }
body.page-publique .topbar{padding:11px 20px}
/* ⚠️ PLUS GRANDE, ET DES DEUX CÔTÉS (Paul, 22/08 : « je t'ai demandé de grossir
   le logo et Gestineo dans le header »). Je l'avais fait sur la landing, puis
   rapetissé en l'alignant sur /formules - une correction qui en défait une
   autre. Les deux barres bougent ensemble, ou l'écart se rouvre ailleurs. */
/* ⚠️ LA TAILLE SUIT LA LARGEUR, elle n'est pas fixe. À 17 px sur un écran de
   390, « Gestineo · Immobilia » demandait 197 px pour 193 disponibles - quatre
   pixels - et passait À LA LIGNE : la marque montait à 49 px de haut, la barre
   à 72 au lieu de 67, et elle cessait de ressembler à celle de la landing. Un
   `clamp` règle la famille entière de ce défaut plutôt que ce cas-là : 17 px
   dès qu'il y a la place, et jamais moins de 14. */
body.page-publique .brand{font-size:clamp(13px,3.6vw,17px);font-weight:700;gap:8px;white-space:nowrap}
/* ⚠️ 3,6vw ET NON 4 : à 375 px, 4vw laissait le nom finir à x=246 quand le
   bouton commence à 242 - quatre pixels de recouvrement, sur UNE largeur, entre
   deux valeurs qui passaient. Un `clamp` mal réglé ne se trompe pas partout, il
   se trompe sur une bande étroite : c'est ce qui le rend long à voir, et ce qui
   oblige à mesurer plusieurs largeurs plutôt qu'une. */
body.page-publique .brand .logo{width:32px;height:32px}

/* Le « /an » d'un quota : il précise sans peser — c'est le nombre qu'on lit. */
.offre .par-an{font-size:11px;font-weight:600;color:var(--muted);margin-left:1px}

/* ⚠️ LA BANDE DE LOYERS EST UNE PRÉCISION, PAS UN CRITÈRE DE PLUS. Elle suit le
   nombre de biens entre parenthèses (Paul, 21/08) : plus petite et grise, elle
   se lit comme la borne du chiffre qui la précède. À la même graisse, elle
   redeviendrait la ligne autonome qu'on vient de retirer. Elle passe à la ligne
   quand la place manque — d'où le `display:block` : sur une carte étroite, une
   parenthèse coupée en deux au milieu d'un montant est illisible. */
.offre .bande{
  display:block; margin-top:2px;
  font-size:11px; font-weight:500; color:var(--muted); letter-spacing:0;
}

/* ═══ LES JAUGES DE QUOTA (lot L15) ══════════════════════════════════════ */
.jauge-carte { padding:14px 15px 15px; }
.jauge-tete { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
.jauge-tete b { font-size:14px; font-weight:700; color:var(--ink); }

/* ⚠️ LE RESTE EST LE GROS CHIFFRE, le total le petit. C'est le reste qui décide
   s'il faut racheter — et c'est pour ça qu'on ouvre cet écran. */
.jauge-reste { font-size:19px; font-weight:800; color:var(--brand-ink);
  font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
.jauge-reste i { font-style:normal; font-size:13px; font-weight:650;
  color:var(--muted); letter-spacing:0; }

/* ⚠️ `.jauge` ÉTAIT DÉJÀ PRIS — c'est la barre actif/passif du bilan
   Patrimonia (`display:flex`, fond blanc, marge haute). Ma règle, écrite plus
   bas et à spécificité égale, l'aurait emportée : la barre du bilan aurait
   changé d'allure sans que personne ne touche à son écran. */
.jauge-quota { height:8px; border-radius:999px; background:var(--neutral-weak);
  overflow:hidden; margin:9px 0 8px; }
.jauge-quota i { display:block; height:100%; border-radius:999px;
  background:var(--brand); transition:width .25s ease; }

/* ⚠️ À ZÉRO, LA BARRE EST VIDE — pas rouge. Un rouge de plus sur un écran de
   facturation se confond avec un impayé ; le vide, lui, ne se lit que d'une
   seule façon. */
.jauge-note { margin:0 0 10px; line-height:1.45; }


/* ══════════════════════════════════════════════════════════════════════════
   LA PAGE DES TARIFS — refaite le 26/08, quand la grille à quatre formules a
   été remplacée par un barème à tranches.

   ⚠️ CES RÈGLES PARTENT AVEC LA VUE, ET C'EST TOUT LEUR OBJET. Ce dépôt a
   livré trois vues sans leur CSS : la messagerie (deux bulles identiques à
   340×80, on ne voyait plus qui écrivait), la ligne `.ctx` de trois écrans
   (15 px presque noirs au lieu de 11 px gris), et la coche à 204 px. Le geste
   qui l'attrape coûte dix secondes et il a été fait AVANT d'écrire ceci :
   `grep -n '^\.<classe>' app.css module.css` sur chacune des douze classes
   neuves — toutes libres, aucune ne piétine une règle existante.
   ══════════════════════════════════════════════════════════════════════════ */

.tarif-tete { text-align:center; margin:6px 0 18px; }
/* L'accroche porte le seul chiffre que le visiteur retiendra : elle a droit à
   la taille d'un titre, sans en être un — la page n'a pas de <h1>. */
.tarif-accroche { font-size:1.5rem; line-height:1.25; margin:0 0 6px; color:var(--ink); }
.tarif-accroche b { color:var(--brand-ink); }
.tarif-sous { margin:0 auto; max-width:46ch; color:var(--ink-soft); line-height:1.5; }

/* Le tableau du barème et celui des actes partagent la même caisse : deux
   présentations pour deux tableaux de prix inviteraient à croire qu'ils se
   lisent différemment. */
.bareme { background:var(--card); border:1px solid var(--line); border-radius:12px;
  overflow:hidden; margin:0 0 18px; }
.bareme table { width:100%; border-collapse:collapse; }
.bareme caption { caption-side:top; text-align:left; padding:12px 16px 4px;
  color:var(--muted); font-size:.86rem; line-height:1.5; }
.bareme td, .bareme th { padding:10px 16px; border-bottom:1px solid var(--line);
  text-align:left; vertical-align:top; }
.bareme thead th { color:var(--muted); font-size:.78rem; font-weight:600;
  text-transform:uppercase; letter-spacing:.06em; }
.bareme tbody tr:last-child td { border-bottom:0; }
/* ⚠️ `tabular-nums` : sans lui, une colonne de taux ne s'aligne pas et le
   lecteur compare des virgules qui se baladent. */
.bareme .n { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
.bareme td .small { display:block; margin-top:2px; }

.simu { background:var(--card); border:1px solid var(--line); border-radius:12px;
  padding:16px; margin:0 0 18px; }
.simu h2 { margin:0 0 10px; font-size:1.05rem; }
.simu-champs { display:flex; flex-wrap:wrap; gap:10px; align-items:flex-end; }
.simu-champs label { display:flex; flex-direction:column; gap:4px; flex:1 1 190px;
  min-width:0; font-size:.9rem; color:var(--ink-soft); }
.simu-champs input { font:inherit; color:var(--ink); background:var(--bg);
  border:1px solid var(--line); border-radius:8px; padding:9px 11px;
  /* 44 px : le minimum tactile d'Apple, et il vaut sur le web comme dans le
     paquet. Une taille de police se transpose, un minimum de doigt non. */
  min-height:44px; min-width:0; }
.simu-champs input:focus-visible { outline:2px solid var(--brand); outline-offset:1px; }
.simu-champs button { font:inherit; cursor:pointer; min-height:44px; padding:0 18px;
  border:0; border-radius:8px; background:var(--brand); color:#fff; font-weight:600; }
.simu-champs button:hover { background:var(--brand-dark); }
.simu-champs button:focus-visible { outline:2px solid var(--brand-ink); outline-offset:2px; }

.simu-out { margin-top:14px; padding-top:14px; border-top:1px solid var(--line); }
.simu-prix { margin:0 0 10px; font-size:1.05rem; color:var(--ink-soft); }
.simu-prix b { font-size:1.9rem; color:var(--brand-ink); font-variant-numeric:tabular-nums;
  display:block; line-height:1.1; }
.simu-detail { list-style:none; margin:0; padding:0; }
.simu-detail li { display:flex; justify-content:space-between; gap:12px;
  padding:6px 0; border-bottom:1px solid var(--line); font-size:.92rem; }
.simu-detail li:last-child { border-bottom:0; }
.simu-detail li span:last-child { font-variant-numeric:tabular-nums; white-space:nowrap; }
/* La dernière ligne est celle qu'on compare aux annonces des autres : elle se
   distingue sans crier. */
.simu-taux { font-weight:600; color:var(--ink); }

.actes { margin:0 0 18px; }
.actes h2 { margin:0 0 6px; font-size:1.05rem; }
.actes > .small { margin:0 0 10px; }

.tarif-cta { text-align:center; margin:18px 0; }

@media (max-width:560px) {
  /* Sur un téléphone, les deux champs et le bouton s'empilent : à 190 px de
     base ils tiendraient sur une ligne de 375 px en se comprimant, et un champ
     de saisie comprimé cache la fin du montant qu'on vient de taper. */
  .simu-champs { flex-direction:column; align-items:stretch; }
  .simu-champs button { width:100%; }
}

/* ════════════════════════════════════════════════════════════════════════
   ACCUEIL « HORS MODULE » — le choix du module (views/gestionnaire/modules.php).
   Système de design de la landing, validé par Paul (maquette accueil-natif).

   ⚠️ TOUT EST PORTÉ PAR `.accueil` (classe du <body> de cet écran), et ce n'est
   pas de la coquetterie : `.tile`, `.tiles` et `.logo` existent DÉJÀ ailleurs
   dans cette feuille pour d'autres écrans. Sans ce préfixe, les deux familles se
   marcheraient dessus. Les jetons (`--fond`, `--panneau`…) sont donc eux aussi
   locaux à `.accueil` : ils ne touchent pas le `:root` global de l'app.
   ════════════════════════════════════════════════════════════════════════ */
.accueil{
  --fond:#edeef7; --panneau:#ffffff; --panneau-2:#f5f4fb;
  --encre:#141227; --encre2:#3a3653; --doux:#6a6689; --doux-2:#9591b0;
  --trait:#e7e4f1; --bord:#d3cfe4;
  --indigo:#4451ab; --violet:#8a6fc0; --lav:#5f6fc9; --vert:#2f6b4f;
  --mkt:#6a5fc4; --mkt-b:#eeecfb; --mkt-line:#d8d2f2;
  --indigo-doux:#e8eafb;
  --gloss:inset 0 1px 0 rgba(255,255,255,.92);
  --ombre-s:0 1px 2px rgba(28,24,60,.04);
  --ombre-p:inset 0 1px 0 rgba(255,255,255,.92), 0 1px 2px rgba(28,24,60,.045), 0 12px 26px -16px rgba(28,24,60,.26);
  --ombre-pill:inset 0 1px 0 rgba(255,255,255,.95), 0 2px 8px -4px rgba(28,24,60,.4);
  --alerte:#9a6a1e; --alerte-b:#fdf5e6; --alerte-line:#f0dcb0;
  /* LE ROUGE MANQUAIT À CE JEU, et la porte de sortie est née AMBRE (08/09).
     Mesuré à l'écran : le bouton « se déconnecter » sortait en #fdf5e6/#9a6a1e,
     c'est-à-dire EXACTEMENT le fond du bandeau « Profil incomplet » et
     EXACTEMENT sa pastille — trois sens pour une seule couleur, à dix pixels
     l'un de l'autre. « Une porte, et elle est rouge » (Paul, 19/08) : le seul
     geste qui DÉFAIT quelque chose porte la seule couleur qu'aucun autre
     élément de l'écran ne porte. Valeurs de la charte (:root --danger-ink /
     --danger-bg), qui n'avaient pas leur déclinaison sombre. */
  --rouge:#99414a; --rouge-b:#fbebec;
  --f-titre:"Archivo","Instrument Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --f-texte:"Instrument Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,system-ui,sans-serif;
  --f-mono:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,monospace;
  background:var(--fond); color:var(--encre); font-family:var(--f-texte); line-height:1.5;
  background-image:radial-gradient(560px 320px at 88% -6%, var(--indigo-doux), transparent 58%);
  min-height:100dvh;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .accueil{
    --fond:#0b0a14; --panneau:#161430; --panneau-2:#1d1a39;
    --encre:#f0eefb; --encre2:#cdc8e8; --doux:#a19cc4; --doux-2:#7c789e;
    --trait:#2a2649; --bord:#3a3564;
    --indigo:#97a2ef; --violet:#b89ae2; --lav:#8b96e6; --vert:#74cfa2;
    --mkt:#a99cf0; --mkt-b:#211d40; --mkt-line:#332c5c;
    --indigo-doux:#211f45;
    --gloss:inset 0 1px 0 rgba(255,255,255,.05);
    --ombre-s:0 1px 2px rgba(0,0,0,.3);
    --ombre-p:inset 0 1px 0 rgba(255,255,255,.05), 0 1px 2px rgba(0,0,0,.3), 0 12px 26px -16px rgba(0,0,0,.55);
    --ombre-pill:inset 0 1px 0 rgba(255,255,255,.06), 0 2px 8px -4px rgba(0,0,0,.6);
    --alerte:#e6b45f; --alerte-b:#2a2110; --alerte-line:#4a3a1c;
    --rouge:#f0989e; --rouge-b:#2c1418;
  }
}
:root[data-theme="dark"] .accueil{
  --fond:#0b0a14; --panneau:#161430; --panneau-2:#1d1a39;
  --encre:#f0eefb; --encre2:#cdc8e8; --doux:#a19cc4; --doux-2:#7c789e;
  --trait:#2a2649; --bord:#3a3564;
  --indigo:#97a2ef; --violet:#b89ae2; --lav:#8b96e6; --vert:#74cfa2;
  --mkt:#a99cf0; --mkt-b:#211d40; --mkt-line:#332c5c;
  --indigo-doux:#211f45;
  --gloss:inset 0 1px 0 rgba(255,255,255,.05);
  --ombre-s:0 1px 2px rgba(0,0,0,.3);
  --ombre-p:inset 0 1px 0 rgba(255,255,255,.05), 0 1px 2px rgba(0,0,0,.3), 0 12px 26px -16px rgba(0,0,0,.55);
  --ombre-pill:inset 0 1px 0 rgba(255,255,255,.06), 0 2px 8px -4px rgba(0,0,0,.6);
  --alerte:#e6b45f; --alerte-b:#2a2110; --alerte-line:#4a3a1c;
  --rouge:#f0989e; --rouge-b:#2c1418;
}

/* ── la colonne : même largeur que le reste de l'app ── */
.accueil .ac-shell{max-width:var(--app-large,480px); margin:0 auto; min-height:100dvh; display:flex; flex-direction:column; position:relative}

/* ── EN-TÊTE : logo + Gestineo (gauche) · bulle d'initiales (droite) ── */
.accueil .ac-hd{flex:0 0 auto; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:16px 20px 12px}
.accueil .ac-hd .l{display:flex; align-items:center; gap:11px; min-width:0}
.accueil .ac-hd .logo{width:34px; height:34px; border-radius:10px; display:block; flex:0 0 34px; object-fit:contain;
  background:#fff; padding:3px; box-shadow:var(--ombre-s), 0 0 0 1px var(--trait)}
.accueil .wordmark{font-family:var(--f-texte); font-weight:700; font-size:20px; letter-spacing:-.022em; color:var(--encre); white-space:nowrap}
.accueil .ac-bulle{position:relative; width:38px; height:38px; border-radius:50%; flex:0 0 38px; cursor:pointer; border:0; text-decoration:none;
  background:linear-gradient(150deg,var(--lav),var(--indigo)); color:#fff; font-family:var(--f-mono); font-weight:800; font-size:13px;
  display:grid; place-items:center; box-shadow:inset 0 1px 0 rgba(255,255,255,.4), 0 3px 9px -2px rgba(68,81,171,.55)}
:root[data-theme="dark"] .accueil .ac-bulle,:root:not([data-theme="light"]) .accueil .ac-bulle{color:#fff}
.accueil .ac-bulle.alerte::after{content:""; position:absolute; top:0; right:0; width:11px; height:11px; border-radius:50%; background:var(--alerte); border:2px solid var(--fond)}
.accueil .ac-bulle:active{transform:scale(.95)}
/* ── SE DÉCONNECTER depuis l'écran des modules (incident Paul 08/09 ㉒). Assortie à la
   bulle (rond 38 px), mais ROUGE — « une porte, et elle est rouge » (Paul 19/08), comme
   la déconnexion de la coquille Immobilia, qui prend var(--red). ⚠️ PAS var(--alerte) :
   l'ambre est DÉJÀ pris sur cet écran par la pastille « profil incomplet » et son
   bandeau (mesuré : la première version rendait les trois en #fdf5e6/#9a6a1e). Le `.r`
   regroupe la bulle et la porte à droite de l'en-tête. ── */
.accueil .ac-hd .r{display:flex; align-items:center; gap:10px}
.accueil .ac-sortir-f{margin:0; display:flex}
.accueil .ac-sortir{width:38px; height:38px; border-radius:50%; flex:0 0 38px; cursor:pointer; border:0;
  background:var(--rouge-b); color:var(--rouge); display:grid; place-items:center; box-shadow:var(--gloss)}
.accueil .ac-sortir svg{width:19px; height:19px}
.accueil .ac-sortir:active{transform:scale(.95)}

/* ── LE CORPS : il défile, il ne déborde pas ── */
.accueil .ac-body{flex:1; display:flex; flex-direction:column; padding:2px 20px 28px}

/* ── BANDEAU « profil incomplet » (cliquable vers le compte) ── */
.accueil .ac-profil{display:flex; gap:11px; align-items:center; text-align:left; text-decoration:none; width:100%; cursor:pointer;
  background:var(--alerte-b); border:1px solid var(--alerte-line); border-radius:15px; padding:12px 13px; margin:8px 0 4px; box-shadow:var(--gloss);
  font-family:var(--f-texte); color:var(--encre)}
.accueil .ac-profil .pic{width:28px; height:28px; border-radius:9px; background:var(--alerte-line); color:var(--alerte); display:grid; place-items:center; flex:0 0 28px}
.accueil .ac-profil .pic svg{width:17px; height:17px}
.accueil .ac-profil .t{flex:1; min-width:0}
.accueil .ac-profil b{font-family:var(--f-titre); font-weight:700; font-size:14px; display:block; color:var(--alerte); line-height:1.2}
.accueil .ac-profil p{font-size:12px; color:var(--doux); margin:2px 0 0; line-height:1.4}
.accueil .ac-profil .chev{color:var(--alerte); font-size:20px; flex:0 0 auto; align-self:center}
.accueil .ac-profil:active{transform:scale(.99)}

/* ── LES TUILES ── */
.accueil .ac-tiles{display:flex; flex-direction:column; gap:12px; margin-top:14px}
.accueil .ac-tile{width:100%; text-align:left; font-family:var(--f-texte); color:var(--encre); cursor:pointer;
  display:flex; align-items:center; gap:14px; background:var(--panneau); border:1px solid var(--trait);
  border-radius:19px; padding:15px 16px; box-shadow:var(--ombre-p)}
.accueil form.ac-tile-f{margin:0}
.accueil .ac-tile .ic{width:48px; height:48px; border-radius:14px; display:grid; place-items:center; flex:0 0 48px; box-shadow:inset 0 1px 0 rgba(255,255,255,.55);
  background:var(--panneau-2); color:var(--doux)}
.accueil .ac-tile .ic svg{width:26px; height:26px}
.accueil .ac-tile .body{flex:1; min-width:0; display:flex; flex-direction:column; gap:4px}
.accueil .ac-tile .nom{font-family:var(--f-titre); font-weight:700; font-size:17.5px; letter-spacing:-.015em; line-height:1.1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:var(--encre)}
.accueil .ac-tile .base{font-size:11.5px; color:var(--doux); margin:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.accueil .ac-tier{font-family:var(--f-mono); font-size:11px; font-weight:600; letter-spacing:.05em; text-transform:uppercase; padding:5px 11px; border-radius:999px; white-space:nowrap; flex:0 0 auto; align-self:center;
  background:var(--panneau-2); color:var(--doux)}

/* ACTIF : la couleur PROPRE du module, passée en --c par la tuile (rgba dérivée
   du hex du catalogue → s'adapte au clair comme au sombre). */
.accueil .ac-tile.actif{border-color:var(--c-line)}
.accueil .ac-tile.actif .ic{background:var(--c-b); color:var(--c)}
.accueil .ac-tile.actif .nom{color:var(--c)}
.accueil .ac-tile.actif .ac-tier{background:var(--c-b); color:var(--c)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .accueil .ac-tile.actif .nom,
  :root:not([data-theme="light"]) .accueil .ac-tile.actif .ic,
  :root:not([data-theme="light"]) .accueil .ac-tile.actif .ac-tier{color:color-mix(in srgb, var(--c), #ffffff 32%)}
}
:root[data-theme="dark"] .accueil .ac-tile.actif .nom,
:root[data-theme="dark"] .accueil .ac-tile.actif .ic,
:root[data-theme="dark"] .accueil .ac-tile.actif .ac-tier{color:color-mix(in srgb, var(--c), #ffffff 32%)}

/* MARCHÉ : le module existe mais n'est pas (encore) ouvert à ce compte —
   informatif, jamais cliquable. */
.accueil .ac-tile.marche{background:linear-gradient(180deg,var(--panneau),var(--mkt-b)); border-color:var(--mkt-line); cursor:default}
.accueil .ac-tile.marche .ic{background:var(--mkt-b); color:var(--mkt); box-shadow:inset 0 0 0 1px var(--mkt-line)}
.accueil .ac-tile.marche .nom{color:var(--mkt)}
.accueil .ac-tile.marche .ac-tier{background:var(--mkt-b); color:var(--mkt)}

/* OFF : éteint au Cockpit (facturation suspendue) — grisé, non cliquable. */
.accueil .ac-tile.off{opacity:.62; cursor:default; box-shadow:var(--ombre-s)}
.accueil .ac-tile.off .nom{color:var(--doux)}
.accueil .ac-tile.off .ic{filter:grayscale(1)}

/* ── MOUVEMENT ──
   Entrée : les tuiles apparaissent l'une après l'autre. Repos : un halo qui
   respire dans la couleur du module. `prefers-reduced-motion` coupe tout
   (règle globale de cette feuille, plus une garde locale par sûreté). */
@keyframes ac-tile-in{from{opacity:0; transform:translateY(15px) scale(.97)} to{opacity:1; transform:none}}
@keyframes ac-halo{
  0%,100%{box-shadow:var(--ombre-p)}
  50%{box-shadow:var(--ombre-p), 0 12px 26px -6px var(--glow, transparent)}
}
.accueil .ac-tile{animation:ac-tile-in .55s cubic-bezier(.16,.84,.28,1) both}
.accueil .ac-tile.actif{animation:ac-tile-in .55s cubic-bezier(.16,.84,.28,1) both, ac-halo 3.8s ease-in-out .9s infinite}
.accueil .ac-tile:nth-child(1){animation-delay:.06s, .9s}
.accueil .ac-tile:nth-child(2){animation-delay:.18s, 1s}
.accueil .ac-tile:nth-child(3){animation-delay:.30s, 1.1s}
.accueil .ac-tile:active{transform:scale(.97)}
@media (prefers-reduced-motion:reduce){.accueil .ac-tile{animation:none}}

/* ── OVERLAY de choix de RÔLE (plusieurs vues sur un module) ── */
.accueil .ac-overlay{position:fixed; inset:0; z-index:60; display:none; align-items:flex-end; justify-content:center; background:rgba(18,14,32,.52)}
.accueil .ac-overlay.on{display:flex; animation:ac-scrim .22s ease}
@keyframes ac-scrim{from{opacity:0} to{opacity:1}}
.accueil .ac-sheet{width:100%; max-width:var(--app-large,480px); background:var(--fond); border-radius:24px 24px 0 0; padding:14px 20px 24px; box-shadow:0 -14px 44px -14px rgba(9,7,22,.55); animation:ac-sheet-up .36s cubic-bezier(.16,.84,.28,1)}
@keyframes ac-sheet-up{from{transform:translateY(100%)} to{transform:none}}
.accueil .ac-grip{width:40px; height:4px; border-radius:3px; background:var(--bord); margin:0 auto 14px}
.accueil .ac-sheet h4{font-family:var(--f-titre); font-weight:800; font-size:20px; letter-spacing:-.02em; margin:0 0 3px; color:var(--encre)}
.accueil .ac-sheet .sub{font-size:12.5px; color:var(--doux); margin:0 0 15px}
.accueil form.ac-role-f{margin:0}
.accueil .ac-role{width:100%; text-align:left; display:flex; align-items:center; gap:13px; background:var(--panneau); border:1px solid var(--trait); border-radius:16px; padding:13px 14px; box-shadow:var(--ombre-p); margin-bottom:11px; font-family:var(--f-texte); color:var(--encre); cursor:pointer}
.accueil .ac-role .ri{width:42px; height:42px; border-radius:12px; display:grid; place-items:center; flex:0 0 42px; background:var(--c-b,var(--indigo-doux)); color:var(--c,var(--indigo)); box-shadow:inset 0 1px 0 rgba(255,255,255,.5)}
.accueil .ac-role .ri svg{width:22px; height:22px}
.accueil .ac-role .t{flex:1; min-width:0}
.accueil .ac-role .t b{font-family:var(--f-titre); font-weight:700; font-size:16px; display:block; line-height:1.12; color:var(--encre)}
.accueil .ac-role .t span{font-size:12px; color:var(--doux)}
.accueil .ac-role .chev{color:var(--doux-2); font-size:20px; flex:0 0 auto}
.accueil .ac-role:active{transform:scale(.98)}
@media (prefers-reduced-motion:reduce){.accueil .ac-overlay.on,.accueil .ac-sheet{animation:none}}

/* ── ÉTAT VIDE : aucun module rattaché ── */
.accueil .ac-vide{background:var(--panneau); border:1px solid var(--trait); border-radius:19px; padding:20px 18px; box-shadow:var(--ombre-p); margin-top:16px}
.accueil .ac-vide h2{font-family:var(--f-titre); font-weight:800; font-size:19px; letter-spacing:-.02em; margin:0 0 8px; color:var(--encre)}
.accueil .ac-vide p{font-size:13px; color:var(--doux); margin:0 0 8px; line-height:1.45}

/* ═══════════════════════════════════════════════════════════════════════════
   MON COMPTE — l'écran personnel FUSIONNÉ (Paul, 27/08 : « fusionner dans un
   seul écran »). Compte perso + sociétés + Google + déconnexion, hors-module.
   Classes .cpt-* / .deco / .mark / .act : design validé dans l'établi, promu
   ici sous le scope .accueil. Les tokens --amber* de l'établi = les --alerte*
   déjà définis plus haut (mêmes valeurs) ; le bandeau « profil incomplet »
   réutilise .ac-profil, qui fait déjà exactement ce travail.
   ═══════════════════════════════════════════════════════════════════════════ */

/* En-tête retour (remplace le chevron de la coquille module, absente ici) */
.accueil .cpt-back{width:38px; height:38px; border-radius:50%; flex:0 0 38px;
  display:grid; place-items:center; text-decoration:none; border:1px solid var(--trait);
  background:var(--panneau); color:var(--doux); box-shadow:var(--ombre-s); font-size:23px; line-height:0}
.accueil .cpt-back:active{transform:scale(.95)}

/* Identité : avatar d'initiales + nom/e-mail */
.accueil .cpt-head{display:flex; align-items:center; gap:14px; padding:6px 2px 10px}
.accueil .cpt-av{width:56px; height:56px; border-radius:18px; flex:0 0 56px;
  background:linear-gradient(150deg,var(--lav),var(--indigo)); color:#fff;
  display:grid; place-items:center; font-family:var(--f-mono); font-weight:800; font-size:19px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4), 0 5px 13px -3px rgba(68,81,171,.5)}
.accueil .cpt-id{min-width:0}
.accueil .cpt-id b{font-family:var(--f-titre); font-weight:800; font-size:21px; letter-spacing:-.02em; display:block; line-height:1.08; color:var(--encre)}
.accueil .cpt-id span{font-size:12.5px; color:var(--doux); word-break:break-word}

/* Message transitoire (ex. « compte Google délié ») */
.accueil .cpt-flash{border-radius:12px; padding:11px 13px; margin:4px 0 12px; font-size:13px; font-weight:600; box-shadow:var(--gloss)}
.accueil .cpt-flash.ok{background:var(--panneau-2); color:var(--vert); border:1px solid var(--trait)}
.accueil .cpt-flash.ko{background:var(--alerte-b); color:var(--alerte); border:1px solid var(--alerte-line)}

/* Intertitre de groupe */
.accueil .cpt-lab{font-family:var(--f-mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--doux); margin:18px 2px 9px}

/* Une rangée-pilier : icône + titre/sous-titre + pastille d'état + chevron */
.accueil .cpt-row{width:100%; text-align:left; text-decoration:none; cursor:pointer;
  font-family:var(--f-texte); color:var(--encre); display:flex; align-items:center; gap:13px;
  background:var(--panneau); border:1px solid var(--trait); border-radius:15px; padding:13px 14px;
  box-shadow:var(--ombre-p); margin-bottom:10px}
.accueil .cpt-row:active{transform:scale(.98)}
.accueil .cpt-row .ci{width:40px; height:40px; border-radius:12px; flex:0 0 40px;
  background:var(--panneau-2); color:var(--doux); display:grid; place-items:center; box-shadow:var(--gloss)}
.accueil .cpt-row .ci svg{width:20px; height:20px}
.accueil .cpt-row .ci.acc{background:var(--indigo-doux); color:var(--indigo)}
.accueil .cpt-row .t{flex:1; min-width:0}
.accueil .cpt-row .t b{font-weight:600; font-size:14.5px; display:block; line-height:1.15; color:var(--encre)}
.accueil .cpt-row .t span{font-size:12px; color:var(--doux); display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.accueil .cpt-row .chev{color:var(--doux-2); font-size:20px; flex:0 0 auto; line-height:1}

/* Pastilles d'état (réutilisables : rangées ET section Google) */
.accueil .act{font-family:var(--f-mono); font-size:10.5px; font-weight:600; letter-spacing:.04em; text-transform:uppercase;
  color:var(--indigo); background:var(--indigo-doux); border-radius:999px; padding:5px 10px; flex:0 0 auto; white-space:nowrap}
.accueil .mark{font-family:var(--f-mono); font-size:10px; font-weight:600; letter-spacing:.05em; text-transform:uppercase;
  padding:4px 9px; border-radius:999px; flex:0 0 auto; white-space:nowrap}
.accueil .mark.req{background:var(--alerte-b); color:var(--alerte)}
.accueil .mark.opt{background:var(--panneau-2); color:var(--doux); border:1px solid var(--trait)}
.accueil .mark.ok{background:var(--panneau-2); color:var(--vert); border:1px solid var(--trait)}

/* Section « Connexion avec Google » — panneau de même matière que les rangées */
.accueil .cpt-sec{background:var(--panneau); border:1px solid var(--trait); border-radius:15px;
  padding:14px 15px; box-shadow:var(--ombre-p); margin-bottom:10px}
.accueil .cpt-sec-h{display:flex; align-items:center; gap:11px}
.accueil .cpt-sec-h .ci{width:36px; height:36px; border-radius:11px; flex:0 0 36px;
  background:var(--panneau-2); color:var(--doux); display:grid; place-items:center; box-shadow:var(--gloss)}
.accueil .cpt-sec-h .ci svg{width:19px; height:19px}
.accueil .cpt-sec-h b{font-family:var(--f-titre); font-weight:700; font-size:15px; color:var(--encre)}
.accueil .cpt-sec-h .act{margin-left:auto}
.accueil .cpt-sec p{font-size:12.5px; color:var(--doux); line-height:1.45; margin:9px 0 0}
.accueil .cpt-sec .adr{font-size:12.5px; color:var(--encre); margin:9px 0 0; font-weight:600; word-break:break-word}

/* Bouton d'action (relier / délier Google) */
.accueil .cpt-btn{display:inline-flex; align-items:center; justify-content:center; gap:8px; width:100%;
  min-height:44px; padding:11px 16px; border-radius:12px; border:0; cursor:pointer;
  font-family:var(--f-texte); font-weight:600; font-size:14.5px; margin-top:11px;
  background:linear-gradient(150deg,var(--lav),var(--indigo)); color:#fff;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4), 0 3px 9px -2px rgba(68,81,171,.5)}
.accueil .cpt-btn.ghost{background:transparent; border:1px solid var(--bord); color:var(--indigo); box-shadow:none}
.accueil .cpt-btn:active{transform:scale(.98)}

/* Déconnexion — ROUGE, collée tout en bas (margin-top:auto ; .ac-body est une
   colonne flex qui grandit, cf. .accueil .ac-body plus haut) */
.accueil .deco-f{margin-top:auto; padding-top:18px}
.accueil .deco{width:100%; padding:15px; border:0; background:transparent; cursor:pointer;
  font-family:var(--f-texte); font-weight:600; font-size:14.5px; color:#c94a44; transition:transform .1s}
.accueil .deco:active{transform:scale(.97)}

/* Textes clairs sur fond sombre : rouge de la déco éclairci, encre des dégradés
   (avatar + bouton) inversée — mêmes valeurs que .ac-bulle. Media-gardé pour ne
   PAS teinter le mode clair. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .accueil .deco{color:#f0837c}
  :root:not([data-theme="light"]) .accueil .cpt-av,
  :root:not([data-theme="light"]) .accueil .cpt-btn{color:#0b0a14}
}
:root[data-theme="dark"] .accueil .deco{color:#f0837c}
:root[data-theme="dark"] .accueil .cpt-av,
:root[data-theme="dark"] .accueil .cpt-btn{color:#0b0a14}
