/* ══════════════════════════════════════════════
   iOS 17 Design System — Dual Theme (Dark/Light)
   Variables + Unification de la Navbar & du Content
   ══════════════════════════════════════════════ */

:root {
  /* ── MODE SOMBRE PAR DÉFAUT (iOS 17 Dark) ── */
  --bg:              #000000;
  --bg-grouped:      #1C1C1E;
  --bg-grouped-2:    #1E3438;
  --bg-grouped-3:    #274750;
  --nav-segment-bg:     #22202A; /* Fond — lavande-gris sombre */
  --nav-segment-active: #35304A; /* Pill actif — lavande-gris moyen */
  --nav-segment-active-text: #BDB4E8; /* Texte pill actif — lavande douce */

  /* Pastel tokens (dark) */
  --pastel-blue-bg:   rgba(99,179,237,0.12);
  --pastel-blue-text: #93C5FD;
  --pastel-green-bg:  rgba(110,231,183,0.12);
  --pastel-green-text:#6EE7B7;
  --pastel-orange-bg: rgba(253,186,116,0.12);
  --pastel-orange-text:#FCD34D;
  --pastel-purple-bg: rgba(196,181,253,0.12);
  --pastel-purple-text:#C4B5FD;
  --pastel-pink-bg:   rgba(249,168,212,0.12);
  --pastel-pink-text: #F9A8D4;
  --pastel-teal-bg:   rgba(94,234,212,0.12);
  --pastel-teal-text: #5EEAD4;
  /* 💡 Palette DÉDIÉE hub Équilibre — sans violet/jaune/vert (exclus
     volontairement). Adoucie : couleurs plus claires/désaturées et fond
     moins opaque (0.10 au lieu de 0.16) pour un rendu plus pastel/discret,
     utilisée en DÉGRADÉ sur chaque tuile (voir .eqhub-tile). */
  --pastel-coral-bg:   rgba(255,138,128,0.10);
  --pastel-coral-text: #FFAB9E;
  --pastel-rose-bg:    rgba(255,138,178,0.10);
  --pastel-rose-text:  #FFAEC9;
  --pastel-sky-bg:     rgba(125,211,252,0.10);
  --pastel-sky-text:   #AEE1FA;
  --pastel-slate-bg:   rgba(148,163,184,0.10);
  --pastel-slate-text: #AFC0D6;
  /* Anciennes valeurs (repli/référence) :
  --pastel-amber-bg:    rgba(255,193,7,0.16);
  --pastel-amber-text:  #FFCA5C;
  --pastel-emerald-bg:  rgba(52,211,153,0.16);
  --pastel-emerald-text:#4ADE9C;
  --pastel-orchid-bg:   rgba(217,111,222,0.16);
  --pastel-orchid-text: #E38FE8;
  --pastel-terracotta-bg:  rgba(212,150,125,0.14);
  --pastel-terracotta-text:#D4967D;
  --pastel-sage-bg:        rgba(156,175,136,0.14);
  --pastel-sage-text:      #9CAF88;
  --pastel-slate-bg:       rgba(143,168,196,0.14);
  --pastel-slate-text:     #8FA8C4;
  --pastel-mauve-bg:       rgba(194,153,181,0.14);
  --pastel-mauve-text:     #C299B5;
  */
  --label:           #FFFFFF;
  --label-2:         rgba(235, 235, 245, 0.75);
  --label-3:         rgba(235, 235, 245, 0.5);
  --label-4:         rgba(235, 235, 245, 0.22);
  --fill:            rgba(120, 120, 128, 0.36);
  --fill-2:          rgba(120, 120, 128, 0.32);
  --fill-3:          rgba(118, 118, 128, 0.24);
  --fill-4:          rgba(116, 116, 128, 0.18);
  --sep:             rgba(182, 182, 189, 0.65);
  --sep-opaque:      #262627;
  
  /* Couleurs Système iOS */
  --blue:            #0A84FF;
  --green:           #32D74B;
  --red:             #FF453A;
  --orange:          #FF9F0A;
  --indigo:          #5E5CE6;
  --purple:          #BF5AF2;
  --teal:            #5AC8FA;

  /* Animation fluide lors du switch */
  --theme-transition: background-color 0.25s cubic-bezier(.4,0,.2,1), 
                      color 0.25s cubic-bezier(.4,0,.2,1), 
                      border-color 0.25s cubic-bezier(.4,0,.2,1), 
                      box-shadow 0.25s cubic-bezier(.4,0,.2,1);

  /* ── HAUTEURS FIXES UNIQUES ── */
  /* 50px = ligne titre uniquement (segment control supprimé) */
  --topbar-h: 50px;

  /* Compat aliases */
  --surface:    var(--bg-grouped);
  --surface2:   var(--bg-grouped-2);
  --border:     var(--sep-opaque);
  --accent:     var(--blue);
  --text:       var(--label);
  --muted:      var(--label-3);
  --danger:     var(--red);
  --success:    var(--green);
  --prev-cyan:  var(--teal);
  --condo:      var(--blue);
  --taxes:      var(--purple);
  --owners:     var(--green);
  --autres:     var(--label-3);
}

/* ── MODE CLAIR (iOS 17 Light Edition) ── */
[data-theme="light"] {
  --bg:              #F2F2F7; /* Gris clair de fond groupé iOS */
  --bg-grouped:      #FFFFFF; /* Encarts purs blancs */
  --bg-grouped-2:    #E2F2F4; /* Éléments secondaires teintés teal pastel */
  --bg-grouped-3:    #C9E8EC;
  --nav-segment-bg:     #EDEAF5; /* Fond — lavande-gris très pâle */
  --nav-segment-active: #FFFFFF; /* Pill actif — blanc pur sur lavande */
  --nav-segment-active-text: #5B4FA8; /* Texte pill actif — lavande profond */

  /* Pastel tokens (light) */
  --pastel-blue-bg:   rgba(59,130,246,0.09);
  --pastel-blue-text: #2563EB;
  --pastel-green-bg:  rgba(16,185,129,0.09);
  --pastel-green-text:#059669;
  --pastel-orange-bg: rgba(245,158,11,0.09);
  --pastel-orange-text:#D97706;
  --pastel-purple-bg: rgba(139,92,246,0.09);
  --pastel-purple-text:#7C3AED;
  --pastel-pink-bg:   rgba(236,72,153,0.09);
  --pastel-pink-text: #BE185D;
  --pastel-teal-bg:   rgba(20,184,166,0.09);
  --pastel-teal-text: #0D9488;
  /* 💡 Même quatuor qu'en dark mode — adouci (moins saturé, fond moins
     opaque : 0.07 au lieu de 0.10) pour un rendu plus pastel/discret,
     tout en gardant un contraste suffisant sur fond clair. */
  --pastel-coral-bg:   rgba(220,38,38,0.07);
  --pastel-coral-text: #C2564E;
  --pastel-rose-bg:    rgba(219,39,119,0.07);
  --pastel-rose-text:  #C25E8C;
  --pastel-sky-bg:     rgba(2,132,199,0.07);
  --pastel-sky-text:   #4A8FB0;
  --pastel-slate-bg:   rgba(71,85,105,0.07);
  --pastel-slate-text: #57677E;
  /* Anciennes valeurs (repli/référence) :
  --pastel-amber-bg:    rgba(217,119,6,0.10);
  --pastel-amber-text:  #B45309;
  --pastel-emerald-bg:  rgba(5,150,105,0.10);
  --pastel-emerald-text:#0F9D74;
  --pastel-orchid-bg:   rgba(192,38,211,0.10);
  --pastel-orchid-text: #A21CAF;
  --pastel-terracotta-bg:  rgba(168,98,63,0.11);
  --pastel-terracotta-text:#A8623F;
  --pastel-sage-bg:        rgba(95,122,84,0.11);
  --pastel-sage-text:      #5F7A54;
  --pastel-slate-bg:       rgba(74,107,138,0.11);
  --pastel-slate-text:     #4A6B8A;
  --pastel-mauve-bg:       rgba(138,85,120,0.11);
  --pastel-mauve-text:     #8A5578;
  */
  --label:           #000000; /* Texte principal */
  --label-2:         rgba(60, 60, 67, 0.75);  /* Label secondaire clair */
  --label-3:         rgba(60, 60, 67, 0.5);   /* Label tertiaire */
  --label-4:         rgba(60, 60, 67, 0.22);  /* Quaternaire */
  --fill:            rgba(118, 118, 128, 0.24);
  --fill-2:          rgba(118, 118, 128, 0.16);
  --fill-3:          rgba(118, 118, 128, 0.12);
  --fill-4:          rgba(118, 118, 128, 0.08);
  --sep:             rgba(60, 60, 67, 0.29);  /* Séparateur natif iOS Light */
  --sep-opaque:      #E5E5EA;
  
  /* Couleurs Système adaptées pour contraste Light */
  --blue:            #007AFF;
  --green:           #34C759;
  --red:             #FF3B30;
  --orange:          #FF9500;
  --indigo:          #5856D6;
  --purple:          #AF52DE;
  --teal:            #30B0C7;
}

*, *::before, *::after {
  box-sizing: border-box; margin: 0; padding: 0;
  -webkit-tap-highlight-color: transparent;
  outline: none !important;
}

html, body {
  
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Rounded", sans-serif;
  background: var(--bg); color: var(--label);
  min-height: 100%;
  display: flex; flex-direction: column;
  -webkit-font-smoothing: antialiased;
  transition: var(--theme-transition);
}



/* 💡 #mobile-apps-root doit avoir une hauteur explicite (pas "auto") pour que
   ses enfants (#app-home, #app-condo, etc.) puissent utiliser height:100%
   de façon fiable. Sans ça, chaque #app-xxx recalculait sa propre hauteur en
   "100dvh - topbar-h", ignorant le padding-top déjà réservé par son parent
   #app-content-layout pour la navbar fixe — le débord (~topbar-h + navbar-h)
   était alors tronqué par l'overflow:hidden du parent (bug visible surtout
   en WebView Scriptable, moins indulgente que Safari sur ce point). */
#mobile-apps-root {
  display: flex;
  flex-direction: column;
  flex: 1;
  /*height: 100svh;*/
  min-height: 0;
  overflow: hidden;
}

/* #apps-container reçoit le HTML applicatif (buildShellBodyHtml) — doit
   pouvoir se réduire dans le flex parent (min-height:0) pour laisser
   .tabbar (order:1, flex-shrink:0) garder sa taille naturelle plutôt
   que d'être compressée ou de déborder. */
#apps-container {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

#dynamic-page-title {
  font-weight: 500;
  color: var(--label-3, #8e8e93);
  font-size: 15px;
  margin-left: 6px;
  white-space: nowrap; 
  overflow: hidden;
  text-overflow: ellipsis;
  transition: var(--theme-transition);
}

.nav-segmented {
  display: flex;
  background: var(--nav-segment-bg);
  padding: 3px; 
  border-radius: 13px;
  border: 0.5px solid rgba(155,135,220,0.2);
  gap: 2px;
  transition: var(--theme-transition);
}

/* ══ TOPBAR FILTER BUTTON — remplace le segment control 3 items (Équilibre,
   Calendrier) par un bouton compact (icône + libellé + chevron) qui ouvre
   un menu déroulant listant les mêmes options. Vit dans #topbar-segment-slot
   au même titre que .nav-segmented (non touché ailleurs dans l'app). ══ */
.topbar-filter-wrap {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
}
.topbar-filter-btn {
  display: flex; align-items: center; gap: 6px;
  height: 34px; padding: 0 8px 0 6px;
  border-radius: 11px;
  background: transparent;
  border: 0.5px solid transparent;
  color: var(--label-2);
  font-size: 13px; font-weight: 600;
  cursor: pointer; font-family: inherit;
  transition: var(--theme-transition), background 0.15s, border-color 0.15s;
}
.topbar-filter-btn:active { background: var(--fill-4); }
.topbar-filter-wrap.open .topbar-filter-btn { background: var(--fill-4); }
.topbar-filter-btn-ico {
  display: flex; align-items: center; flex-shrink: 0;
  color: var(--label-3);
}
.topbar-filter-btn-ico svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2.2; }
.topbar-filter-btn-label { flex-shrink: 0; white-space: nowrap; }
.topbar-filter-btn-chev {
  display: flex; align-items: center; flex-shrink: 0; margin-left: 1px;
  color: var(--label-4);
  transition: transform 0.2s cubic-bezier(.4,0,.2,1);
}
.topbar-filter-wrap.open .topbar-filter-btn-chev { transform: rotate(180deg); }

.topbar-filter-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: auto;
  min-width: 190px;
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 14px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.22), 0 1px 4px rgba(0,0,0,0.12);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  padding: 5px;
  display: flex; flex-direction: column; gap: 1px;
  opacity: 0; transform: translateY(-6px) scale(0.97);
  pointer-events: none;
  transform-origin: top left;
  transition: opacity 0.16s ease, transform 0.2s cubic-bezier(.34,1.56,.64,1);
  z-index: 50;
}
.topbar-filter-menu.show {
  opacity: 1; transform: translateY(0) scale(1);
  pointer-events: auto;
}
.topbar-filter-item {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-radius: 10px;
  font-size: 13px; font-weight: 500; color: var(--label-2);
  cursor: pointer; white-space: nowrap;
  transition: background 0.12s, color 0.15s;
}
.topbar-filter-item:active { background: var(--fill-4); }
.topbar-filter-item-ico {
  display: flex; align-items: center; flex-shrink: 0;
  color: var(--label-4);
}
.topbar-filter-item-ico svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2.2; }
.topbar-filter-item.active {
  background: rgba(10,132,255,0.12);
  color: var(--blue); font-weight: 700;
}
.topbar-filter-item.active .topbar-filter-item-ico { color: var(--blue); }

/* ── Slot filtre de la barre la plus haute (à côté de l'avatar) — un
   panneau par app concernée, un seul visible à la fois (voir
   core.js::_buildTopbarFilterSlotHtml / switchApp). ── */
.topbar-filterslot-panel { display: none; height: 100%; }
.topbar-filterslot-panel.active { display: flex; align-items: center; }


/* ══ CONTENU SCROLLABLE ══ */
.content,
.content-segmented {
  flex: 1 !important;
  height: 100% !important;
  max-height: 100% !important;
  overflow-y: scroll !important;
  min-height: calc(100% + 1px) !important; 
  padding: 14px 12px !important;
  padding-left:  max(12px, env(safe-area-inset-left)) !important;
  padding-right: max(12px, env(safe-area-inset-right)) !important;
  /* 💡 .tabbar est désormais en flux (flex, plus fixed) — elle ne
     recouvre plus le contenu, donc plus besoin de réserver sa hauteur
     ici. On garde juste une petite marge de confort en bas + les FAB
     (qui restent fixed, voir plus bas) ont leur propre "bottom" calculé
     par rapport au viewport, pas au contenu. */
  padding-bottom: 20px !important;
}

.app-section { display: none; }
.app-section.active { display: block; }
 
/* ══ FORM ══ */
.form-grid { display: flex; flex-direction: column; gap: 14px; }
 
.field label {
  display: block; font-size: 9px; font-weight: 700;
  letter-spacing: 0.8px; text-transform: uppercase;
  color: var(--label-3); margin-bottom: 7px;
  transition: var(--theme-transition);
}

.field input, .field select, .field textarea {
  width: 100%;
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px; color: var(--label);
  font-size: 15px; padding: 12px 14px;
  -webkit-appearance: none; font-family: inherit;
  transition: var(--theme-transition);
}

.field input:focus, .field select:focus {
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(10,132,255,0.15);
}
 
/* ══ SEGMENTED CONTROL — iOS 17 Native ══ */
.segmented-control {
  display: flex;
  background: var(--nav-segment-bg);
  padding: 3px; border-radius: 10px;
  border: 0.5px solid rgba(155,135,220,0.18);
  gap: 2px;
  transition: var(--theme-transition);
}

.segmented-item {
  flex: 1; text-align: center; padding: 8px 6px;
  font-size: 12px; font-weight: 500; border-radius: 7px;
  cursor: pointer; color: var(--label-3);
  transition: all 0.18s cubic-bezier(.4,0,.2,1), color 0.25s ease;
  font-family: inherit; letter-spacing: -0.1px;
}

.segmented-item.active-status {
  background: var(--pastel-blue-bg);
  color: var(--pastel-blue-text); font-weight: 700;
  box-shadow: 0 0 0 0.5px rgba(59,130,246,0.25), inset 0 0.5px 0 rgba(255,255,255,0.08);
}
.segmented-item.active-status-cyan {
  background: var(--pastel-orange-bg);
  color: var(--pastel-orange-text); font-weight: 700;
  box-shadow: 0 0 0 0.5px rgba(245,158,11,0.25), inset 0 0.5px 0 rgba(255,255,255,0.08);
}
.segmented-item.active-debit {
  background: var(--pastel-pink-bg);
  color: var(--pastel-pink-text); font-weight: 700;
  box-shadow: 0 0 0 0.5px rgba(236,72,153,0.25), inset 0 0.5px 0 rgba(255,255,255,0.08);
}
.segmented-item.active-credit {
  background: var(--pastel-green-bg);
  color: var(--pastel-green-text); font-weight: 700;
  box-shadow: 0 0 0 0.5px rgba(16,185,129,0.25), inset 0 0.5px 0 rgba(255,255,255,0.08);
}
.segmented-item.active-owner {
  background: var(--pastel-purple-bg);
  color: var(--pastel-purple-text); font-weight: 700;
  box-shadow: 0 0 0 0.5px rgba(139,92,246,0.25), inset 0 0.5px 0 rgba(255,255,255,0.08);
}
 
/* ══ ICON CARDS ══ */
.icon-grid { display: grid; gap: 8px; }
.icon-grid.grid-cat    { grid-template-columns: repeat(2, 1fr); }
.icon-grid.grid-items  { grid-template-columns: repeat(2, 1fr); }
.icon-grid.grid-items-3 { grid-template-columns: repeat(3, 1fr); }
 
/* 💡 Hauteur fixe (44px) + troncature une ligne : fusionné ici depuis un
   patch qui vivait auparavant ~500 lignes plus bas ("ICON CARDS —
   hauteur fixe, label tronqué sur une ligne"), qui redéfinissait déjà
   .icon-card/.ic-label une 2e fois au lieu de compléter cette règle. */
.icon-card {
  display: flex; flex-direction: row; align-items: center;
  gap: 9px; padding: 11px 13px;
  border-radius: 12px;
  border: 0.5px solid var(--sep-opaque);
  background: var(--bg-grouped); cursor: pointer;
  transition: var(--theme-transition);
  height: 44px;
  min-height: unset;
  overflow: hidden;
}
.icon-card:active { transform: scale(.95); }
.icon-card.active {
  background: var(--bg-grouped-2);
  border-color: var(--ic-color, #636366);
  box-shadow: 0 0 0 1.5px var(--ic-color, #636366), 0 2px 10px rgba(0,0,0,0.05);
}
.icon-card.active .ic-label { color: var(--ic-color, var(--label)); font-weight: 600; }
.ic-ico { width: 22px; height: 22px; flex-shrink: 0; color: var(--ic-color, var(--label-3)); }
.ic-ico svg { width: 100%; height: 100%; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ══════════════════════════════════════════════
   ICÔNE DE REPLI GÉNÉRIQUE — core.js::getIconHtml() insère
   <span class="icon-fallback-generic" data-icon-fallback="…"> à la
   place d'un <svg> quand l'item_id/category_id reçu (souvent depuis
   /budget-items-full) n'a pas d'icône dédiée dans SVGS/SVGS_ITEMS.
   Dessinée en pur CSS (pas de nouvel asset SVG à charger/maintenir) :
   un anneau pointillé + un point central, qui hérite de `currentColor`
   — donc automatiquement teintée par le conteneur (.solid-xxx,
   --ic-color, --pc-color…) qui l'englobe, exactement comme un <svg>
   normal l'aurait fait. Visuellement distincte des icônes "connues"
   (pointillé plutôt que trait plein) pour signaler qu'il s'agit d'un
   repli, sans être alarmante. Un seul jeu de règles, appliqué à TOUS
   les conteneurs d'icône de l'app (grid, entry, carte propriété…). ══ */
.icon-fallback-generic,
.ic-ico .icon-fallback-generic,
.entry-ico .icon-fallback-generic,
.prop-card-ico .icon-fallback-generic {
  display: block;
  width: 100%; height: 100%;
  box-sizing: border-box;
  border-radius: 50%;
  border: 1.6px dashed currentColor;
  opacity: 0.75;
  position: relative;
}
.icon-fallback-generic::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 26%; height: 26%;
  min-width: 3px; min-height: 3px;
  background: currentColor;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.ic-label {
  font-size: 12px; font-weight: 500; color: var(--label-3); line-height: 1.2;
  transition: color .15s, font-weight .15s;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0; flex: 1 1 0;
}

/* ══ ICON TINT — fond teinté (12%) + couleur d'accent ══ */
.tint-blue   { background: rgba(99,179,237,0.15);  color: var(--pastel-blue-text); }
.tint-green  { background: rgba(110,231,183,0.15); color: var(--pastel-green-text); }
.tint-orange { background: rgba(253,186,116,0.15); color: var(--pastel-orange-text); }
.tint-indigo { background: rgba(196,181,253,0.15); color: var(--pastel-purple-text); }

/* ══ ICON SOLID — RENOMMÉ EN INTERNE MAIS DEVENU "PASTEL" ══
   ⚠️ Les noms de classes .solid-xxx sont conservés tels quels (utilisés
   partout en JS : core.js::getItemSolidClass, _ITEM_SOLID_CLASSES,
   admin.js::_dbCategoryIconClass, propriete.js::_bankDetailItemClassFor…)
   — seul le RENDU change : fond teinté (color-mix 16%) + icône/texte de
   la couleur d'accent, au lieu d'un fond plein + icône blanche. Même
   esprit que .tint-xxx ci-dessus, mais calculé dynamiquement via
   color-mix() pour coller exactement aux 12 couleurs de la palette JS
   (au lieu de valeurs rgba() figées par couleur). */
.solid-blue   { background: color-mix(in srgb, var(--blue) 16%, transparent);   color: var(--blue); }
.solid-green  { background: color-mix(in srgb, var(--green) 16%, transparent);  color: var(--green); }
.solid-orange { background: color-mix(in srgb, var(--orange) 16%, transparent); color: var(--orange); }
.solid-red    { background: color-mix(in srgb, var(--red) 16%, transparent);    color: var(--red); }
.solid-indigo { background: color-mix(in srgb, var(--indigo) 16%, transparent); color: var(--indigo); }
.solid-purple { background: color-mix(in srgb, var(--purple) 16%, transparent); color: var(--purple); }
.solid-teal   { background: color-mix(in srgb, var(--teal) 16%, transparent);   color: var(--teal); }

/* ── Variantes supplémentaires — alignent la palette CSS des icônes
   (.solid-xxx) sur la palette JS élargie à 12 couleurs
   (core.js::_CATEGORY_COLOR_PALETTE / _ITEM_COLOR_PALETTE), pour que
   getItemSolidClass() puisse attribuer une classe distincte à chaque
   poste/catégorie au-delà des 7 couleurs système d'origine. Basées sur
   les tokens pastel-*-text déjà définis en tête de fichier (dark/light
   gérés automatiquement, comme le reste des tokens du thème). ── */
.solid-pastel-blue   { background: var(--pastel-blue-bg);   color: var(--pastel-blue-text); }
.solid-pastel-green  { background: var(--pastel-green-bg);  color: var(--pastel-green-text); }
.solid-pastel-orange { background: var(--pastel-orange-bg); color: var(--pastel-orange-text); }
.solid-pastel-purple { background: var(--pastel-purple-bg); color: var(--pastel-purple-text); }
.solid-pastel-pink   { background: var(--pastel-pink-bg);   color: var(--pastel-pink-text); }

/* ── Variantes combinées .entry-ico.solid-* — nécessaires car .entry-ico
   (définie plus bas dans ce fichier, section TIMELINE) a la même
   spécificité (0,1,0) qu'un .solid-xxx seul : à spécificité égale, la
   règle la PLUS BASSE dans le fichier gagne, donc .entry-ico écrasait
   silencieusement la couleur du poste (fond neutre --bg-grouped-2 au
   lieu de la couleur attendue). Une sélecteur à deux classes a une
   spécificité supérieure (0,2,0) et gagne dans tous les cas, quel que
   soit l'ordre des règles. Même rendu pastel que les classes .solid-xxx
   seules ci-dessus (fond teinté + icône colorée). ── */
.entry-ico.solid-blue   { background: color-mix(in srgb, var(--blue) 16%, transparent);   color: var(--blue); }
.entry-ico.solid-green  { background: color-mix(in srgb, var(--green) 16%, transparent);  color: var(--green); }
.entry-ico.solid-orange { background: color-mix(in srgb, var(--orange) 16%, transparent); color: var(--orange); }
.entry-ico.solid-red    { background: color-mix(in srgb, var(--red) 16%, transparent);    color: var(--red); }
.entry-ico.solid-indigo { background: color-mix(in srgb, var(--indigo) 16%, transparent); color: var(--indigo); }
.entry-ico.solid-purple { background: color-mix(in srgb, var(--purple) 16%, transparent); color: var(--purple); }
.entry-ico.solid-teal   { background: color-mix(in srgb, var(--teal) 16%, transparent);   color: var(--teal); }
.entry-ico.solid-pastel-blue   { background: var(--pastel-blue-bg);   color: var(--pastel-blue-text); }
.entry-ico.solid-pastel-green  { background: var(--pastel-green-bg);  color: var(--pastel-green-text); }
.entry-ico.solid-pastel-orange { background: var(--pastel-orange-bg); color: var(--pastel-orange-text); }
.entry-ico.solid-pastel-purple { background: var(--pastel-purple-bg); color: var(--pastel-purple-text); }
.entry-ico.solid-pastel-pink   { background: var(--pastel-pink-bg);   color: var(--pastel-pink-text); }
 
/* ══ AMOUNT FIELD ══ */
.amount-wrap { position: relative; }
.amount-wrap input { padding-left: 2rem; font-size: 17px; font-weight: 700; }
.amount-wrap .currency {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  color: var(--blue); font-weight: 700; font-size: 16px;
  transition: color 0.25s ease;
}
 
/* ══ PRIMARY BUTTON ══ */
.btn-primary {
  width: 100%; background: var(--blue); color: #fff;
  border: none; border-radius: 12px; padding: 14px;
  font-size: 15px; font-weight: 700; cursor: pointer;
  font-family: inherit;
  box-shadow: 0 4px 14px rgba(10,132,255,0.25);
  transition: opacity 0.15s, transform 0.1s, background-color 0.25s;
}
.btn-primary:active { transform: scale(0.97); opacity: 0.85; }
.btn-primary:disabled { background: var(--bg-grouped-2); color: var(--label-3); cursor: not-allowed; box-shadow: none; }
 
/* ══ BILAN ENCART ══ */
.encart-bloc {
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex; flex-direction: column; gap: 10px;
  margin-bottom: 14px;
  transition: var(--theme-transition);
}
/* Dans un conteneur home-wrap (flex + gap:12px), le margin-bottom
   s'additionnerait au gap — on le neutralise pour un espacement uniforme. */
.home-wrap .encart-bloc { margin-bottom: 0; }
.bilan-ligne-principale { display: flex; justify-content: space-between; align-items: flex-end; }
.bilan-titre-group { display: flex; flex-direction: column; gap: 3px; }
.bilan-titre { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.8px; color: var(--label-3); }
.bilan-montant {
  font-size: 20px; font-weight: 800; color: var(--label);
  font-variant-numeric: tabular-nums; letter-spacing: -0.5px; line-height: 1;
}
.bilan-montant.c-red   { color: var(--red) !important; }
.bilan-montant.c-green { color: var(--green) !important; }
.bilan-detail {
  font-size: 10.5px; color: var(--label-2); font-weight: 500;
  font-variant-numeric: tabular-nums;
  background: var(--fill-4); padding: 4px 9px;
  border-radius: 6px; border: 0.5px solid var(--sep);
  transition: var(--theme-transition);
}
 
/* ══ REPARTITION TABLE ══ */
.repartition-table {
  display: flex; width: 100%;
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 8px; overflow: hidden;
  transition: var(--theme-transition);
}
.repartition-cell { flex: 1; padding: 9px 12px; display: flex; flex-direction: column; gap: 3px; }
.repartition-cell:not(:last-child) { border-right: 0.5px solid var(--sep-opaque); }
/* 💡 Couleurs de fond + label déplacées et fusionnées plus bas dans ce
   fichier (section "repartition-cell colors") — ce bloc portait
   auparavant sa propre version (opacité .05, sans couleur de label) qui
   était entièrement écrasée par la version plus complète (opacité .08 +
   couleur de label) définie plus loin. Les deux ont été fusionnées en
   un seul jeu de règles pour éviter la duplication silencieuse. */
.repartition-label { font-size: 9px; text-transform: uppercase; font-weight: 700; letter-spacing: 0.5px; }
.repartition-valeur { font-size: 15px; font-weight: 700; color: var(--label); font-variant-numeric: tabular-nums; }
 
/* ══ FILTER CHIPS ══ */
.filter-scroll { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 6px; margin-bottom: 14px; scrollbar-width: none; }
.filter-scroll::-webkit-scrollbar { display: none; }
.filter-chip {
  flex-shrink: 0; font-size: 12px; font-weight: 600;
  padding: 6px 14px; border-radius: 20px;
  border: 0.5px solid var(--sep-opaque);
  background: var(--bg-grouped); color: var(--label-3);
  cursor: pointer; white-space: nowrap; font-family: inherit;
  transition: var(--theme-transition);
}
.filter-chip.active { background: rgba(10,132,255,0.12); border-color: var(--blue); color: var(--blue); }
 
/* ══ TARIFS — bouton suppression d'année ══ */
.h-tarifs-year-del {
  order: 1;
  width: 24px; height: 24px; border-radius: 7px;
  background: rgba(255,69,58,0.1);
  border: 0.5px solid rgba(255,69,58,0.25);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0; margin-left: 8px;
  transition: background 0.12s;
}
.h-tarifs-year-del:active { background: rgba(255,69,58,0.2); }
.h-tarifs-year-del svg { stroke: var(--red); fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
 
/* ══ TIMELINE ══ */
.month-group { margin-bottom: 20px; }
.month-group-title {
  font-size: 10px; font-weight: 700; color: var(--label-3);
  text-transform: uppercase; letter-spacing: 0.8px;
  margin: 14px 0 8px 2px;
  display: flex; align-items: center; gap: 8px;
}
.month-group-title::after { content: ''; flex: 1; height: 0.5px; background: var(--sep-opaque); margin-left: 6px; }
 
.year-group { margin-bottom: 8px; }
.year-group-title {
  font-size: 15px; font-weight: 800; color: var(--label);
  letter-spacing: -0.3px;
  margin: 0px 0 2px 2px;
  display: flex; align-items: center; gap: 10px;
}
.year-group-title::after { content: ''; flex: 1; height: 1.5px; background: var(--sep-opaque); margin-left: 8px; }
 
.entry-list { display: flex; flex-direction: column; gap: 7px; }
.entry-item {
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px; padding: 11px 13px;
  display: flex; align-items: center; gap: 10px;
  transition: var(--theme-transition);
}
.entry-item.is-prev {
  border-color: rgba(90,200,250,0.15);
  background: linear-gradient(90deg, var(--bg-grouped) 0%, rgba(90,200,250,0.02) 100%);
}
.entry-ico {
  width: 32px; height: 32px; border-radius: 8px;
  background: var(--bg-grouped-2);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  transition: var(--theme-transition);
}
.entry-ico svg { width: 15px; height: 15px; stroke: currentColor; fill: none; stroke-width: 2; }
.entry-body { flex: 1; min-width: 0; }
.entry-title { font-weight: 600; font-size: 13.5px; display: flex; align-items: center; justify-content: space-between; width: 100%; color: var(--label); }
.entry-text-wrap { display: inline-flex; align-items: center; min-width: 0; flex: 1; margin-right: 4px; }
.entry-label-span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.entry-sub { font-size: 11px; color: var(--label-3); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.entry-libelle { font-size: 12px; color: var(--label-2); margin-top: 1px; }
.entry-right { text-align: right; flex-shrink: 0; margin-left: 8px; }
.entry-amount { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; }
 
.c-red   { color: var(--red)    !important; }
.c-green { color: var(--green)  !important; }
.c-cyan  { color: var(--orange) !important; }
 
/* ══ STATUS BADGES ══ */
.status-badge {
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  padding: 2px 7px; border-radius: 6px;
  display: inline-flex; align-items: center;
  margin-left: 7px; flex-shrink: 0;
}
.badge-is-prev { background: rgba(255,159,10,0.12); color: var(--orange); border: 0.5px solid rgba(255,159,10,0.25); }
.badge-is-real { background: rgba(10,132,255,0.12); color: var(--blue); border: 0.5px solid rgba(10,132,255,0.25); }
 
/* ══ SYNTHÈSE — breakdown catégorie dépliable, détail par poste ══
   NB : <details> natif a été abandonné ici — son contenu fermé n'est
   pas seulement display:none, il est totalement absent du rendu tant
   que [open] n'est pas présent (comportement intégré au navigateur,
   pas une règle CSS qu'on peut surclasser), donc impossible à animer
   en transition. On reprend ici le même pattern .open/.show déjà
   utilisé ailleurs dans le projet (.modal-overlay.show, .drawer.show)
   : un conteneur cliquable en JS (toggleCatBreakdown), avec une classe
   .open qui pilote la transition grid-template-rows. ══ */
.cat-breakdown-card {
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px;
  overflow: hidden;
  transition: var(--theme-transition);
}
.cat-breakdown-card .entry-item {
  border: none; border-radius: 0; background: transparent;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  box-shadow: inset 0 -0.5px 0 0 transparent;
  transition: box-shadow 0.22s ease;
}
.cat-breakdown-card.open .entry-item {
  box-shadow: inset 0 -0.5px 0 0 var(--sep-opaque);
}
.cat-breakdown-chevron {
  flex-shrink: 0; margin-left: 8px; color: var(--label-4);
  transition: transform 0.22s cubic-bezier(.4,0,.2,1);
}
.cat-breakdown-card.open .cat-breakdown-chevron { transform: rotate(90deg); }
 
.poste-list {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  overflow: hidden;
  contain: layout;
  transition: grid-template-rows 0.28s cubic-bezier(.4,0,.2,1), opacity 0.2s ease;
}
.cat-breakdown-card.open .poste-list {
  grid-template-rows: 1fr;
  opacity: 1;
}
/* 💡 .poste-list-inner est l'enfant DIRECT de la grid row animée — il ne
   doit porter AUCUN padding propre : même à grid-template-rows:0fr, le
   padding d'un enfant direct peut rester partiellement visible (résidu
   de hauteur), certains moteurs (WebKit/WebView) réservant l'espace du
   padding indépendamment de la hauteur de ligne calculée à 0fr. Le vrai
   padding est donc reporté sur .poste-list-content, un niveau plus bas. */
.poste-list-inner { min-height: 0; overflow: hidden; }
.poste-list-content { display: flex; flex-direction: column; padding: 4px 13px 10px; }
.poste-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0;
  border-bottom: 0.5px solid var(--sep);
  font-variant-numeric: tabular-nums;
}
.poste-row:last-child { border-bottom: none; }
.poste-date {
  flex-shrink: 0;
  width: 56px;
  font-size: 11.5px; font-weight: 500; color: var(--label-3);
  font-variant-numeric: tabular-nums;
}
.poste-label {
  flex: 1; min-width: 0;
  font-size: 12.5px; font-weight: 500; color: var(--label-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.poste-pct {
  font-size: 10.5px; font-weight: 600; color: var(--label-4);
  flex-shrink: 0; width: 32px; text-align: right;
}
.poste-amount {
  font-size: 12.5px; font-weight: 700; color: var(--label);
  flex-shrink: 0; min-width: 64px; text-align: right;
}
 
/* ══ DONUT ══ */
.chart-wrap {
  background: var(--bg-grouped); border: 0.5px solid var(--sep-opaque);
  border-radius: 12px; padding: 14px;
  display: flex; align-items: center; gap: 14px; margin-bottom: 18px;
  transition: var(--theme-transition);
}
.chart-wrap svg { flex-shrink: 0; }
.legend { display: flex; flex-direction: column; gap: 7px; flex: 1; }
.legend-item { display: flex; align-items: center; gap: 7px; font-size: 12px; }
.legend-dot  { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.legend-name { flex: 1; color: var(--label-3); }
.legend-val  { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--label); }
 
/* ══ EMPTY ══ */
.empty { text-align: center; padding: 48px 16px; color: var(--label-3); }
.empty-ico { margin-bottom: 8px; display: flex; justify-content: center; }
.empty-ico svg { width: 30px; height: 30px; stroke: currentColor; fill: none; stroke-width: 1.5; }
 
/* ══ SECTION TITLE ══ */
.section-title {
  font-size: 10px; font-weight: 700; color: var(--label-3);
  text-transform: uppercase; letter-spacing: 0.8px;
  margin: 18px 0 9px 2px;
}
 
/* ══ TOAST ══ */
.toast {
  position: fixed; bottom: calc(env(safe-area-inset-bottom) + 80px); left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--bg-grouped-2); border: 0.5px solid var(--sep-opaque);
  color: var(--label); padding: 10px 20px;
  border-radius: 24px; font-weight: 600; font-size: 13px;
  opacity: 0; transition: all .3s cubic-bezier(.4,0,.2,1), border-color 0.25s;
  pointer-events: none;
  /* 💡 était 1200 — trop bas : passait SOUS .saisie-sheet/.saisie-sheet-overlay
     (9985/9986, cf. sheet Documents, sheet d'affectation multiple, sheet
     Saisie…) et sous .doc-preview-panel (9986), rendant tout showToast()
     invisible (mais bien déclenché) pendant que l'un de ces panneaux est
     ouvert. Doit rester au-dessus de tout le reste de l'UI. */
  z-index: 9990;
  box-shadow: 0 8px 24px rgba(0,0,0,0.15);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
 
/* ══ MODAL ══ */
.modal-overlay {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0,0,0,0.3); /* Alégé pour le mode clair */
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  z-index: 2000; display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity 0.22s cubic-bezier(.4,0,.2,1);
}
.modal-overlay.show { opacity: 1; pointer-events: auto; }
.modal-container {
  background: var(--bg-grouped); border: 0.5px solid var(--sep-opaque);
  width: 82%; max-width: 310px;
  border-radius: 16px; padding: 20px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.15);
  transform: translateY(15px) scale(0.97);
  transition: transform 0.22s cubic-bezier(.4,0,.2,1), background-color 0.25s;
}
.modal-overlay.show .modal-container { transform: translateY(0) scale(1); }
.modal-title    { font-size: 15px; font-weight: 700; margin-bottom: 3px; color: var(--label); }
.modal-footer   { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 18px; }

.btn-modal {
  border: none; padding: 12px; border-radius: 10px;
  font-size: 13px; font-weight: 600; cursor: pointer;
  text-align: center; font-family: inherit;
  transition: opacity 0.15s, transform 0.1s;
}
.btn-modal:active { transform: scale(0.97); opacity: 0.85; }
.btn-modal.cancel { background: var(--fill); color: var(--label); }
.btn-modal.save   { background: var(--blue); color: #fff; font-weight: 700; box-shadow: 0 2px 8px rgba(10,132,255,0.2); }
.btn-modal.save-green { background: var(--green); color: #000; font-weight: 700; box-shadow: 0 2px 8px rgba(50,215,75,0.2); }
.btn-modal.delete { background: var(--red); color: #fff; font-weight: 700; box-shadow: 0 2px 8px rgba(255,69,58,0.2); }
 
/* ══ DELETE CONFIRMATION MODAL ══ */
.delete-modal-overlay {
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
  background: rgba(0,0,0,0.3);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  z-index: 3000; display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s cubic-bezier(.4,0,.2,1);
}
.delete-modal-overlay.show { opacity: 1; pointer-events: auto; }
.delete-modal-container {
  background: var(--bg-grouped); border: 0.5px solid var(--sep-opaque);
  width: 78%; max-width: 290px;
  border-radius: 16px; overflow: hidden;
  box-shadow: 0 12px 40px rgba(0,0,0,0.15);
  transform: scale(0.92) translateY(10px);
  transition: transform 0.22s cubic-bezier(.34,1.56,.64,1), background-color 0.25s;
}
.delete-modal-overlay.show .delete-modal-container { transform: scale(1) translateY(0); }
.delete-modal-body {
  padding: 22px 18px 14px;
  display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px;
}
.delete-modal-icon {
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(255,69,58,0.1); border: 0.5px solid rgba(255,69,58,0.2);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 4px;
}
.delete-modal-icon svg { width: 20px; height: 20px; stroke: var(--red); fill: none; stroke-width: 2.2; }
.delete-modal-title { font-size: 15px; font-weight: 700; color: var(--label); }
.delete-modal-label {
  font-size: 12px; color: var(--label-3); line-height: 1.4;
  max-width: 220px; word-break: break-word;
}
.delete-modal-amount { font-size: 22px; font-weight: 800; color: var(--red); font-variant-numeric: tabular-nums; letter-spacing: -0.5px; }
.delete-modal-actions {
  display: flex; flex-direction: column;
  border-top: 0.5px solid var(--sep-opaque);
}
.delete-action-btn {
  padding: 15px; font-size: 14px; font-weight: 600;
  border: none; background: transparent; cursor: pointer;
  font-family: inherit; transition: background 0.12s, color 0.25s;
}
.delete-action-btn:active { background: var(--fill-4); }
.delete-action-btn.confirm-delete {
  color: var(--red); font-weight: 700;
  border-bottom: 0.5px solid var(--sep-opaque);
}
.delete-action-btn.cancel-delete { color: var(--blue); }
 
/* ══ ENTRY ITEM ACTION BTNS ══ */
.entry-actions { display: flex; align-items: center; gap: 6px; margin-left: 8px; flex-shrink: 0; }
.entry-action-btn {
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; border: 0.5px solid var(--sep-opaque);
  background: var(--bg-grouped-2);
  transition: background 0.12s, transform 0.1s, border-color 0.25s;
}
.entry-action-btn:active { transform: scale(0.88); }
.entry-action-btn svg { width: 12px; height: 12px; fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.entry-edit-btn svg { stroke: var(--blue); }
.entry-del-btn { background: rgba(255,69,58,0.06); border-color: rgba(255,69,58,0.15); }
.entry-del-btn svg { stroke: var(--red); }
 
/* ══ BOTTOM TAB BAR ══
   💡 EN FLUX (flex), plus en position:fixed — évite le décalage visuel
   au retour d'inactivité (verrouillage écran / app en arrière-plan
   longtemps) où env(safe-area-inset-bottom) pouvait être mal recalculé
   par Safari pour un élément fixed, donnant l'impression que la tabbar
   "saute" au réveil. En flux, le moteur de layout recalcule sa hauteur
   à chaque reflow naturel, sans dépendre d'une mesure JS ponctuelle.
   order:1 la place après #apps-container (elle est avant lui dans le
   DOM, voir index.html) ; flex-shrink:0 garantit qu'elle garde sa
   taille naturelle même si le contenu au-dessus déborde. */
.tabbar {
  position: static;
  order: 1;
  bottom: 0;
  flex-shrink: 0;
  display: flex; z-index: 1100;
  background: var(--bg-grouped); /* 💡 Corrigé pour le mode clair */
  /*backdrop-filter: blur(32px); -webkit-backdrop-filter: blur(32px);*/
  border-top: 0.5px solid var(--sep);
  padding-top: 6px;
  padding-bottom: env(safe-area-inset-bottom, 16px);
  padding-left:  max(0px, env(safe-area-inset-left));
  padding-right: max(0px, env(safe-area-inset-right));
  transition: var(--theme-transition);
  /* 💡 Isole la tabbar sur sa propre couche de composition GPU : sans
     ça, le backdrop-filter doit être recalculé à chaque frame quand le
     contenu derrière elle change de hauteur (ex: transition
     grid-template-rows du dépliement par poste sur Synthèse), ce qui
     donne un effet de scintillement visible le temps de l'animation. */
  transform: translateZ(0);
  will-change: transform;
}

.tabbar-item {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
  padding: 3px 0; cursor: pointer;
  color: var(--label-3);
  transition: color 0.18s;
}
.tabbar-item svg { width: 19px; height: 19px; stroke: currentColor; fill: none; stroke-width: 2; }
.tabbar-item span { font-size: 9.5px; font-weight: 600; letter-spacing: 0.1px; }
.tabbar-item.active { color: var(--blue); }
.tabbar-item.active svg { stroke-width: 2.2; }

/* ── Indicateur de sélection — segment coloré posé exactement sur la
   ligne de bordure supérieure de la tabbar (.tabbar { border-top:
   0.5px; padding-top: 6px; }), au lieu d'une pastille flottant au-dessus
   de l'icône. .tabbar-item est positionné à top:6.5px de l'extérieur de
   .tabbar (border + padding) — on remonte le pseudo-élément de cette
   même valeur pour qu'il colle pile sur le border-top. Scopé à la
   tabbar mobile (bas d'écran) : la version desktop (sidebar ≥768px)
   garde son propre indicateur latéral existant plus bas dans ce
   fichier. ── */
.tabbar-item { position: relative; }
@media (max-width: 767px) {
  .tabbar-item.active::before {
    content: '';
    position: absolute;
    top: -6.5px; left: 0; right: 0;
    width: 100%; height: 1px;
    border-radius: 0;
    background: var(--pastel-blue-text);
    opacity: 0.6;
  }
  #tab-home.active::before      { background: var(--pastel-blue-text); }
  #tab-equilibre.active::before { background: var(--pastel-green-text); }
  #tab-propriete.active::before { background: var(--pastel-orange-text); }
  #tab-admin.active::before     { background: var(--pastel-purple-text); }
}
 
/* ══ OWNER TYPE FIELD — toujours visible, occupe sa place même masquée ══ */
.owner-type-field-wrap {
  overflow: hidden;
  opacity: 1;
  transition: opacity 0.2s ease;
}
.owner-type-field-wrap.owner-field-hidden {
  opacity: 0;
  pointer-events: none;
  visibility: hidden; /* invisible mais occupe toujours la place */
}
 
/* ══ POSTES BUDGÉTAIRES — hauteur fixe, zéro layout shift ══ */
#subject-chips-container {
  min-height: 100px;
}
 
/* ══ SUBJECT FIELD WRAP — hauteur réservée même pendant le chargement ══ */
.subject-field-wrap {
  min-height: 96px; /* 2 rangées × 44px + 8px gap */
}
 
/* ══ ERROR BANNER ══ */
.error-banner {
  background: rgba(255,69,58,0.10);
  border: 0.5px solid rgba(255,69,58,0.35);
  border-radius: 12px;
  padding: 12px 14px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-bottom: 14px;
  animation: errorSlideIn 0.22s cubic-bezier(.4,0,.2,1);
}
@keyframes errorSlideIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.error-banner-ico {
  width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0;
  background: rgba(255,69,58,0.15);
  display: flex; align-items: center; justify-content: center;
  margin-top: 1px;
}
.error-banner-ico svg { width: 15px; height: 15px; stroke: var(--red); fill: none; stroke-width: 2.2; }
.error-banner-body { flex: 1; min-width: 0; }
.error-banner-title { font-size: 13px; font-weight: 700; color: var(--red); margin-bottom: 3px; }
.error-banner-detail {
  font-size: 12px; color: var(--label-3);
  line-height: 1.5; word-break: break-word;
}
.error-banner-close {
  width: 22px; height: 22px; border-radius: 6px; flex-shrink: 0; cursor: pointer;
  background: rgba(255,69,58,0.12);
  border: 0.5px solid rgba(255,69,58,0.2);
  display: flex; align-items: center; justify-content: center;
  transition: background 0.12s;
}
.error-banner-close:active { background: rgba(255,69,58,0.25); }
.error-banner-close svg { width: 10px; height: 10px; stroke: var(--red); fill: none; stroke-width: 2.5; }
 
/* ══════════════════════════════════════════════
   ÉQUILIBRE — Coquille flex full height (mobile)
   Synthèse / Historique / Saisie : même motif que
   #app-home pour bénéficier du scroll interne et
   du correctif clavier iOS (100dvh)
   ══════════════════════════════════════════════ */
#app-equilibre {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* ══════════════════════════════════════════════
   HOLIDU — Layout pages
   Réutilise les composants Équilibre (encart-bloc,
   repartition-table, nav-item, etc.)
   ══════════════════════════════════════════════ */
 
/* App calendrier : flex column full height — le contenu scrollable
   utilise désormais .content.content-segmented comme les autres apps
   à segmented control (3 sous-pages en .app-section, plus de classe
   spécifique au calendrier). */
#app-calendrier {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
 
/* repartition-cell colors */
.repartition-cell.r-red   { background: rgba(255,69,58,0.08); }
.repartition-cell.r-red   .repartition-label { color: var(--red); }
.repartition-cell.r-green { background: rgba(50,215,75,0.08); }
.repartition-cell.r-green .repartition-label { color: var(--green); }
.repartition-cell.r-blue  { background: rgba(10,132,255,0.08); }
.repartition-cell.r-blue  .repartition-label { color: var(--blue); }
.repartition-cell.r-orange { background: rgba(255,159,10,0.08); }
.repartition-cell.r-orange .repartition-label { color: var(--orange); }
 
/* Calendrier Holidu — réutilise les classes day-wrapper etc */
.month-table { width: 100%; border-collapse: separate; border-spacing: 0; padding: 6px 8px 12px; background: var(--bg-grouped); }
.month-table th { color: var(--label-3); font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.4px; padding: 8px 0; border-bottom: 0.5px solid var(--sep); width: 14.28%; text-align: center; }
.month-table td { text-align: center; padding: 2px 1px; width: 14.28%; vertical-align: middle; }
.month-table td.empty { background: transparent; }
 
.day-wrapper {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 3px; height: 40px; width: 40px;
  margin: 0 auto; border-radius: 8px;
  background: var(--bg-grouped);
  border: 0.5px solid transparent;
  transition: background 0.12s, transform 0.1s, opacity 0.15s;
}
#holidu-calendar-grid.edit-mode .day-wrapper { cursor: pointer; border-color: var(--sep); }
#holidu-calendar-grid.edit-mode .day-wrapper:active { transform: scale(0.88); }
 
.day-num { font-weight: 600; font-size: 13px; color: var(--label); font-variant-numeric: tabular-nums; line-height: 1; }
.past-day     { color: var(--label-4) !important; font-weight: 400; }
.prop-day-text { color: var(--blue) !important; font-weight: 700; }
 
.dot { width: 5px; height: 5px; border-radius: 50%; display: block; flex-shrink: 0; }
.dot-available        { background: var(--green); }
.dot-unavailable      { background: var(--red); }
.dot-unavailable-prop { background: var(--blue); }
.dot-past             { background: var(--fill-3); }
.dot-manual           { border: 1.5px solid rgba(255,255,255,0.4); width: 6px; height: 6px; }
 
.day-wrapper[data-status="available"],
.day-wrapper[data-status="available-manual"]    { background: rgba(50,215,75,0.12);  border-color: rgba(50,215,75,0.22); }
.day-wrapper[data-status="unavailable"],
.day-wrapper[data-status="unavailable-manual"]  { background: rgba(255,69,58,0.12);  border-color: rgba(255,69,58,0.22); }
.day-wrapper[data-status="unavailable-prop"]    { background: rgba(10,132,255,0.12); border-color: rgba(10,132,255,0.22); }
.day-wrapper[data-status="unknown"]             { background: rgba(120,120,128,0.08); border-color: transparent; }
.past-day-wrapper:not([data-status="unknown"])  { opacity: 0.50; border-color: transparent !important; }
.past-day-wrapper[data-status="unknown"]        { background: rgba(120,120,128,0.06); }
 
/* Réservations */
.resa-card {
  background: var(--bg-grouped); border: 0.5px solid var(--sep-opaque);
  border-radius: 12px; padding: 13px 14px; margin-bottom: 8px;
  position: relative; overflow: hidden;
}
.resa-card::before { content: ''; position: absolute; top: 0; left: 0; bottom: 0; width: 3px; }
.resa-card.past::before    { background: var(--label-4); }
.resa-card.future::before  { background: var(--orange); }
.resa-card.ongoing::before { background: var(--blue); }
.resa-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; }
.resa-dates { font-size: 14px; font-weight: 700; color: var(--label); letter-spacing: -0.2px; }
.resa-badge { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; padding: 2px 7px; border-radius: 6px; display: inline-flex; align-items: center; flex-shrink: 0; }
.badge-past    { background: var(--fill-3); color: var(--label-3); border: 0.5px solid var(--sep); }
.badge-future  { background: rgba(255,159,10,0.14); color: var(--orange); border: 0.5px solid rgba(255,159,10,0.3); }
.badge-ongoing { background: rgba(10,132,255,0.14);  color: var(--blue);  border: 0.5px solid rgba(10,132,255,0.3); }
.resa-stats { display: flex; background: var(--bg-grouped-2); border-radius: 8px; overflow: hidden; border: 0.5px solid var(--sep-opaque); }
.resa-stat { flex: 1; padding: 7px 10px; display: flex; flex-direction: column; gap: 2px; }
.resa-stat + .resa-stat { border-left: 0.5px solid var(--sep-opaque); }
.resa-stat-label { font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.4px; color: var(--label-3); }
.resa-stat-val   { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--label); }
 
/* Save btn */
.h-save-btn {
  display: none; position: fixed;
  bottom: calc(var(--topbar-h, 50px) + env(safe-area-inset-bottom) + 12px); right: 14px;
  padding: 12px 20px; background: var(--blue); color: #fff;
  border-radius: 12px; font-weight: 700; font-size: 13px;
  border: none; cursor: pointer; z-index: 1050;
  box-shadow: 0 4px 14px rgba(10,132,255,0.35); font-family: inherit;
}
 
/* ══ HOLIDU calendrier — month-group title badge ══ */
#holidu-page-calendrier .month-group-title,
#routers-content .month-group-title {
  /* Pas de ::after line — la table suit directement */
}
#holidu-page-calendrier .month-group-title::after,
#routers-content .month-group-title::after,
summary.h-month-summary .month-group-title::after {
  display: none;
}
/* month-table th scoped pour ne pas écraser les autres th */
#holidu-page-calendrier .month-table th {
  color: var(--label-3);
  font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.4px;
  padding: 8px 0;
  border-bottom: 0.5px solid var(--sep);
  width: 14.28%; text-align: center;
}
#holidu-page-calendrier .month-table td {
  text-align: center; padding: 2px 1px;
  width: 14.28%; vertical-align: middle;
}
 
/* ══ HOLIDU — encart full / collapsed au scroll ══ */
 
.h-encart-full {
  overflow: hidden;
  margin-bottom: 14px;
}
 
/* ══ HOLIDU — réservations dépliables dans l'encart ══ */
 
.h-resa-details {
  background: var(--bg-grouped-2);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 10px;
  overflow: hidden;
}
.h-resa-details summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 9px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--label-2);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.h-resa-details summary::marker,
.h-resa-details summary::-webkit-details-marker { display: none; }
 
.h-resa-count {
  font-size: 11px;
  font-weight: 700;
  color: var(--label-3);
  background: var(--fill-3);
  padding: 2px 8px;
  border-radius: 10px;
}
 
.h-resa-liste {
  padding: 4px 12px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 200px;
  overflow-y: auto;
}
 
/* ══════════════════════════════════════════════
   ROUTEURS — Visualiseur statut UptimeRobot
   Design 100% Équilibre — zéro style custom
   ══════════════════════════════════════════════ */
 
/* Layout app */
#app-routers {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* App admin — titre simple (Accueil, Condo, Admin) */
#app-admin {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* App condo — titre simple (Accueil, Condo, Admin) */
#app-condo {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* App base de données */
#app-database {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
/* 💡 La page Base de données / Postes budgétaires (menu, tables, édition,
   relevé bancaire) n'a pas de contenu propre dans le segment du topbar
   (juste la date, cf. #topbar-seg-database) — le titre de chaque vue est
   rendu directement dans le contenu (cf. admin.js, gabarit
   .year-group-title identique au titre "Administration"). On réduit
   simplement le padding-top réservé par le shell. */
#app-database .content,
#app-database .content-segmented { padding-top: 14px !important; }

/* App documents — explorateur Google Drive */
#app-documents {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
#app-documents .content { padding-top: 14px !important; }

/* ══════════════════════════════════════════════
   DOCUMENT PREVIEW — panneau plein écran (Admin ▸
   Documents), iframe embarqué vers Google Drive
   /preview — aucune redirection hors-app.
   ══════════════════════════════════════════════ */
.doc-preview-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.6);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  z-index: 9985;
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s cubic-bezier(.4,0,.2,1);
}
.doc-preview-overlay.show { opacity: 1; pointer-events: auto; }

.doc-preview-panel {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 9986;
  background: var(--bg-grouped);
  display: flex; flex-direction: column;
  transform: translateY(16px) scale(0.98);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.28s cubic-bezier(.32,0,.67,0), opacity 0.22s ease;
}
.doc-preview-panel.show {
  transform: translateY(0) scale(1);
  opacity: 1;
  pointer-events: auto;
  transition: transform 0.32s cubic-bezier(.22,1,.36,1), opacity 0.2s ease;
}

.doc-preview-header {
  flex-shrink: 0;
  display: flex; align-items: center; gap: 10px;
  padding: calc(env(safe-area-inset-top) + 12px) 14px 12px;
  border-bottom: 0.5px solid var(--sep-opaque);
  background: var(--bg-grouped);
}
.doc-preview-title {
  flex: 1; min-width: 0;
  font-size: 14.5px; font-weight: 700; color: var(--label);
  letter-spacing: -0.2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.doc-preview-action-btn {
  flex-shrink: 0;
  width: 32px; height: 32px; border-radius: 9px;
  background: var(--fill-3);
  border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--label-2);
  text-decoration: none;
  transition: background 0.12s, transform 0.1s;
}
.doc-preview-action-btn:active { background: var(--fill-2); transform: scale(0.9); }

.doc-preview-body {
  flex: 1; min-height: 0;
  background: #202124; /* fond neutre Drive, évite le flash blanc au chargement */
  position: relative;
  display: flex; align-items: center; justify-content: center;
}
.doc-preview-body iframe {
  width: 100%; height: 100%; border: none; display: block;
}

/* 💡 Centrage ABSOLU (pas seulement flex) : loading/fallback restent
   toujours parfaitement centrés dans .doc-preview-body quel que soit
   l'état des autres enfants (pdf-container/iframe présents mais
   display:none dans le DOM) — retirés du flux flex normal, ils ne
   peuvent plus se retrouver poussés à gauche par un autre enfant. */
.doc-preview-loading,
.doc-preview-fallback {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: max-content;
  max-width: 85%;
}
.doc-preview-loading {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  color: rgba(255,255,255,0.75);
  font-size: 12.5px; font-weight: 500;
}
.doc-preview-spinner {
  width: 30px; height: 30px; border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,0.18);
  border-top-color: rgba(255,255,255,0.85);
  animation: docPreviewSpin 0.75s linear infinite;
}
@keyframes docPreviewSpin { to { transform: rotate(360deg); } }

.doc-preview-fallback {
  flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; text-align: center; padding: 24px;
  color: rgba(255,255,255,0.75);
  max-width: 320px;
}
.doc-preview-fallback-ico { color: rgba(255,255,255,0.4); }
.doc-preview-fallback p { font-size: 13px; line-height: 1.5; margin: 0; }

/* ── Boutons zoom (entête) — même gabarit que .doc-preview-action-btn,
   simplement un contenu texte ("+"/"−") plutôt qu'une icône SVG. ── */
.doc-preview-zoom-group {
  display: flex; align-items: center; gap: 4px;
  flex-shrink: 0;
}
.doc-preview-zoom-btn {
  font-size: 18px; font-weight: 700; line-height: 1;
  font-family: inherit;
}

/* ── Conteneur PDF.js — fenêtre fixe (overflow:hidden), le déplacement
   et le zoom sont gérés entièrement en JS (translate/scale appliqués
   au calque .doc-preview-pdf-stage, cf. admin.js::_docPdfApplyView),
   PAS via le scroll natif du navigateur : ce mélange s'est montré peu
   fiable (zoom qui ne persistait pas, déplacement à un doigt inopérant).
   touch-action:none laisse la totalité du geste tactile à notre JS
   (Pointer Events), sans interférence du navigateur. ── */
.doc-preview-pdf-container {
  width: 100%; height: 100%;
  overflow: hidden;
  position: relative;
  touch-action: none;
  /* 💡 PAS de user-select:none ici — sur iOS (WKWebView/PWA en
     particulier), un ancêtre en user-select:none peut empêcher un
     descendant de repasser en user-select:text via CSS (bug WebKit
     connu : la valeur "none" gagne indépendamment de la spécificité),
     ce qui rendait inopérants les overrides posés sur .textLayer
     ci-dessous. Le seul contenu réellement "sélectionnable" dans ce
     conteneur EST le calque texte (le <canvas> ne l'a jamais été de
     toute façon) — cette règle défensive était donc à la fois inutile
     et contre-productive. */
}
.doc-preview-pdf-stage {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  box-sizing: border-box;
  padding: 14px 12px 24px;
  transform-origin: 0 0;
  will-change: transform;
}
.doc-preview-pdf-page {
  display: block;
  margin: 0 auto 12px;
  border-radius: 3px;
  box-shadow: 0 1px 6px rgba(0,0,0,0.25);
  background: #fff; /* fond blanc pendant le rendu, avant que le canvas ne soit peint */
}
.doc-preview-pdf-page:last-child { margin-bottom: 0; }

/* ── Text layer PDF.js — spans transparents superposés au canvas de
   chaque page (cf. documents.js::_docPdfRenderPage), pour rendre le
   texte sélectionnable. Le canvas seul n'est qu'une image de pixels :
   sans cette couche, rien n'est sélectionnable dans un PDF affiché. ── */
.textLayer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  line-height: 1;
  transform-origin: 0 0;
  z-index: 3;
}
.textLayer span, .textLayer br {
  color: transparent;
  position: absolute;
  white-space: pre;
  cursor: text;
  transform-origin: 0% 0%;
  user-select: text;
  -webkit-user-select: text;
}
.textLayer ::selection { background: rgba(10,132,255,.35); }
/* 💡 iOS — .doc-preview-pdf-container (ci-dessus) pose touch-action:none
   pour que les gestes personnalisés (pinch/pan au doigt, Pointer Events)
   pilotent seuls le zoom/déplacement du PDF, sans interférence du scroll
   natif. Mais touch-action ne suit pas le user-select d'un descendant :
   un enfant doit poser SON PROPRE touch-action pour réactiver un geste
   natif (ici, l'appui long → sélection de texte iOS), sinon il reste
   supprimé sur toute la zone malgré le user-select:text ci-dessus.
   -webkit-touch-callout:default réautorise en plus le menu contextuel
   (Copier…) qui accompagne la sélection sur iOS Safari. */
.textLayer,
.textLayer span,
.textLayer br {
  touch-action: auto !important;
  -webkit-touch-callout: default !important;
}

@media (min-width: 700px) {
  .doc-preview-panel { left: 220px; }
}

/* App bilan détaillé par propriété (donuts + transactions) */
#app-bankdetail {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* ── Tables de l'explorateur "Base de données" ── */
.db-table-meta { display: flex; justify-content: flex-end; margin-bottom: 10px; }
.db-table-count {
  font-size: 10.5px; color: var(--label-2); font-weight: 500;
  font-variant-numeric: tabular-nums;
  background: var(--fill-4); padding: 4px 9px;
  border-radius: 6px; border: 0.5px solid var(--sep);
}
.db-table-scroll {
  overflow: auto;
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px;
  background: var(--bg-grouped);
  max-width: 100%;
  -webkit-overflow-scrolling: touch;
}
.db-table { border-collapse: collapse; width: 100%; font-size: 11.5px; white-space: nowrap; }
.db-table th, .db-table td {
  padding: 8px 11px;
  border-bottom: 0.5px solid var(--sep-opaque);
  text-align: left;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--label-2);
}
.db-table th {
  background: var(--bg-grouped-2);
  color: var(--label-3);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 9.5px;
  letter-spacing: 0.5px;
  position: sticky; top: 0;
}
.db-table tbody tr:last-child td { border-bottom: none; }
.db-table tbody tr:nth-child(odd) { background: rgba(255,255,255,0.015); }
.db-cell-empty { color: var(--label-4); }
 
/* Panneaux moniteurs */
.rt-panel        { display: block; }
.rt-panel-hidden { display: none; }
 
/* Grille calendrier — 5 colonnes de jours */
.rt-calendar-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 5px;
  padding: 10px 0 4px;
}
 
/* Cellule jour */
.rt-day-cell {
  background: var(--bg-grouped-2);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 10px;
  padding: 6px 3px;
  display: flex; flex-direction: column;
  align-items: center; gap: 4px;
}
.rt-day-cell.rt-today {
  border-color: var(--blue);
  background: rgba(10,132,255,0.08);
}
.rt-day-num {
  font-size: 11px; font-weight: 700;
  color: var(--label-2); font-variant-numeric: tabular-nums; line-height: 1;
}
.rt-day-cell.rt-today .rt-day-num { color: var(--blue); font-weight: 800; }
 
/* Grille pings 2×4 */
.rt-ping-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(4, 1fr);
  grid-auto-flow: column;
  gap: 2px;
  width: 100%;
}
.rt-ping {
  height: 10px; border-radius: 2px;
  background: var(--fill-3);
  display: flex; align-items: center; justify-content: center;
  font-size: 7px; font-weight: 700;
  color: var(--label-4);
  line-height: 10px; font-variant-numeric: tabular-nums;
}
.rt-ping.rt-up    { background: var(--green);  color: rgba(0,0,0,0.75); }
.rt-ping.rt-down  { background: var(--red);    color: #fff; box-shadow: 0 0 4px rgba(255,69,58,0.5); }
.rt-ping.rt-pause { background: var(--orange); color: rgba(0,0,0,0.75); }
 
/* Badge % UP — réutilise .status-badge */
.rt-pct-badge {
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
  padding: 2px 7px; border-radius: 6px;
  display: inline-flex; align-items: center; flex-shrink: 0;
}
.rt-pct-badge.pct-green  { background: rgba(50,215,75,0.14);  color: var(--green);  border: 0.5px solid rgba(50,215,75,0.3); }
.rt-pct-badge.pct-orange { background: rgba(255,159,10,0.14); color: var(--orange); border: 0.5px solid rgba(255,159,10,0.3); }
.rt-pct-badge.pct-red    { background: rgba(255,69,58,0.14);  color: var(--red);    border: 0.5px solid rgba(255,69,58,0.3); }
.rt-pct-badge.pct-empty  { background: var(--fill-3);         color: var(--label-3); border: 0.5px solid var(--sep); }

/* Badge "N incident(s)" — mois passés avec interruption détectée */
.rt-incident-badge {
  font-size: 9px; font-weight: 700;
  color: var(--red);
  background: rgba(255,69,58,0.12);
  border: 0.5px solid rgba(255,69,58,0.25);
  padding: 2px 6px; border-radius: 6px;
}
 
.rt-chevron-ico {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--fill-3);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0; transition: transform 0.22s;
}
.rt-chevron-ico svg { width: 8px; height: 8px; }
 
/* Légende */
.rt-legend-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 8px;
}
.rt-legend-item {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-grouped); border: 0.5px solid var(--sep-opaque);
  border-radius: 8px; padding: 8px 10px;
  font-size: 11px; font-weight: 500; color: var(--label-2);
}
.rt-legend-dot {
  width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0;
  background: var(--fill-3);
}
.rt-legend-dot.rt-up    { background: var(--green);  box-shadow: 0 0 4px rgba(50,215,75,0.5); }
.rt-legend-dot.rt-down  { background: var(--red);    box-shadow: 0 0 4px rgba(255,69,58,0.5); }
.rt-legend-dot.rt-pause { background: var(--orange); }
 
/* ══ HOLIDU — mois pliables (details/summary) ══ */
 
details.h-month-details { margin-bottom: 20px; }
details.h-month-details:not([open]) { opacity: 0.65; }
 
summary.h-month-summary {
  display: flex; align-items: center;
  cursor: pointer; list-style: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
  margin: 14px 0 8px 2px;
}
summary.h-month-summary::-webkit-details-marker { display: none; }
/* month-group-title inside the summary fills all space */
summary.h-month-summary .month-group-title {
  flex: 1;
  /* cancel the ::after pseudo-line — chevron takes its place */
  pointer-events: none;
}
summary.h-month-summary .month-group-title::after { display: none; }
 
/* Chevron rotation */
details.h-month-details[open] > summary.h-month-summary .rt-chevron-ico { transform: rotate(180deg); }
 
.h-month-body { margin-top: 4px; }
 
/* ══════════════════════════════════════════════
   HOME — Page d'accueil widgets
   ══════════════════════════════════════════════ */
 
#app-home {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
 
.home-wrap { display: flex; flex-direction: column; gap: 12px; }
 
.home-greeting {
  padding: 4px 2px 6px;
}
.home-greeting-text {
  font-size: 22px; font-weight: 800; letter-spacing: -0.5px; color: var(--label);
}
.home-greeting-date {
  font-size: 12px; color: var(--label-3); margin-top: 3px; font-weight: 500;
}
 
/* Widget card */
.home-widget {
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 20px;
  overflow: hidden;
  cursor: pointer;
  transition: transform 0.12s, opacity 0.12s, box-shadow 0.15s;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 2px 12px rgba(0,0,0,0.06);
}
.home-widget:active { transform: scale(0.975); opacity: 0.85; }

/* Couleur accent par widget via attribut data-widget */
.home-widget[data-widget="comptabilite"] { border-color: rgba(99,179,237,0.25); }
.home-widget[data-widget="calendrier"]  { border-color: rgba(110,231,183,0.25); }
.home-widget[data-widget="condo"]       { border-color: rgba(253,186,116,0.25); }
.home-widget[data-widget="routers"]     { border-color: rgba(196,181,253,0.25); }
 
.home-widget-header {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 14px 12px;
  border-bottom: 0.5px solid var(--sep-opaque);
  /* Gradient pastel très subtil dans l'en-tête */
  background: linear-gradient(135deg, rgba(139,92,246,0.04) 0%, transparent 60%);
}
.home-widget-ico {
  width: 38px; height: 38px; border-radius: 12px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.home-widget-ico svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 2; }
.home-widget-title-group { flex: 1; }
.home-widget-title { font-size: 14px; font-weight: 700; color: var(--label); letter-spacing: -0.2px; }
.home-widget-sub   { font-size: 11px; color: var(--label-3); margin-top: 1px; }
.home-widget-arrow { margin-left: auto; flex-shrink: 0; color: var(--label-4); }
.home-widget-arrow svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.5; }
 
.home-widget-body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 10px; }
 
.home-kpi-row { display: flex; gap: 0; min-height: calc(8px * 2 + 9px * 1.3 + 3px + 15px * 1.3); }
.home-kpi {
  flex: 1; display: flex; flex-direction: column; gap: 3px;
  padding: 9px 10px;
  background: var(--pastel-purple-bg); border: 0.5px solid rgba(139,92,246,0.18);
  border-radius: 0;
}
.home-kpi:first-child { border-radius: 8px 0 0 8px; }
.home-kpi:last-child  { border-radius: 0 8px 8px 0; }
.home-kpi:only-child  { border-radius: 8px; }
.home-kpi + .home-kpi { border-left: none; }
.home-kpi-label { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px; color: var(--label-3); line-height: 1.3; }
.home-kpi-value { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -0.3px; color: var(--label); line-height: 1.3; }
.home-kpi-sub   { font-size: 10px; color: var(--label-3); font-variant-numeric: tabular-nums; line-height: 1.3; }

/* ── Pills KPI colorées selon le sens du montant ── */
/* Le fond + label prennent la teinte pastel du montant affiché */
.home-kpi:has(.c-red) {
  background: var(--pastel-pink-bg);
  border-color: rgba(236,72,153,0.2);
}
.home-kpi:has(.c-red) .home-kpi-label { color: var(--pastel-pink-text); }

.home-kpi:has(.c-green) {
  background: var(--pastel-green-bg);
  border-color: rgba(16,185,129,0.2);
}
.home-kpi:has(.c-green) .home-kpi-label { color: var(--pastel-green-text); }

.home-kpi:has(.c-orange) {
  background: var(--pastel-orange-bg);
  border-color: rgba(245,158,11,0.2);
}
.home-kpi:has(.c-orange) .home-kpi-label { color: var(--pastel-orange-text); }

.home-kpi:has(.c-blue) {
  background: var(--pastel-blue-bg);
  border-color: rgba(59,130,246,0.2);
}
.home-kpi:has(.c-blue) .home-kpi-label { color: var(--pastel-blue-text); }
 
.c-orange { color: var(--orange) !important; }
 
/* Next reservation */
.home-next-resa {
  background: var(--pastel-teal-bg); border: 0.5px solid rgba(20,184,166,0.2);
  border-radius: 10px; padding: 9px 12px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: calc(9px * 2 + 13px * 1.3);
}
.home-next-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.3; }
.home-next-dates { font-size: 13px; font-weight: 700; color: var(--label); font-variant-numeric: tabular-nums; line-height: 1.3; }
 
/* Supprimer la ligne ::after des year-group-title à l'intérieur des widgets home */
.home-widget-header .year-group-title::after { display: none; }
/* Supprimer margin top des year-group-title dans les widgets */
.home-widget-header .year-group-title { margin: 0 !important; }
/* section-title sans margin dans widget header */
.home-widget-header .section-title { margin: 2px 0 0 !important; }
 
/* Réservations supprimées de l'encart */
.h-resa-details { display: none !important; }

/* ══════════════════════════════════════════════
   ADMIN HUB — Grille style "Listes intelligentes"
   iOS Reminders : cartes 2 colonnes avec icône
   colorée + badge compteur + titre
   ══════════════════════════════════════════════ */

.admin-hub { display: flex; flex-direction: column; gap: 0; padding: 0px 0 0; }

/* ── Conserver les styles existants .reminders-* pour compatibilité ── */
.reminders-list {
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 12px;
  overflow: hidden;
}
.reminders-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; min-height: 52px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 0.12s;
}
.reminders-row:active { background: var(--fill-4); }
.reminders-row + .reminders-row { border-top: 0.5px solid var(--sep-opaque); }
.reminders-row-label { flex: 1; min-width: 0; font-size: 15px; font-weight: 500; color: var(--label); display: flex; flex-direction: column; justify-content: center; }

/* ══ DOCUMENTS — nom de fichier tronqué + badge extension ══ */
.doc-file-label-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.doc-file-name {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--label);
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1 1 auto;
}
.doc-ext-badge {
  flex-shrink: 0;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--label-3);
  background: var(--fill-3);
  border: 0.5px solid var(--sep);
  border-radius: 5px;
  padding: 1px 5px;
}

/* ══ Relevé bancaire — sélection multiple (Admin ▸ Base de données) ══
   Checkbox circulaire à DROITE de la ligne (le label/infos occupe tout
   l'espace à gauche, pas d'icône catégorie à gauche pour cette table). */
.bank-row .reminders-row-label { display: flex; flex-direction: column; min-width: 0; }
.bank-row .db-menu-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bank-row-ben { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; font-size: 13px; font-weight: 500; color: var(--label); }
/* ── Montant + checkbox regroupés à droite, en dehors du bloc texte —
   ce groupe est un enfant direct de .bank-row (comme .reminders-row-label),
   il hérite donc de align-items:center (.reminders-row) et se centre sur
   TOUTE la hauteur de la carte, quel que soit le nombre de sous-lignes
   (date/motif/catégorie) affichées sous le bénéficiaire. ── */
.bank-row-amount-check { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.bank-row-amount { flex-shrink: 0; font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.bank-row-amount.c-green { color: var(--green); }
.bank-row-amount.c-red   { color: var(--red); }
.bank-row-checkbox {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-grouped-2);
  border: 1.5px solid var(--sep-opaque);
  transition: background 0.15s, border-color 0.15s;
}
.bank-row-checkbox.checked {
  background: var(--blue);
  border-color: var(--blue);
}

/* ══════════════════════════════════════════════
   BULK ASSIGN — panneaux pré-rendus
   Les panneaux masqués utilisent visibility:hidden
   + height:0 + overflow:hidden inline (JS).
   Les wrappers n'ont PAS de overflow:hidden —
   les bordures des icon-cards ne sont jamais rognées.
   .bulk-items-flex : items sur la même ligne (flex
   wrap) plutôt qu'une grid rigide N colonnes.
   ══════════════════════════════════════════════ */
/* Wrappers des 3 niveaux du sheet d'affectation multiple — position:relative
   est statique (toujours nécessaire dès que des .bulk-panel absolus y sont
   injectés), seule la hauteur en px reste pilotée en JS (dépend du nombre
   de catégories/postes/types chargés dynamiquement depuis l'API). */
.bulk-assign-wrapper {
  position: relative;
}

/* ══ BULK-ASSIGN — champ "Type de contribution" : toujours présent dans
   le flux du .form-grid (jamais display:none), pour ne jamais faire
   varier la hauteur totale du sheet selon que le poste sélectionné a
   ou non des allowed_contribution_types. Même convention que
   .owner-type-field-wrap ci-dessus : visibility:hidden + opacity:0,
   la place reste réservée. ══ */
.bulk-pointage-field-hidden {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}

/* ══ BULK-ASSIGN PANELS — superposition absolue dans un wrapper
   à hauteur fixe (fixée en JS, car dépendante des données chargées :
   nombre de catégories/postes/types varie par propriété). Le panneau
   lui-même est toujours en position:absolute + top/left/right:0 —
   c'est ce qui permet de changer de panneau visible sans jamais
   modifier la hauteur du wrapper parent (zéro reflow / zéro "saut"
   du bottom sheet à la sélection). Seule la classe .bulk-panel-hidden
   est ajoutée/retirée en JS (jamais de style inline). ══ */
.bulk-panel {
  position: absolute;
  top: 0; left: 0; right: 0;
}
/* Utilitaire générique masquage — pas seulement pour .bulk-panel :
   réutilisé aussi pour le champ "Type de contribution"
   (#bulk-assign-pointage-field, un .field classique, pas un .bulk-panel). */
.bulk-panel-hidden {
  display: none !important;
}

/* ══════════════════════════════════════════════
   PROGRESS BAR — utilisée par la page Condo
   (répartition réalisée / payée)
   ══════════════════════════════════════════════ */
.pct-bar-bg { height: 4px; background: var(--sep-opaque); border-radius: 2px; }
.pct-bar    { height: 4px; border-radius: 2px; }

/* ══ DATABASE — menu-liste et navigation ══
   Label + sous-titre dans les lignes reminders-row,
   badge compteur aligné à droite avant le chevron.    */
.db-menu-label { font-size: 15px; font-weight: 500; color: var(--label); line-height: 1.2; }
.db-menu-sub   { font-size: 11px; color: var(--label-3); margin-top: 2px; font-weight: 400; }

/* ══════════════════════════════════════════════
   SIDEBAR LAYOUT — ≥ 768px
   Tabbar → sidebar gauche fixe, contenu à droite
   Design modernisé — aucun changement JS
   ══════════════════════════════════════════════ */

@media (min-width: 700px) {

  /* ── Root ── */
  body {
    flex-direction: row;
    overflow: hidden;
    height: 100vh;
    height: 100dvh;
    height: 100dvh;
  }

  /* ── Login centré, pleine largeur ── */
  .login-screen { width: 100vw; }

    /* ── SÉCURITÉ DE SOUCHE SUR L'INJECTION JAVASCRIPT ── */
  #mobile-apps-root {
    display: flex !important;
    flex-direction: row !important;
    flex: 1 !important;
    height: 100% !important;
    max-height: 100% !important;
    overflow: hidden !important;
  }

  /* ══════════════════════════════════════════════
     TABBAR → SIDEBAR GAUCHE
  ══════════════════════════════════════════════ */
  .tabbar {
    /* Position et dimensions */
    position: static;
    order: -1;               /* toujours à gauche */
    flex-direction: column;
    flex-shrink: 0;
    width: 220px;
    height: 100%;

    /* Couleurs et fond */
    background: #0a0a0b;
    border-top: none;
    border-right: 0.5px solid rgba(255,255,255,0.07);

    /* Espacement */
    padding: 0;
    padding-top: calc(env(safe-area-inset-top) + 28px);
    padding-bottom: calc(env(safe-area-inset-bottom) + 20px);

    /* Layout interne */
    justify-content: flex-start;
    align-items: stretch;
    gap: 1px;
    overflow-y: auto;
    scrollbar-width: none;
    z-index: 10;

    /* Effet glassmorphism subtil */
    box-shadow: 1px 0 10px rgba(0,0,0,0.2);
  }
  .tabbar::-webkit-scrollbar { display: none; }

  /* Logo en header */
  .tabbar::before {
    content: 'Il Fiordo';
    display: block;
    flex-shrink: 0;
    font-size: 18px;
    font-weight: 800;
    letter-spacing: -0.5px;
    color: var(--label);
    padding: 0 20px 22px;
    margin-bottom: 6px;
    border-bottom: 0.5px solid rgba(255,255,255,0.06);
    background: linear-gradient(135deg, #fff 30%, var(--blue));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }

  /* ── Items de navigation ── */
  .tabbar-item {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    align-items: center;
    gap: 10px;

    padding: 9px 14px 9px 16px;
    margin: 0 10px;
    width: calc(100% - 20px);
    border-radius: 10px;

    font-size: 13px;
    font-weight: 500;
    letter-spacing: -0.1px;
    color: rgba(235,235,245,0.45);

    cursor: pointer;
    position: relative;
    transition: background 0.15s, color 0.15s;
  }

  .tabbar-item:hover {
    background: rgba(255,255,255,0.05);
    color: rgba(235,235,245,0.75);
  }

  .tabbar-item.active {
    background: rgba(10,132,255,0.14);
    color: #fff;
    font-weight: 600;
  }

  /* Indicateur actif — trait gauche */
  .tabbar-item.active::before {
    content: '';
    position: absolute;
    left: -10px; top: 50%;
    transform: translateY(-50%);
    width: 3px; height: 20px;
    background: var(--blue);
    border-radius: 0 3px 3px 0;
    box-shadow: 0 0 8px rgba(10,132,255,0.6);
  }

  .tabbar-item svg {
    width: 15px; height: 15px;
    flex-shrink: 0;
    opacity: 0.7;
    transition: opacity 0.15s;
  }
  .tabbar-item:hover svg  { opacity: 0.9; }
  .tabbar-item.active svg { opacity: 1; }

  .tabbar-item span {
    font-size: 13px;
    font-weight: inherit;
  }

  /* ── Zone apps ── */
  #app-home,
  #app-equilibre,
  #app-calendrier,
  #app-condo,
  #app-admin,
  #app-routers,
  #app-database {
    flex: 1;
    min-width: 0;
    height: 100%;
    overflow: hidden;
  }

  /* ── Le segment control vit désormais dans #topbar-segment-slot, à
     l'intérieur du header fixe unique (#app-header-bar) — plus de
     .navbar-fixed séparée à repositionner par app en desktop, le
     header couvre déjà toute la largeur du viewport (sidebar comprise)
     dans les deux modes. #app-content-layout gère seul le padding-top
     compensatoire via --topbar-h (voir index.html). ── */

  /* ── Annuler le padding-bottom mobile (tabbar fixe en bas) ── */
  .content {
    padding-bottom: 28px !important;
  }

  /* ── Scrollbars discrètes ── */
  .content {
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.1) transparent;
  }

  /* ── Toast et boutons flottants ── */
  .toast    { bottom: 24px; }
  .h-save-btn { bottom: 24px; }

  /* ── Largeur confortable et centrée pour tout le contenu desktop ── */
  .content {
    max-width: 1080px;
    margin-left: auto;
    margin-right: auto;
    width: 100%;
  }

}

/* ══════════════════════════════════════════════
   BOTTOM SHEET — Saisie écriture
   Slide-up depuis le bas, overlay derrière
   ══════════════════════════════════════════════ */

.saisie-sheet-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /* 💡 Au-dessus de .navbar-fixed (z-index:100, mais isolée sur sa propre
     couche GPU via translateZ(0)/will-change:transform) : un z-index plus
     élevé ne suffit pas toujours à passer par-dessus un élément qui a son
     propre contexte d'empilement composé — on lui donne donc aussi un
     transform/will-change pour rivaliser explicitement au même niveau. */
  z-index: 9985; /* 💡 était 2100 — doit dépasser .app-header-bar (index.html, z-index:9980) */
  transform: translateZ(0);
  will-change: transform;
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s cubic-bezier(.4,0,.2,1);
}
.saisie-sheet-overlay.show { opacity: 1; pointer-events: auto; }

.saisie-sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  /* 💡 Idem : z-index élevé + contexte d'empilement propre (transform)
     pour garantir le passage par-dessus .navbar-fixed dans tous les
     moteurs de rendu (WebView Scriptable comprise).
     💡 était 2101 — doit dépasser .app-header-bar (index.html, z-index:9980)
     ET rester au-dessus de .saisie-sheet-overlay (9985 ci-dessus). */
  z-index: 9986;
  background: var(--bg-grouped);
  border-top: 0.5px solid var(--sep-opaque);
  border-radius: 20px 20px 0 0;
  /* 💡 Recouvre désormais aussi la zone de la navbar fixe (le sheet
     passe AU-DESSUS d'elle, il ne lui laisse plus sa bande réservée en
     haut) — seule la topbar reste hors du sheet. */
  height: calc(100dvh - var(--topbar-h));
  max-height: calc(100dvh - var(--topbar-h));
  display: flex; flex-direction: column;
  transform: translateY(100%);
  transition: transform 0.38s cubic-bezier(.32,0,.67,0);
}
.saisie-sheet.show {
  transform: translateY(0) translateZ(0);
  transition: transform 0.38s cubic-bezier(.22,1,.36,1);
}

/* Handle pill */
.saisie-sheet-header {
  display: flex; align-items: center; justify-content: center;
  padding: 10px 14px 8px; position: relative;
  border-bottom: 0.5px solid var(--sep-opaque);
  flex-shrink: 0;
}
.saisie-sheet-handle {
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--fill-3);
  position: absolute; top: 9px; left: 50%; transform: translateX(-50%);
}
.saisie-sheet-title {
  font-size: 15px; font-weight: 700; color: var(--label);
  letter-spacing: -0.2px; margin-top: 12px;
}
.saisie-sheet-close {
  position: absolute; right: 14px; top: 50%;
  transform: translateY(-50%);
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--fill-3);
  border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--label-2);
  transition: background 0.12s, transform 0.1s;
}
.saisie-sheet-close:active { background: var(--fill-2); transform: translateY(-50%) scale(0.88); }

/* Scrollable body */
.saisie-sheet-body {
  flex: 1; overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 16px 14px 4px;
  scrollbar-width: none;
  background: var(--bg);
}
.saisie-sheet-body::-webkit-scrollbar { display: none; }

/* Footer avec bouton */
.saisie-sheet-footer {
  padding: 10px 14px;
  padding-bottom: calc(env(safe-area-inset-bottom) + 10px);
  border-top: 0.5px solid var(--sep-opaque);
  flex-shrink: 0;
  background: var(--bg-grouped);
}

/* ══ FAB ROND + ÉCRITURE — fixe au-dessus de la tabbar ══ */
.fab-ecriture {
  position: fixed;
  right: 18px;
  bottom: calc(var(--topbar-h, 50px) + env(safe-area-inset-bottom) + 14px);
  z-index: 1050;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--blue);
  border: none;
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(10,132,255,0.45), 0 1px 4px rgba(0,0,0,0.3);
  transition: transform 0.15s cubic-bezier(.34,1.56,.64,1), box-shadow 0.15s, background 0.12s;
  -webkit-tap-highlight-color: transparent;
}
.fab-ecriture:active {
  transform: scale(0.9);
  box-shadow: 0 2px 8px rgba(10,132,255,0.3);
}
.fab-ecriture svg { stroke: #fff; flex-shrink: 0; }

/* ── FAB retour — bas gauche, même style que fab-ecriture ── */
.fab-back {
  position: fixed;
  left: 18px;
  bottom: calc(var(--topbar-h, 50px) + env(safe-area-inset-bottom) + 14px);
  z-index: 1050;
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--bg-grouped-2);
  border: 0.5px solid var(--sep-opaque);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 4px 20px rgba(0,0,0,0.35), 0 1px 4px rgba(0,0,0,0.2);
  transition: transform 0.15s cubic-bezier(.34,1.56,.64,1), box-shadow 0.15s, background 0.12s;
  -webkit-tap-highlight-color: transparent;
  color: var(--blue);
}
.fab-back:active {
  transform: scale(0.9);
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
  background: var(--bg-grouped-3);
}
.fab-back svg { stroke: currentColor; flex-shrink: 0; }

/* ── Desktop : positionner après la sidebar ── */
@media (min-width: 700px) {
  .saisie-sheet {
    left: 220px;
    max-width: 560px;
    border-radius: 20px 20px 0 0;
  }
  .saisie-sheet-overlay { left: 220px; }
  .fab-ecriture {
    right: 24px;
    bottom: 24px;
  }
  .fab-back {
    left: calc(220px + 18px);
    bottom: 24px;
  }
}

/* ══ FAB MENU — PDF + Excel + Nouvelle écriture (Historique) ══
   Déploiement vertical (pile droite) au-dessus du bouton principal,
   icônes seules — pas de libellé texte à côté de chaque mini-bouton. */
.fab-menu {
  position: fixed;
  right: 18px;
  bottom: calc(var(--topbar-h, 50px) + env(safe-area-inset-bottom) + 14px);
  z-index: 1050;
  width: 52px;
  height: 52px;
}

/* Le bouton rond principal — ancré en place, sert de pivot à la pile */
.fab-menu .fab-ecriture {
  position: absolute;
  inset: 0;
  right: auto; left: 0; top: 0; bottom: auto;
  transition: transform 0.2s cubic-bezier(.4,0,.2,1), box-shadow 0.2s;
}
.fab-menu.open .fab-ecriture {
  box-shadow: 0 4px 24px rgba(10,132,255,0.6), 0 1px 4px rgba(0,0,0,0.3);
}

/* ── Icônes du bouton principal : 3 points ↔ croix (crossfade + rotation) ── */
.fab-ico { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(0deg) scale(1); transition: opacity 0.22s ease, transform 0.28s cubic-bezier(.34,1.56,.64,1); }
.fab-ico-menu  { opacity: 1; }
.fab-ico-close { opacity: 0; transform: translate(-50%,-50%) rotate(-45deg) scale(0.4); }
.fab-menu.open .fab-ico-menu  { opacity: 0; transform: translate(-50%,-50%) rotate(45deg) scale(0.4); }
.fab-menu.open .fab-ico-close { opacity: 1; transform: translate(-50%,-50%) rotate(0deg) scale(1); }

/* ── Effet circulaire (ripple) au pivot, à l'ouverture ── */
.fab-ico-ripple {
  position: absolute; inset: 0; border-radius: 50%;
  background: rgba(255,255,255,0.35);
  transform: scale(0); opacity: 0;
  pointer-events: none;
}
.fab-menu.open .fab-ico-ripple {
  animation: fabRipple 0.5s cubic-bezier(.25,.8,.4,1);
}
@keyframes fabRipple {
  0%   { transform: scale(0);   opacity: 0.55; }
  70%  { transform: scale(2.6); opacity: 0.12; }
  100% { transform: scale(3.2); opacity: 0; }
}

/* ── Panneau du menu — carte arrondie détachée du bouton principal,
   contient tous les mini-boutons empilés verticalement. C'est ce
   panneau (et non chaque bouton séparément) qui s'anime à l'ouverture,
   ce qui donne un cadre net et continu autour de l'ensemble plutôt que
   des boutons flottant individuellement collés au FAB principal. ── */
#fab-menu-items {
  position: absolute;
  right: 4px;
  bottom: 64px; /* détaché du bouton principal (52px + 12px d'espace net) */
  display: flex;
  flex-direction: column-reverse; /* item[0] (ex: PDF) reste le plus proche du bouton principal, en bas du panneau */
  align-items: center;
  gap: 6px;
  padding: 8px;
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 16px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.22), 0 1px 4px rgba(0,0,0,0.12);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  transform-origin: bottom center;
  opacity: 0;
  transform: translateY(8px) scale(0.85);
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.26s cubic-bezier(.34,1.56,.64,1);
}
.fab-menu.open #fab-menu-items {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.fab-menu-item {
  display: flex;
  align-items: center;
  justify-content: center;
}

.fab-mini-btn {
  width: 44px; height: 44px;
  border-radius: 50%;
  border: none;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0,0,0,0.18);
  transition: transform 0.15s cubic-bezier(.34,1.56,.64,1);
  -webkit-tap-highlight-color: transparent;
  flex-shrink: 0;
}
.fab-mini-btn:active { transform: scale(0.9); }
.fab-mini-btn.fab-mini-pdf    { background: var(--teal); }
.fab-mini-btn.fab-mini-pdf svg { stroke: #fff; }
.fab-mini-btn.fab-mini-xlsx    { background: var(--green); }
.fab-mini-btn.fab-mini-xlsx svg { stroke: #fff; }
.fab-mini-btn.fab-mini-green  { background: var(--green); }
.fab-mini-btn.fab-mini-green svg { stroke: #fff; }
.fab-mini-btn.fab-mini-add    { background: var(--blue); }
.fab-mini-btn.fab-mini-add svg { stroke: #fff; }
.fab-mini-btn.fab-mini-teal   { background: var(--teal); }
.fab-mini-btn.fab-mini-teal svg { stroke: #fff; }
.fab-mini-btn.fab-mini-orange { background: var(--orange); }
.fab-mini-btn.fab-mini-orange svg { stroke: #fff; }
.fab-mini-btn.fab-mini-purple { background: var(--purple); }
.fab-mini-btn.fab-mini-purple svg { stroke: #fff; }

@media (min-width: 700px) {
  .fab-menu { right: 24px; bottom: 24px; }
}

/* ══ HISTORIQUE — totaux débit/crédit par mois ══ */
.month-totaux {
  display: inline-flex; align-items: center; gap: 6px;
  flex-shrink: 0;
}
.month-total-debit,
.month-total-credit {
  font-size: 10px; font-weight: 700;
  padding: 2px 7px; border-radius: 6px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.1px;
}
.month-total-debit  { background: rgba(255,69,58,0.10);  color: var(--red);   border: 0.5px solid rgba(255,69,58,0.2); }
.month-total-credit { background: rgba(50,215,75,0.10);  color: var(--green); border: 0.5px solid rgba(50,215,75,0.2); }
.month-progressif {
  font-size: 10px; font-weight: 800;
  padding: 2px 7px; border-radius: 6px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.1px;
  border: 0.5px solid var(--sep);
}
.month-prog-debit  { background: rgba(255,69,58,0.06);  color: var(--red);   border-style: dashed; }
.month-prog-credit { background: rgba(50,215,75,0.06);  color: var(--green); border-style: dashed; }
/* Quand les totaux sont présents, la ligne ::after ne s'étire plus entre le titre et les totaux */
.month-group-title:has(.month-totaux)::after { flex: 0; width: 8px; }

/* ══ BILAN DÉTAILLÉ — montant par groupe encadré à droite, somme par
   catégorie sur la ligne du titre (propriete.js::_renderBankDetailYear) ══ */
.year-group-title:has(.bd-group-total)::after,
.month-group-title:has(.bd-cat-total)::after { flex: 0; width: 8px; }

/* Pastille montant colorée (vert positif / rouge négatif) + cadre —
   réutilisée pour les totaux groupe/catégorie/poste (voir
   propriete.js::_bankDetailAmountChip). flex-shrink:0 garantit qu'elle
   ne se compresse jamais et reste plaquée à droite dans les conteneurs
   flex parents (.year-group-title, .month-group-title, .entry-title). */
.bd-amount-chip {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  padding: 3px 9px;
  border-radius: 7px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.1px;
  border: 0.5px solid transparent;
  line-height: 1.3;
}
.bd-amount-chip.bd-amt-pos {
  background: rgba(50,215,75,0.10);
  color: var(--green);
  border-color: rgba(50,215,75,0.22);
}
.bd-amount-chip.bd-amt-neg {
  background: rgba(255,69,58,0.10);
  color: var(--red);
  border-color: rgba(255,69,58,0.22);
}

/* Chevron du poste (Propriété ▸ Bilan détaillé) — resserré (au lieu du
   margin-left:8px par défaut de .cat-breakdown-chevron, réutilisé
   ailleurs dans l'app) pour que le montant du poste se rapproche du
   bord droit de la carte, cohérent avec les totaux groupe/catégorie
   qui eux n'ont pas de chevron à leur suite. */
.bd-poste-chevron {
  margin-left: 4px !important;
}

#chr-owners-detail {
  background: var(--bg-grouped-2);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 8px;
  padding: 0 12px;
}
.chr-owner-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 0;
  border-bottom: 0.5px solid var(--sep-opaque);
  flex-wrap: wrap;
}
.chr-owner-row:last-child { border-bottom: none; }
.chr-owner-name {
  font-size: 12px; font-weight: 700; color: var(--label-2);
  min-width: 62px; flex-shrink: 0;
}
.chr-owner-chip {
  font-size: 11px; font-weight: 500;
  padding: 3px 9px; border-radius: 7px;
  display: inline-flex; align-items: center; gap: 4px;
}
.chr-owner-chip strong { font-weight: 700; font-variant-numeric: tabular-nums; }
.chip-pay    { background: rgba(255,159,10,0.12); color: var(--orange); border: 0.5px solid rgba(255,159,10,0.25); }
.chip-refund { background: rgba(10,132,255,0.12); color: var(--blue);   border: 0.5px solid rgba(10,132,255,0.25); }

/* ══ INDIVISION — classes spécifiques au relevé bancaire ══ */

/* Lignes plus compactes + libellé (nom du bénéficiaire, .entry-title)
   réduit de 2px — scopé à #sec-indivision pour ne pas affecter les
   autres listes qui partagent .entry-item/.entry-title (Historique…). */
#sec-indivision .entry-item {
  padding: 7px 13px;
  gap: 8px;
}
#sec-indivision .entry-ico {
  width: 28px; height: 28px;
}
#sec-indivision .entry-title {
  font-size: 11.5px; /* 13.5px - 2px */
}

/* Icône colorée selon débit/crédit */
.entry-ico-credit { color: var(--green); }
.entry-ico-debit  { color: var(--red); }

/* Sous-ligne : date + badge type + motif sur une même ligne flex.
   Le badge type (.entry-sub-type) a une largeur minimale garantie
   (flex-shrink:0 + width fixe) — avant, il rétrécissait en concurrence
   avec le motif (flex:1) et finissait écrasé à ~0px quand le motif
   était long, le rendant invisible. Le motif, lui, prend tout l'espace
   restant et se tronque proprement avec l'ellipsis. */
.entry-sub-flex {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
}
.entry-sub-date {
  flex-shrink: 0;
  font-size: 11px;
  color: var(--label-3);
  font-variant-numeric: tabular-nums;
}
.entry-sub-type {
  flex-shrink: 0;
  flex-grow: 0;
  max-width: 80px;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  color: var(--label-2);
  background: var(--fill-2);
  border: 0.5px solid var(--sep);
  border-radius: 5px;
  padding: 1px 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entry-sub-flex .entry-libelle-flex {
  flex: 1 1 0;
  min-width: 0;
  font-size: 11px;
  color: var(--label-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-top: 0;
}

/* Montant sans marge gauche excessive */
.entry-right-tight {
  text-align: right;
  flex-shrink: 0;
  margin-left: 4px;
}

/* Détail déplié : valeur dans poste-row.
   Avant : flex-shrink:0 sans flex-basis contraint → poste-value prenait
   sa largeur de contenu complète quand le texte était long, poussant
   poste-label hors champ (label "Motif" invisible) et s'affichant lui-même
   à sa taille naturelle, plus gros que prévu. Maintenant : poste-value
   partage l'espace avec poste-label (tous deux flex:1) mais peut aussi
   passer à la ligne (white-space:normal) si le texte est long, plutôt
   que de pousser son voisin — le label reste toujours visible. */
.poste-value {
  flex: 1 1 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--label);
  text-align: right;
  min-width: 0;
  white-space: normal;
  overflow-wrap: break-word;
  word-break: break-word;
}
.poste-label-muted {
  color: var(--label-4);
  font-style: italic;
}

/* ── Statistiques mensuelles (Indivision) — affichées EN DESSOUS du
   titre de chaque mois (voir equilibre.js::_buildIndivisionMonthStatsHtml),
   pas sur la même ligne que le titre, pour éviter tout débordement.
   Une cellule par valeur (Débits / Crédits / Solde du mois / Progressif),
   libellé au-dessus, montant centré en dessous — couleur selon le signe
   réel (rouge = négatif/débit, vert = positif/crédit), même esprit que
   .repartition-table / .repartition-cell déjà utilisées ailleurs.

   .mstat-encart est le cadre extérieur qui porte la bordure/coins
   arrondis. Les cellules à l'intérieur sont collées (flex, pas de gap),
   séparées par un simple trait vertical — comme .repartition-table —
   pour rester compactes sans laisser d'espace mort entre elles. */
.mstat-encart {
  display: flex;
  background: var(--bg-grouped);
  border: 0.5px solid var(--sep-opaque);
  border-radius: 10px;
  overflow: hidden;
  margin: 6px 0 10px;
  transition: var(--theme-transition);
}

.mstat-cell {
  flex: 1;
  min-width: 0;
  padding: 5px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
}

.mstat-cell:not(:last-child) {
  border-right: 0.5px solid var(--sep-opaque);
}

.mstat-label {
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  opacity: 0.75;
}

.mstat-value {
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
  text-align: center;
}

.mstat-cell.mstat-red   { background: rgba(255,69,58,0.08);  }
.mstat-cell.mstat-green { background: rgba(50,215,75,0.08);  }

.mstat-cell.mstat-red   .mstat-label,
.mstat-cell.mstat-red   .mstat-value { color: var(--red); }
.mstat-cell.mstat-green .mstat-label,
.mstat-cell.mstat-green .mstat-value { color: var(--green); }

/* ══════════════════════════════════════════════
   SYNTHÈSE — bloc quote-part (badges), aligné à
   droite de .bilan-ligne-principale, à hauteur
   constante entre tous les encarts de groupe.
   ══════════════════════════════════════════════ */
.syn-qp-zone {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-shrink: 0;
}

/* Cas multi-owners : badges empilés verticalement, alignés à droite */
.syn-qp-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
}

/* .status-badge porte margin-left:7px par défaut (pensé pour suivre un
   texte inline) — ici le badge est seul dans sa propre zone flex, donc
   on neutralise ce décalage pour un alignement net à droite. */
.syn-qp-badge {
  margin-left: 0;
}

/* Détail par owner sous l'encart "Total Différence" */
.syn-total-diff-detail .repartition-table {
  margin-top: 10px;
}

/* Couleurs cycliques des badges quote-part par owner — même palette que
   .r-orange/.r-blue/.r-green/.r-red (repartition-cell), réutilisée ici
   sous forme de badge plein. */
.syn-badge-0 { background: rgba(255,159,10,0.12); color: var(--orange); border: 0.5px solid rgba(255,159,10,0.25); }
.syn-badge-1 { background: rgba(10,132,255,0.12);  color: var(--blue);   border: 0.5px solid rgba(10,132,255,0.25); }
.syn-badge-2 { background: rgba(50,215,75,0.12);   color: var(--green);  border: 0.5px solid rgba(50,215,75,0.25); }
.syn-badge-3 { background: rgba(255,69,58,0.12);   color: var(--red);    border: 0.5px solid rgba(255,69,58,0.25); }

/* ══ SYNTHÈSE — pill compacte par owner : 2 lignes (Versé / Diff)
   alignées en colonnes (clé à gauche, valeur à droite), cadrées entre
   les différentes cellules d'un même .repartition-table grâce à une
   largeur de clé fixe. ══ */
.syn-owner-pill {
  padding-top: 6px;
  padding-bottom: 6px;
  gap: 2px;
}
.syn-owner-pill-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.syn-owner-pill-key {
  flex-shrink: 0;
  color: var(--label-3);
  font-weight: 500;
  font-size: 10px;
}
.syn-owner-pill-val {
  color: var(--label);
  font-weight: 700;
  text-align: right;
}

/* ══════════════════════════════════════════════
   ÉQUILIBRE HUB — Grille "Listes intelligentes"
   façon iOS 26 Reminders : cartes carrées en grille
   2 colonnes, icône ronde colorée (fond plein) en
   haut à gauche, compteur optionnel en haut à
   droite, titre + sous-titre en bas de la carte.
   Namespace séparé de .prop-card (tuiles pleine
   largeur, utilisées par le Hub Propriété) — ici on
   veut explicitement le rendu "grille de vignettes".
   ══════════════════════════════════════════════ */
.eqhub-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}
.eqhub-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 13px 11px;
  min-height: 84px;
  border-radius: 16px;
  border: 0.5px solid color-mix(in srgb, var(--et-color, var(--blue)) 18%, transparent);
  /* 💡 Dégradé diagonal (au lieu d'un fond teinté plat) — deux arrêts de
     LA MÊME --et-color mixée à des proportions différentes avec
     --bg-grouped, donc toujours dérivé d'une seule variable par tuile
     (aucun second token couleur à fournir côté JS). */
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--et-color, var(--blue)) 10%, var(--bg-grouped)) 0%,
    color-mix(in srgb, var(--et-color, var(--blue)) 3%,  var(--bg-grouped)) 100%);
  box-shadow: 0 1px 6px rgba(0,0,0,0.04);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
  transition: transform 0.14s cubic-bezier(.34,1.56,.64,1), opacity 0.12s, box-shadow 0.15s;
}
.eqhub-tile:active { transform: scale(0.965); opacity: 0.85; }

/* 💡 4 COULEURS DISTINCTES, une par position — plutôt que 2 teintes en
   damier (qui, selon la disposition de la grille, pouvaient quand même se
   retrouver côte à côte). Puisque les 4 couleurs sont toutes différentes
   les unes des autres, deux tuiles voisines ne peuvent JAMAIS partager la
   même couleur, quelle que soit la disposition (2 colonnes en mobile, 4
   en rangée unique sur grand écran) — plus besoin de logique par
   disposition/breakpoint. */
.eqhub-tile:nth-child(4n+1) { --et-color: var(--pastel-sky-text)   !important; }
.eqhub-tile:nth-child(4n+2) { --et-color: var(--pastel-coral-text) !important; }
.eqhub-tile:nth-child(4n+3) { --et-color: var(--pastel-rose-text)  !important; }
.eqhub-tile:nth-child(4n)   { --et-color: var(--pastel-slate-text) !important; }

.eqhub-tile-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
.eqhub-tile-ico {
  width: 20px; height: 20px;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--et-color, var(--blue));
}
.eqhub-tile-ico svg { width: 19px; height: 19px; stroke: currentColor; fill: none; stroke-width: 2.1; }
.eqhub-tile-count {
  font-size: 15px;
  font-weight: 800;
  color: var(--et-color, var(--blue));
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.3px;
  line-height: 1;
}
.eqhub-tile-body { min-width: 0; }
.eqhub-tile-title {
  font-size: 13px; font-weight: 700; color: var(--label);
  letter-spacing: -0.1px; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
}
.eqhub-tile-sub {
  font-size: 9.5px; font-weight: 500; color: var(--label-3);
  margin-top: 1px; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
}

/* ── Skeleton de chargement — remplace un texte/chiffre encore inconnu
   par un bloc qui "respire" doucement, plutôt que d'afficher une valeur
   provisoire (—, 0) qui sera brutalement remplacée dès la réponse
   réseau (= clignotement). Le texte réel reste dans le DOM (transparent)
   pour conserver la largeur naturelle du bloc, évitant tout saut de
   mise en page au moment du retrait de la classe. ── */
@keyframes eqhubSkeletonPulse {
  0%, 100% { opacity: 0.35; }
  50%      { opacity: 0.8; }
}
.eqhub-skeleton {
  color: transparent !important;
  background: var(--fill-3);
  border-radius: 6px;
  animation: eqhubSkeletonPulse 1.15s ease-in-out infinite;
  user-select: none;
}
/* Fondu léger appliqué au moment où la vraie valeur remplace le skeleton
   — évite le "pop" instantané, sans pour autant ralentir l'affichage. */
@keyframes eqhubValueIn {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
.eqhub-value-in { animation: eqhubValueIn 0.3s ease both; }

@media (min-width: 1200px) {
  .eqhub-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ══════════════════════════════════════════════
   PROPRIÉTÉ HUB — REDESIGN v2
   Remplace les anciennes .ahub-card (rangées
   compactes façon Reminders, toujours utilisées
   par le Hub Admin) par des tuiles pleine largeur,
   dédiées à la page Propriété (.prop-card /
   .prop-grid) : icône teintée, liseré coloré à
   gauche, badge compteur en pilule + chevron.
   Namespace séparé de .ahub-* pour ne rien changer
   côté Admin Hub (routers.js/database.js).
   ══════════════════════════════════════════════ */

.prop-grid {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.prop-card {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: 14px;
  background:
    radial-gradient(120% 140% at 0% 0%, var(--pc-tint, rgba(10,132,255,0.12)) 0%, transparent 60%),
    var(--bg-grouped);
  box-shadow: 0 1px 6px rgba(0,0,0,0.04);
  overflow: hidden;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s cubic-bezier(.4,0,.2,1), opacity 0.12s, background 0.12s, box-shadow 0.15s;
}
.prop-card:active {
  transform: scale(0.975);
  opacity: 0.9;
}

.prop-card-ico {
  width: 38px; height: 38px; border-radius: 11px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  /* 💡 Pastel : fond teinté (--pc-tint, déjà une couleur pastel ~9-12%
     d'opacité fournie par les appelants — cf. admin.js::_DB_SOLID_TO_PROP_COLORS,
     core.js::_CATEGORY_COLOR_PALETTE) + icône de la couleur d'accent,
     au lieu d'un fond plein --pc-color avec icône blanche. */
  background: var(--pc-tint, rgba(10,132,255,0.12));
  color: var(--pc-color, var(--blue));
  box-shadow: none;
}
.prop-card-ico svg { width: 18px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.prop-card-body { flex: 1; min-width: 0; }
.prop-card-title {
  font-size: 13.5px; font-weight: 700; letter-spacing: -0.2px;
  color: var(--label); line-height: 1.25;
}
.prop-card-sub {
  font-size: 10.5px; font-weight: 500; color: var(--label-3);
  margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.prop-card-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.prop-card-count {
  font-size: 10.5px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--pc-color, var(--blue));
  background: var(--pc-tint, rgba(10,132,255,0.12));
  padding: 2px 8px; border-radius: 20px;
  letter-spacing: -0.1px;
}
.prop-card-chevron { color: var(--label-4); flex-shrink: 0; display: flex; }
.prop-card-chevron svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }

/* ── Hero mono-propriété — habillé d'un fond carte dégradé pour
   marquer davantage la hiérarchie avec les tuiles en dessous
   (avant : simple ligne avatar+texte posée sur le fond de page). ── */
.propriete-hero {
  padding: 18px 16px 20px;
  margin-bottom: 6px;
  border-radius: 20px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--blue) 9%, var(--bg-grouped)) 0%, var(--bg-grouped) 75%);
  border: 0.5px solid var(--sep-opaque);
}

/* ── Panneaux multi-propriétés — la grille de tuiles à l'intérieur
   reprend le fond --bg-grouped (contraste garanti sur le panneau
   teinté), ombre déjà appliquée par .prop-card ci-dessus donc pas
   besoin de dupliquer la règle .ahub-card historique. ── */
.propriete-panel .prop-card {
  background: var(--bg-grouped);
}

/* ══════════════════════════════════════════════
   DESKTOP — Réorganisation en grille des listes de
   blocs (Accueil, Propriété, Admin, Base de données,
   Synthèse…). Pur CSS : les mêmes conteneurs qu'en
   mobile (.home-wrap, .prop-grid, .ahub-grid — pile
   verticale, un bloc par ligne) deviennent des grid
   containers dès 768px, pour profiter de la largeur
   de .content (déjà plafonnée à 1080px) au lieu
   d'étirer chaque bloc sur toute la largeur.
   ══════════════════════════════════════════════ */
@media (min-width: 700px) {
  /* Widgets Accueil (.home-widget) + groupes de cartes Synthèse
     (Total Différence / Cumul / par année, cf. equilibre.js::renderAnnuel)
     — 2 colonnes fixes. align-items:start évite qu'une carte plus haute
     n'étire ses voisines : chaque bloc garde sa hauteur naturelle,
     comme en pile verticale, simplement côte à côte. */
  .home-wrap {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    align-items: start;
  }
  /* .home-wrap .encart-bloc{margin-bottom:0} (déjà défini plus haut)
     neutralisait l'espacement vertical du flex — inutile mais inoffensif
     sous grid (l'espacement vient désormais du gap ci-dessus). */
  .home-wrap .encart-bloc,
  .home-wrap .home-widget { min-width: 0; }

  /* Cartes Propriété / Admin / Base de données (.prop-card, format ligne
     compacte icône+titre+badge) — 2 colonnes, pour ne plus les étirer
     inutilement sur toute la largeur d'un écran large. */
  .prop-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 9px;
  }
  .prop-grid .prop-card { min-width: 0; }

  /* Cartes historiques (.ahub-card / .ahub-grid, conservées pour
     compatibilité interne) — même traitement en grille fixe. */
  .ahub-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
}

/* Écrans très larges — un cran de densité supplémentaire pour les listes
   à effectif variable (Propriété/Admin/Base de données peuvent contenir
   plus de cartes que l'Accueil, qui reste volontairement à 2 colonnes
   pour garder une grille 2×2 régulière quel que soit l'écran). Toujours
   dans la largeur .content déjà plafonnée à 1080px. */
@media (min-width: 1200px) {
  .prop-grid { grid-template-columns: repeat(3, 1fr); }
  .ahub-grid { grid-template-columns: repeat(3, 1fr); }
}