/* =========================================================
   Bullet Journal — Feuille de style principale
   Design pastel lumineux, mobile-first, dégradés par
   catégorie (variables --g1/--g2 posées par les vues).

   Palette resserrée à 3 couleurs dominantes (refonte design) :
   neutre (--c-bg/--c-surface/--c-ink, la grande majorité des
   surfaces), la couleur de marque indigo (--g-app-1/--g-app-2,
   utilisée aussi pour toutes les catégories du parcours — voir
   config.js) et un unique accent chaud (--c-accent, réservé aux
   moments de mise en avant : séries, réussites). Ne pas ajouter
   de nouvelle teinte "à côté" de ces trois-là ; décliner plutôt
   en variant la luminosité/saturation d'une de ces trois.
   ========================================================= */

:root {
  --font: "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Design "carré/sobre" (essai sur branche design/sharp-minimal) : rayons
     nettement resserrés — plus des coins légèrement adoucis que des
     "bulles" — et un unique rayon pour les formes autrefois en pilule
     (999px/50% sur les boutons, badges, barres de progression...), qui
     étaient le signal le plus fort de l'ancien style "bulle". */
  --radius-s: 3px;
  --radius-m: 6px;
  --radius-l: 8px;
  --radius-pill: 5px;

  --sidebar-w: 224px;

  /* Courbe "signature" des animations un peu spectaculaires (indicateur de
     nav, entrée des vues, tiroir mobile) — même famille que les courbes
     déjà utilisées pour les étapes du parcours (js/views/today.js) et les
     séries, pour une seule "personnalité" de mouvement dans toute l'appli. */
  --ease-spring: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* Dégradé générique de l'application (couleur de marque — 2e des 3
     couleurs dominantes, voir en-tête de fichier) */
  --g-app-1: #8d7ce0;
  --g-app-2: #5a95e0;

  /* Accent chaud — 3e des 3 couleurs dominantes, réservé aux moments de
     mise en avant (séries, réussites) : jamais posé comme couleur de fond
     par défaut d'un écran ou d'une catégorie. */
  --c-accent-1: #f8c56b;
  --c-accent-2: #ef7d54;

  --c-good: #43b57e;
  --c-warn: #f0a72e;
  --c-bad: #e05d5d;
  --c-water: #4d9fd6;
  --c-sleep: #8d7ce0;
  --c-steps: #ef7d43;

  /* Dégradé courant (surchargé par étape/catégorie) */
  --g1: var(--g-app-1);
  --g2: var(--g-app-2);

  /* "Fondu dans le décors" : les cartes ne sont plus un blanc opaque posé
     sur le fond, mais un soupçon de verre dépoli qui laisse deviner le fond
     au travers (backdrop-filter), sans jamais afficher de couleur franche.
     Deux essais abandonnés : (1) un dégradé de marque peint DANS chaque
     carte — identique sur toutes les cartes quelle que soit leur position,
     il lisait comme un motif décoratif plaqué ; (2) `saturate()` sur le
     flou pour faire ressortir la couleur du fond réel — trop efficace, les
     taches de fond (--mesh-1..4) redevenaient un dégradé visible dans
     chaque carte. Ici, une base quasi opaque (90%) : le verre se voit dans
     le liseré et le flou des bords, pas comme une teinte dans le corps de
     la carte. Un seul jeu de valeurs ici (pas par thème) : color-mix() se
     recalcule avec la valeur courante de --c-surface, déjà définie par
     thème. */
  --glass-bg: color-mix(in srgb, var(--c-surface) 90%, transparent);
  --glass-filter: blur(16px);
}

html[data-theme="light"] {
  --c-bg: #f7f4fd;
  --c-bg-soft: #f0ebfa;
  --c-surface: #ffffff;
  --c-surface-2: #faf8ff;
  --c-border: #e9e2f6;
  --c-border-strong: #d9cfee;
  --c-ink: #38304e;
  --c-ink-soft: #6f6790;
  --c-ink-faint: #a29ac0;

  /* Ombres très resserrées (design "fondu dans le décors") : un simple
     contact discret plutôt qu'un flottement prononcé — la bordure
     (--c-border) porte l'essentiel de la séparation visuelle, l'ombre
     n'ajoute qu'un soupçon de profondeur. --shadow-2 reste un peu plus
     marquée, réservée aux éléments réellement au-dessus du reste
     (fenêtres modales, tiroir mobile). Le liseré `inset` (2e valeur) est le
     seul reste de "matière" du verre dépoli une fois le dégradé de marque
     retiré du fond des cartes : un reflet du bord supérieur, comme un vrai
     panneau de verre, plutôt qu'une teinte peinte dessus. */
  --shadow-1: 0 1px 2px rgba(40, 30, 70, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.55);
  --shadow-2: 0 2px 8px rgba(40, 30, 70, 0.13), inset 0 1px 0 rgba(255, 255, 255, 0.55);

  /* 3 des 4 taches reprennent la couleur de marque (2 tons) ; la 4e est
     l'unique touche d'accent — jamais une teinte indépendante. Un peu plus
     marquées que la version purement "carte opaque" : elles se devinent
     maintenant au travers du verre dépoli des cartes (--glass-bg), pas
     seulement dans les marges entre elles. */
  --mesh-1: color-mix(in srgb, var(--g-app-1) 26%, transparent);
  --mesh-2: color-mix(in srgb, var(--c-accent-1) 22%, transparent);
  --mesh-3: color-mix(in srgb, var(--g-app-2) 26%, transparent);
  --mesh-4: color-mix(in srgb, var(--g-app-1) 18%, transparent);
}

html[data-theme="dark"] {
  --c-bg: #171223;
  --c-bg-soft: #211a30;
  --c-surface: #251d38;
  --c-surface-2: #2c2342;
  --c-border: #3a2f56;
  --c-border-strong: #4b3d6e;
  --c-ink: #efeaf9;
  --c-ink-soft: #b3a9d1;
  --c-ink-faint: #7f74a3;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  --shadow-2: 0 2px 10px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.06);

  --mesh-1: color-mix(in srgb, var(--g-app-1) 22%, transparent);
  --mesh-2: color-mix(in srgb, var(--c-accent-1) 12%, transparent);
  --mesh-3: color-mix(in srgb, var(--g-app-2) 18%, transparent);
  --mesh-4: color-mix(in srgb, var(--g-app-1) 12%, transparent);
}

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  font-family: var(--font);
  color: var(--c-ink);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Supprime le double-tap-pour-zoomer (et le délai de 300ms avant un tap) sur
     mobile — contrairement à maximum-scale/user-scalable (balise viewport,
     index.html), ceci s'applique aussi sur iOS Safari. Le pincer-zoomer natif
     reste néanmoins possible sur iOS, qui ignore volontairement sa désactivation
     depuis iOS 10 (choix d'accessibilité d'Apple). */
  touch-action: manipulation;
  background:
    radial-gradient(640px 420px at 8% -4%, var(--mesh-1), transparent 62%),
    radial-gradient(520px 380px at 96% 6%, var(--mesh-2), transparent 62%),
    radial-gradient(640px 460px at 92% 96%, var(--mesh-3), transparent 62%),
    radial-gradient(560px 420px at 2% 88%, var(--mesh-4), transparent 62%),
    var(--c-bg);
  background-attachment: fixed;
}

button {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

input, textarea, select { font-family: inherit; font-size: inherit; color: var(--c-ink); }

h1, h2, h3 { margin: 0; font-weight: 700; }

.icon { display: block; flex: none; }

/* =========================
   Structure générale
   ========================= */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
  /* Sans ceci, align-content vaut "normal" -> équivalent à "stretch" en grille : le
     surplus vertical (.app fait min-height:100vh, le contenu réel souvent moins) se
     répartit sur toutes les pistes "auto", y compris .mobile-topbar — sur mobile, sa
     hauteur gonflait/dégonflait visiblement à chaque changement d'étape du parcours,
     simplement parce que la hauteur de #view variait d'une catégorie à l'autre. */
  align-content: start;
}

/* Écran de connexion : pas de barre latérale, une seule colonne
   pleine largeur (sinon la grille replace #view dans la colonne
   de 224px prévue pour la barre latérale masquée). */
.app.no-sidebar {
  grid-template-columns: 1fr;
}

.view {
  padding: 28px clamp(16px, 4vw, 44px) 96px;
  max-width: 1140px;
  width: 100%;
  min-width: 0; /* évite que la piste de grille "1fr" s'élargisse au-delà du viewport
                   pour accueillir le contenu (calendrier, tableaux…) au lieu de le
                   laisser rétrécir/s'adapter — comportement par défaut de CSS Grid */
  margin: 0 auto;
  outline: none;
}

/* Entrée en cascade du contenu d'une vue : chaque changement de nav (ou de
   date sur "Aujourd'hui") reconstruit les enfants directs de #view — ils
   montent et apparaissent avec un léger décalage plutôt que de surgir tous
   d'un coup. Ne cible que les enfants DIRECTS (l'en-tête, les grilles de
   cartes...) : pas de cascade profonde dans chaque carte, qui alourdirait
   l'animation sans rien apporter de lisible. `backwards` évite un flash au
   contenu final avant que le délai de chaque enfant ne soit écoulé. */
@keyframes view-child-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
.view > * {
  animation: view-child-in 0.46s var(--ease-spring) backwards;
}
.view > *:nth-child(1) { animation-delay: 0ms; }
.view > *:nth-child(2) { animation-delay: 45ms; }
.view > *:nth-child(3) { animation-delay: 90ms; }
.view > *:nth-child(4) { animation-delay: 135ms; }
.view > *:nth-child(5) { animation-delay: 180ms; }
.view > *:nth-child(6) { animation-delay: 225ms; }
.view > *:nth-child(7) { animation-delay: 270ms; }
.view > *:nth-child(n+8) { animation-delay: 315ms; }

/* =========================
   Barre latérale
   ========================= */

.sidebar[hidden] { display: none; }

/* Barre du haut + tiroir : uniquement sur mobile (voir la media query
   plus bas), masqués par défaut pour ne jamais apparaître sur desktop. */
.mobile-topbar { display: none; }
.sidebar-backdrop { display: none; }

.sidebar-close-btn {
  display: none;
  margin-left: auto;
  width: 30px;
  height: 30px;
  border-radius: 5px;
  place-items: center;
  color: var(--c-ink-soft);
  flex: none;
}
.sidebar-close-btn:hover { background: var(--c-bg-soft); color: var(--c-ink); }

.sidebar {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding: 26px 14px 18px;
  background: color-mix(in srgb, var(--c-surface) 90%, transparent);
  backdrop-filter: var(--glass-filter);
  border-right: 1px solid var(--c-border);
  z-index: 50;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 10px;
}

.brand-dot {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: linear-gradient(135deg, #a99bf0, #f38fae 55%, #f8b46b);
  box-shadow: 0 0 0 4px color-mix(in srgb, #a99bf0 18%, transparent);
}

.brand-name { font-size: 17px; font-weight: 750; letter-spacing: 0.2px; }

.nav { position: relative; display: flex; flex-direction: column; gap: 5px; }

/* Pastille de marque partagée qui glisse d'un bouton à l'autre (JS :
   BJ.app.positionNavIndicator) plutôt qu'un dégradé repeint à chaque clic
   sur le bouton actif — un seul élément qui se déplace donne l'impression
   d'un vrai indicateur de position, pas d'un simple changement d'état. */
.nav-indicator {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 44px;
  border-radius: 5px;
  background: linear-gradient(135deg, var(--g-app-1), var(--g-app-2));
  box-shadow: 0 6px 16px color-mix(in srgb, var(--g-app-2) 32%, transparent);
  transition: transform 0.42s var(--ease-spring), height 0.42s var(--ease-spring);
  z-index: 0;
  pointer-events: none;
}

/* L'attribut hidden (nav-cycle, nav-admin) doit gagner face au display:flex
   ci-dessous : les deux sont des règles "normales", mais un style auteur
   l'emporte toujours sur le style user-agent par défaut, quelle que soit
   la spécificité — sans cette règle, [hidden] n'a aucun effet visuel. */
.nav-btn[hidden] { display: none; }

/* Petit point d'alerte (demande d'ami en attente) — voir .card-title-count
   pour le badge chiffré utilisé sur le bouton "Amis" lui-même. [hidden]
   perd toujours face à une règle "display" du même niveau de spécificité :
   override explicite nécessaire (déjà vu pour .nav-btn[hidden] ci-dessus). */
.nav-alert-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--c-bad);
  box-shadow: 0 0 0 2px var(--c-surface);
}

.nav-alert-dot[hidden] { display: none; }

.nav-btn, .theme-toggle {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border-radius: 5px;
  color: var(--c-ink-soft);
  font-weight: 570;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
  width: 100%;
  text-align: left;
}

.nav-btn:hover, .theme-toggle:hover { background: var(--c-bg-soft); color: var(--c-ink); }

.nav-btn.is-active {
  color: #fff;
  font-weight: 680;
}

/* La pastille (.nav-indicator) porte déjà le dégradé et l'ombre : un hover
   par-dessus le bouton actif ne doit pas repeindre un second fond dessus. */
.nav-btn.is-active:hover { background: transparent; }

.nav-icon { display: grid; place-items: center; width: 22px; }

.sidebar-footer { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }

.save-indicator {
  min-height: 20px;
  padding: 0 14px;
  font-size: 12.5px;
  color: var(--c-ink-faint);
}

.save-indicator.is-saved { color: var(--c-good); }

/* =========================
   En-têtes de vue
   ========================= */

.view-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 22px;
}

/* Certaines vues (Bilans, panel admin) empilent plusieurs .card/.stats-grid/
   .charts-grid/.empty-state directement sous #view, sans conteneur wrapper
   intermédiaire (contrairement à .settings-stack et consorts) : sans règle
   dédiée, deux boîtes bordées consécutives se touchent avec un gap de 0.
   Les marges adjacentes d'éléments en flux bloc normal se fondent (le max
   est retenu, pas la somme) : ceci ne double donc jamais l'espacement déjà
   posé par margin-bottom sur .stats-grid par exemple. */
.view > .card + .card,
.view > .card + .stats-grid,
.view > .card + .charts-grid,
.view > .card + .empty-state,
.view > .stats-grid + .card,
.view > .stats-grid + .charts-grid,
.view > .charts-grid + .card,
.view > .empty-state + .card {
  margin-top: 20px;
}

.view-title h2 { font-size: clamp(22px, 3vw, 28px); letter-spacing: -0.3px; }

.view-title .subtitle { margin: 3px 0 0; color: var(--c-ink-soft); font-size: 14px; }

/* =========================
   Boutons génériques
   ========================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface);
  color: var(--c-ink);
  font-weight: 590;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.06s ease, box-shadow 0.15s ease;
}

.btn:hover { background: var(--c-surface-2); border-color: var(--c-ink-faint); }
.btn:active { transform: scale(0.97); }

.btn-grad {
  background: linear-gradient(135deg, var(--g1), var(--g2));
  border: none;
  color: #fff;
}

.btn-grad:hover {
  background: linear-gradient(135deg, var(--g1), var(--g2));
  filter: brightness(1.06);
}

.btn-ghost { border-color: transparent; background: transparent; color: var(--c-ink-soft); }
.btn-ghost:hover { background: var(--c-bg-soft); }

.btn-danger { color: var(--c-bad); border-color: color-mix(in srgb, var(--c-bad) 40%, transparent); }
.btn-danger:hover { background: color-mix(in srgb, var(--c-bad) 8%, transparent); border-color: var(--c-bad); }

.btn-icon { padding: 9px; width: 40px; height: 40px; }

/* Encouragement sur la série d'un ami (Amis) — même teinte que le badge de
   série (.friend-streak/.streak-badge) pour associer visuellement le geste
   à ce qu'il célèbre. */
.btn-encourage:hover { color: var(--c-accent-2); border-color: color-mix(in srgb, var(--c-accent-2) 40%, transparent); background: color-mix(in srgb, var(--c-accent-2) 8%, transparent); }
.btn-encourage.is-encouraged { color: var(--c-accent-2); border-color: color-mix(in srgb, var(--c-accent-2) 40%, transparent); background: color-mix(in srgb, var(--c-accent-2) 12%, transparent); }
.btn-encourage.is-encouraged:hover { background: color-mix(in srgb, var(--c-accent-2) 12%, transparent); }

/* =========================
   Navigation de date / période
   ========================= */

.date-nav {
  display: flex;
  align-items: center;
  gap: 6px;
  background: color-mix(in srgb, var(--c-surface) 90%, transparent);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-pill);
  padding: 5px;
  box-shadow: var(--shadow-1);
}

.date-nav input[type="date"] {
  border: none;
  background: transparent;
  font-weight: 620;
  padding: 6px 2px;
  color: var(--c-ink);
}

.date-nav input[type="date"]:focus { outline: none; }

.date-nav strong { padding: 0 8px; }

/* =========================
   Parcours de saisie (wizard)
   ========================= */

.wizard {
  width: 100%;
}

.wizard-progress {
  display: flex;
  gap: 6px;
  margin: 4px 0 8px;
}

.wp-seg {
  flex: 1;
  height: 7px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--c-ink-faint) 22%, transparent);
  transition: background 0.3s ease, transform 0.15s ease;
}

.wp-seg:hover { transform: scaleY(1.5); }

.wp-seg.is-done { background: linear-gradient(90deg, var(--seg-g1, var(--g-app-1)), var(--seg-g2, var(--g-app-2))); }

.wp-seg.is-current {
  background: linear-gradient(90deg, var(--seg-g1, var(--g-app-1)), var(--seg-g2, var(--g-app-2)));
}

.wizard-progress-label {
  display: flex;
  justify-content: space-between;
  font-size: 12.5px;
  color: var(--c-ink-faint);
  margin-bottom: 16px;
  padding: 0 2px;
}

/* Centre le bloc de l'étape (bannière + champs + navigation) dans
   tout l'espace vertical disponible de la page, plutôt que de le
   caler en haut et laisser un vide en bas sur les étapes courtes. */
.wizard-stage {
  position: relative;
  /* Autorise le scroll vertical natif, laisse le geste horizontal (swipe entre
     étapes, voir attachSwipeNav dans today.js) au JS plutôt qu'au navigateur. */
  touch-action: pan-y;
}

/* --- Étape : occupe toute la page, pas une carte flottante --- */

.step-card {
  display: flex;
  flex-direction: column;
}

.step-hero {
  position: relative;
  overflow: hidden;
  padding: 40px clamp(20px, 5vw, 64px) 34px;
  margin: 0 calc(-1 * clamp(16px, 4vw, 44px));
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--g1) 22%, transparent),
      color-mix(in srgb, var(--g2) 11%, transparent) 65%,
      transparent);
  display: flex;
  align-items: center;
  gap: 22px;
}

.step-hero::after {
  content: "";
  position: absolute;
  top: -90px;
  right: -60px;
  width: 280px;
  height: 280px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--g2) 20%, transparent), transparent 70%);
  pointer-events: none;
  z-index: 0;
}

/* Motif décoratif par catégorie : l'icône de l'étape dispersée en
   filigrane, façon "papier peint" discret — même esprit que les
   dégradés déjà propres à chaque catégorie, juste un peu plus incarné. */
.step-motif {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.step-motif-icon {
  position: absolute;
  color: var(--g2);
  opacity: 0.2;
}

.step-badge, .step-titles, .step-value { position: relative; z-index: 1; }

.step-badge {
  width: 76px;
  height: 76px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  flex: none;
}

.step-titles { min-width: 0; }

.step-title { font-size: clamp(24px, 3.4vw, 32px); font-weight: 780; letter-spacing: -0.4px; }

.step-sub { font-size: 15px; color: var(--c-ink-soft); margin-top: 4px; }

.step-value {
  margin-left: auto;
  font-weight: 750;
  font-size: 19px;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  white-space: nowrap;
}

/* --- Thème "nuit" pour le sommeil : mêmes dégradés de marque,
   fond assombri façon ciel nocturne + étoiles, texte forcé en
   clair pour rester lisible quel que soit le thème clair/sombre
   de l'application (cohérent avec les couleurs fixes déjà
   propres à chaque catégorie). --- */

.step-card[data-step="sleep"] .step-hero {
  background:
    radial-gradient(120% 160% at 12% -10%,
      color-mix(in srgb, var(--g1) 55%, #1a1640) 0%,
      #201c42 55%,
      #14112c 100%);
}

.step-card[data-step="sleep"] .step-title,
.step-card[data-step="sleep"] .step-sub {
  color: #fff;
}

.step-card[data-step="sleep"] .step-sub { color: rgba(255, 255, 255, 0.72); }

.step-card[data-step="sleep"] .step-value {
  background: none;
  -webkit-background-clip: initial;
  background-clip: initial;
  color: #fff;
}

.step-card[data-step="sleep"] .step-motif-icon { color: #fff; opacity: 0.4; }

.step-motif-star {
  position: absolute;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 5px 1px rgba(255, 255, 255, 0.7);
  animation: star-twinkle 3.4s ease-in-out infinite;
}

@keyframes star-twinkle {
  0%, 100% { opacity: 0.85; }
  50% { opacity: 0.35; }
}

.step-body {
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: 40px 0;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.wizard-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: 0 0 8px;
}

.wizard-nav .btn { min-width: 118px; }

/* --- Animations de transition d'étape --- */

@keyframes step-in-right {
  from { opacity: 0; transform: translateX(64px) scale(0.98); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

@keyframes step-in-left {
  from { opacity: 0; transform: translateX(-64px) scale(0.98); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

@keyframes step-out-left {
  to { opacity: 0; transform: translateX(-64px) scale(0.98); }
}

@keyframes step-out-right {
  to { opacity: 0; transform: translateX(64px) scale(0.98); }
}

.anim-in-right { animation: step-in-right 0.32s cubic-bezier(0.2, 0.7, 0.3, 1); }
.anim-in-left  { animation: step-in-left  0.32s cubic-bezier(0.2, 0.7, 0.3, 1); }
.anim-out-left  { animation: step-out-left  0.2s ease forwards; pointer-events: none; }
.anim-out-right { animation: step-out-right 0.2s ease forwards; pointer-events: none; }

/* --- Récapitulatif de fin --- */

@keyframes pop-in {
  0% { transform: scale(0.4); opacity: 0; }
  70% { transform: scale(1.12); }
  100% { transform: scale(1); opacity: 1; }
}

.recap-check {
  width: 76px;
  height: 76px;
  margin: 6px auto 0;
  border-radius: 8px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, #43b57e, #33b8c4);
  animation: pop-in 0.45s cubic-bezier(0.2, 0.7, 0.3, 1.2);
}

.recap-title { text-align: center; font-size: 21px; font-weight: 750; margin-top: 12px; }

.recap-sub { text-align: center; color: var(--c-ink-soft); font-size: 13.5px; margin-top: 2px; }

@keyframes streak-in {
  from { opacity: 0; transform: translateY(4px) scale(0.92); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.streak-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 12px auto 0;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, var(--c-accent-1), var(--c-accent-2));
  color: #fff;
  font-size: 13px;
  font-weight: 650;
  animation: streak-in 0.35s cubic-bezier(0.2, 0.7, 0.3, 1.2);
}

.streak-ico { display: grid; place-items: center; }

/* Badge de palier de série (bronze/argent/or/platine — dès 7 jours
   consécutifs, voir BJ.models.streakTier), remplace .streak-badge une fois
   le premier palier atteint. Dégradé --g1/--g2 posé par la vue selon le
   palier (js/config.js, STREAK_TIERS) — jamais de couleur en dur ici, pour
   rester cohérent avec le reste des badges à dégradé de l'app. */
.streak-tier-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 12px auto 0;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, var(--g1), var(--g2));
  color: #fff;
  animation: streak-in 0.35s cubic-bezier(0.2, 0.7, 0.3, 1.2);
}

.streak-tier-ico { display: grid; place-items: center; flex: none; }

.streak-tier-text { display: flex; flex-direction: column; text-align: left; }

.streak-tier-label { font-size: 14px; font-weight: 700; letter-spacing: 0.2px; }

.streak-tier-msg { font-size: 12px; opacity: 0.92; margin-top: 1px; }

/* Platine : seul palier à associer marque et accent (les 2 des 3 couleurs
   dominantes) plutôt qu'une déclinaison d'une seule — un léger chatoiement
   marque ce caractère exceptionnel plutôt qu'une 4e teinte indépendante. */
@keyframes streak-shimmer {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
.streak-tier-badge--platinum {
  background-size: 200% 200%;
  animation: streak-in 0.35s cubic-bezier(0.2, 0.7, 0.3, 1.2), streak-shimmer 3s ease-in-out infinite;
}

/* Collection de badges (Bilans) : une pastille par palier, discrète —
   estompée/hors-couleur tant que le palier n'a jamais été atteint (voir
   BJ.models.streakInfo, .best), colorée sans autre effet une fois débloquée.
   Volontairement en retrait du badge de série principal : petite taille,
   pas de texte visible, juste un `title` au survol. */
.badge-collection {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  margin: 10px 0 0;
}

.badge-collection-item {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 5px;
  border: 1.5px solid color-mix(in srgb, var(--c-ink-faint) 35%, transparent);
  color: var(--c-ink-faint);
  opacity: 0.5;
}

.badge-collection-item.is-unlocked {
  border-color: transparent;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  color: #fff;
  opacity: 1;
}

.recap-list { display: flex; flex-direction: column; gap: 4px; margin-top: 14px; }

.recap-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 5px;
  transition: background 0.15s ease;
  text-align: left;
  width: 100%;
}

.recap-row:hover { background: var(--c-bg-soft); }

.recap-ico {
  width: 34px;
  height: 34px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  flex: none;
}

.recap-row.is-empty .recap-ico { background: var(--c-bg-soft); color: var(--c-ink-faint); }

.recap-label { font-weight: 640; font-size: 14px; flex: none; width: 92px; }

.recap-value {
  color: var(--c-ink-soft);
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.recap-row.is-empty .recap-value { color: var(--c-ink-faint); font-style: italic; }

/* =========================
   Cartes génériques (réglages…)
   ========================= */

.card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-m);
  padding: 20px;
  box-shadow: var(--shadow-1);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.card-title {
  font-size: 15.5px;
  font-weight: 680;
  display: flex;
  align-items: center;
  gap: 10px;
}

.card-title .icon { color: var(--g2); }

/* Réglages : regroupe les actions rarement utilisées et peu réversibles
   (déconnexion, effacement des entrées) — bordure teintée en plus du
   --g2 posé en JS (icône du titre déjà rouge via la règle générique
   ci-dessus). */
.settings-danger-card { border-color: color-mix(in srgb, var(--c-bad) 35%, var(--c-border)); }

/* Invitation "hier n'est pas rempli" (views/today.js, buildYesterdayNudge) —
   carte insérée sous l'en-tête d'"Aujourd'hui", une seule fois par session. */
.card--nudge { position: relative; }

.nudge-dismiss { position: absolute; top: 10px; right: 10px; }

.nudge-body { display: flex; align-items: flex-start; gap: 14px; padding-right: 32px; }

.nudge-icon {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g-app-1), var(--g-app-2));
}

.nudge-title { font-size: 15px; font-weight: 680; }

.nudge-text { font-size: 13.5px; color: var(--c-ink-soft); margin-top: 3px; }

/* =========================
   Chips (sélection)
   ========================= */

.chip-group { display: flex; flex-wrap: wrap; gap: 9px; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--c-border);
  background: var(--c-surface-2);
  color: var(--c-ink-soft);
  font-size: 13.5px;
  font-weight: 590;
  transition: all 0.16s ease;
}

.chip:hover {
  border-color: color-mix(in srgb, var(--chip-c, var(--g2)) 55%, transparent);
  color: var(--c-ink);
  transform: translateY(-1px);
}

.chip.is-selected {
  background: color-mix(in srgb, var(--chip-c, var(--g2)) 16%, var(--c-surface));
  border-color: var(--chip-c, var(--g2));
  color: color-mix(in srgb, var(--chip-c, var(--g2)) 78%, var(--c-ink));
}

.chip-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--chip-c, var(--g2));
  flex: none;
}

/* =========================
   Contrôle segmenté
   ========================= */

.segmented {
  display: flex;
  background: var(--c-bg-soft);
  border-radius: var(--radius-pill);
  padding: 4px;
  gap: 4px;
}

.seg-btn {
  flex: 1;
  padding: 9px 6px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 590;
  color: var(--c-ink-soft);
  text-align: center;
  transition: all 0.16s ease;
  white-space: nowrap;
}

.seg-btn:hover { color: var(--c-ink); }

.seg-btn.is-selected {
  background: var(--c-surface);
  color: var(--seg-color, var(--g2));
  box-shadow: var(--shadow-1);
  font-weight: 720;
}

/* =========================
   Notation (étoiles / éclairs)
   ========================= */

.rate-row { display: flex; gap: 8px; }

.rate-btn {
  padding: 6px;
  border-radius: 5px;
  color: var(--c-border-strong);
  transition: color 0.15s ease, transform 0.12s ease, background 0.15s ease;
}

.rate-btn:hover { transform: scale(1.18); background: var(--c-bg-soft); }

.rate-btn.is-on { color: var(--g2); }
.rate-btn.is-on .icon { fill: color-mix(in srgb, var(--g1) 55%, var(--g2)); stroke: var(--g2); }

/* =========================
   Compteur (hydratation)
   ========================= */

.counter { display: flex; align-items: center; justify-content: center; gap: 20px; }

.counter-btn {
  width: 52px;
  height: 52px;
  border-radius: 6px;
  border: 1.5px solid var(--c-border-strong);
  background: var(--c-surface-2);
  display: grid;
  place-items: center;
  transition: all 0.15s ease;
  color: var(--c-ink-soft);
}

.counter-btn:hover {
  border-color: var(--g2);
  color: var(--g2);
}

.counter-btn:active { transform: scale(0.92); }

.counter-value { min-width: 96px; text-align: center; }

.counter-value .big {
  font-size: 34px;
  font-weight: 780;
  line-height: 1.1;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.counter-value .small { font-size: 12.5px; color: var(--c-ink-faint); }

/* =========================
   Barres de progression
   ========================= */

.progress {
  height: 9px;
  border-radius: var(--radius-pill);
  background: var(--c-bg-soft);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--g1), var(--g2));
  width: 0%;
  transition: width 0.4s cubic-bezier(0.2, 0.7, 0.3, 1);
}

.progress-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 12.5px;
  color: var(--c-ink-faint);
  margin-top: 6px;
}

/* =========================
   Interrupteur (switch)
   ========================= */

.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

.switch {
  position: relative;
  width: 50px;
  height: 28px;
  border-radius: var(--radius-pill);
  background: var(--c-bg-soft);
  border: 1px solid var(--c-border-strong);
  transition: background 0.2s ease, border-color 0.2s ease;
  flex: none;
}

.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 22px;
  height: 22px;
  border-radius: 3px;
  background: var(--c-surface);
  box-shadow: var(--shadow-1);
  transition: transform 0.2s cubic-bezier(0.2, 0.7, 0.3, 1.3);
}

.switch.is-on {
  background: linear-gradient(135deg, var(--g1), var(--g2));
  border-color: transparent;
}

.switch.is-on::after { transform: translateX(22px); }

.pill-details { display: flex; flex-direction: column; gap: 16px; margin-top: 4px; }
.pill-details[hidden] { display: none; }

/* =========================
   Champs de saisie
   ========================= */

.field { display: flex; flex-direction: column; gap: 7px; }
.field[hidden] { display: none; }

.field-label {
  font-size: 12px;
  font-weight: 680;
  color: var(--c-ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}

.input, .textarea, .select {
  border: 1.5px solid var(--c-border);
  border-radius: var(--radius-s);
  background: var(--c-surface-2);
  padding: 11px 13px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  width: 100%;
}

.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--g2);
  box-shadow: 0 0 0 3.5px color-mix(in srgb, var(--g2) 18%, transparent);
}

.textarea { resize: vertical; min-height: 86px; line-height: 1.55; }

.inline-fields { display: flex; gap: 12px; }
.inline-fields .field { flex: 1; }

/* =========================
   Calendrier (Journal)
   ========================= */

.cycle-forecast-card { margin-bottom: 18px; }

.calendar-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-1);
  padding: 22px;
}

.calendar-card[hidden] { display: none; }

/* =========================
   Recherche dans les notes (vue Journal)
   ========================= */

.notes-search-card { margin-bottom: 18px; }

.notes-search-form { display: flex; gap: 10px; }

.notes-search-form .input { flex: 1; }

.notes-search-hint { font-size: 12.5px; color: var(--c-ink-faint); }

.notes-search-hint[hidden] { display: none; }

.search-results { display: flex; flex-direction: column; gap: 10px; }

.search-result {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--c-border);
  border-radius: 5px;
  text-align: left;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.search-result:hover { background: var(--c-bg-soft); border-color: var(--c-border-strong); }

.search-result:focus-visible { outline: 2px solid var(--g2); outline-offset: 2px; }

.search-result-date { font-weight: 640; font-size: 13.5px; }

.search-result-snippet {
  font-size: 13px;
  color: var(--c-ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.search-highlight {
  background: color-mix(in srgb, var(--g2) 35%, transparent);
  color: inherit;
  border-radius: 2px;
  padding: 0 2px;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}

.cal-dow {
  min-width: 0;
  text-align: center;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--c-ink-faint);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  padding: 6px 0 10px;
}

.cal-cell {
  /* min-width: 0 laisse la piste de grille rétrécir sous la largeur
     naturelle imposée par "aspect-ratio" (sinon les 7 colonnes
     débordent sur les petits écrans au lieu de se compresser). */
  min-width: 0;
  aspect-ratio: 1 / 1.05;
  border-radius: 5px;
  border: 1.5px solid transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 4px;
  padding: 7px 2px 5px;
  transition: all 0.15s ease;
  position: relative;
  background: var(--day-tint, transparent);
}

.cal-cell:not(.is-empty):hover {
  border-color: var(--c-border-strong);
  transform: translateY(-1px);
  box-shadow: var(--shadow-1);
}

.cal-cell.is-out { opacity: 0.32; }

.cal-cell.is-today {
  border-color: var(--g-app-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--g-app-1) 16%, transparent);
}

.cal-cell.is-future { pointer-events: none; opacity: 0.3; }

/* Jour de règles : bordure et halo rouge, prioritaires sur la teinte d'humeur
   (posée via --day-tint en JS, voir views/journal.js). */
.cal-cell.is-period {
  border-color: color-mix(in srgb, #d63e63 45%, transparent);
}

.cal-cell.is-period.is-today {
  border-color: #d63e63;
  box-shadow: 0 0 0 3px color-mix(in srgb, #d63e63 20%, transparent);
}

/* Jours de règles pré-remplis automatiquement au-delà d'aujourd'hui (voir
   handleNewPeriodStart, views/cycle.js) : mêmes règles que .is-period, mais
   sans l'estompage des jours futurs, sinon ce pré-remplissage — pensé pour
   être visible dans le calendrier — resterait quasi invisible. */
.cal-cell.is-future.is-period { opacity: 1; }

/* Jour de début de règles estimé par la prédiction (voir models.cyclePrediction) :
   contour pointillé bien visible + halo pulsant, distinct des règles
   réellement enregistrées (.is-period, contour plein). Exempté de
   l'estompage habituel des jours futurs (.is-future baisse l'opacité
   à 0.3, ce qui rendait le repère quasi invisible). */
.cal-cell.is-period-predicted {
  border-width: 2px;
  border-style: dashed;
  border-color: #d63e63;
  animation: cal-predicted-pulse 2s ease-in-out infinite;
}

.cal-cell.is-future.is-period-predicted { opacity: 1; }

@keyframes cal-predicted-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, #d63e63 45%, transparent); }
  70% { box-shadow: 0 0 0 7px color-mix(in srgb, #d63e63 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, #d63e63 0%, transparent); }
}

.cal-num { font-size: 13px; font-weight: 640; }

.cal-mood-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--mood-c, var(--c-ink-faint));
  box-shadow: 0 0 0 3.5px color-mix(in srgb, var(--mood-c, var(--c-ink-faint)) 22%, transparent);
}

.cal-period-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #d63e63;
  box-shadow: 0 0 0 3px color-mix(in srgb, #d63e63 25%, transparent);
}

.cal-period-dot-predicted {
  background: transparent;
  box-shadow: none;
  border: 2px dashed #d63e63;
}

.cal-dots { display: flex; gap: 3px; margin-top: auto; }

.cal-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--c-ink-faint);
}

.cal-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--c-border);
  font-size: 12.5px;
  color: var(--c-ink-soft);
}

.cal-legend > span { display: inline-flex; align-items: center; gap: 6px; }

.cal-legend .cal-mood-dot { width: 11px; height: 11px; }

.cal-legend .cal-period-dot { width: 10px; height: 10px; }

/* =========================
   Bilans (stats)
   ========================= */

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(225px, 1fr));
  gap: 14px;
  margin-bottom: 24px;
}

.stat-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-m);
  padding: 16px;
  box-shadow: var(--shadow-1);
  display: flex;
  align-items: flex-start;
  gap: 13px;
}

.stat-ico {
  width: 42px;
  height: 42px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  flex: none;}

.stat-info { min-width: 0; }

.stat-label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--c-ink-faint);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.stat-value { font-size: 21px; font-weight: 780; letter-spacing: -0.4px; line-height: 1.2; }

.stat-detail { font-size: 12.5px; color: var(--c-ink-soft); margin-top: 1px; }

/* Comparaison à la période précédente (Bilans) — délibérément neutre, sans
   code couleur bon/mauvais y compris sur la flèche : le sens d'une hausse
   dépend de la personne, pas à l'app de trancher. */
.stat-delta {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 12px;
  color: var(--c-ink-faint);
  margin-top: 3px;
  font-weight: 600;
}

.stat-delta-ico { display: grid; place-items: center; flex: none; }

.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  gap: 18px;
}

.chart-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-m);
  padding: 20px;
  box-shadow: var(--shadow-1);
}

.chart-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}

.chart-title {
  font-size: 14.5px;
  font-weight: 680;
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.chart-title .icon { color: var(--g2); flex: none; }

.chart-expand-btn { flex: none; color: var(--c-ink-faint); }
.chart-expand-btn:hover { color: var(--g2); }

.chart-empty {
  color: var(--c-ink-faint);
  font-size: 13.5px;
  text-align: center;
  padding: 30px 0;
}

.chart-svg { width: 100%; height: auto; display: block; overflow: visible; }
.chart-svg text { font-family: var(--font); fill: var(--c-ink-faint); }
.chart-svg .chart-guide { pointer-events: none; }

/* Tracé progressif des graphiques (charts.js) : la courbe se "dessine"
   plutôt que d'apparaître d'un bloc. Le stroke-dasharray/-dashoffset de
   départ est posé en JS (dépend de la longueur réelle du tracé, via
   getTotalLength) ; cette transition anime juste le retour à 0. */
.chart-line-path { transition: stroke-dashoffset 0.9s var(--ease-spring); }

/* Lignes secondaires (tendance, objectif) : un simple fondu retardé après
   le tracé principal plutôt qu'un vrai dessin — ce sont des repères, pas
   la donnée elle-même, inutile de leur donner autant de "spectacle". */
.chart-secondary-line {
  animation: chart-fade-in 0.5s var(--ease-spring) backwards;
  animation-delay: 0.7s;
}
@keyframes chart-fade-in { from { opacity: 0; } }

/* Points de la courbe : apparaissent en cascade, calée sur le tracé de la
   ligne (délai posé en JS par point). */
.chart-dot {
  transform-box: fill-box;
  transform-origin: center;
  animation: chart-dot-in 0.4s var(--ease-spring) backwards;
}
@keyframes chart-dot-in {
  from { opacity: 0; transform: scale(0); }
  70%  { transform: scale(1.25); }
  to   { opacity: 1; transform: scale(1); }
}

/* Barres : montent depuis leur base plutôt que d'apparaître pleine
   hauteur — délai en cascade posé en JS par index. */
.chart-bar-rect {
  transform-box: fill-box;
  transform-origin: bottom;
  animation: chart-bar-grow 0.55s var(--ease-spring) backwards;
}
@keyframes chart-bar-grow { from { transform: scaleY(0); } }

/* Info-bulle de précision au survol/tap d'un graphique interactif (voir
   charts.js: attachInteractive) — positionnée en % du conteneur, suit le
   point le plus proche du curseur plutôt que le <title> SVG natif (lent
   à apparaître, jamais persistant). */
.chart-tooltip {
  position: absolute;
  transform: translate(-50%, -100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 6px 10px;
  border-radius: 3px;
  background: var(--c-ink);
  color: var(--c-surface);
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: var(--shadow-1);
  z-index: 2;
}

.chart-tooltip strong { font-size: 12px; font-weight: 680; }
.chart-tooltip span { font-size: 12.5px; opacity: 0.9; }

/* =========================
   Vue agrandie d'un graphique (chart-detail.js)
   ========================= */

.chart-detail-overlay {
  position: fixed;
  inset: 0;
  z-index: 150;
  background: color-mix(in srgb, #000 45%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  animation: chart-detail-fade 0.18s ease;
}

@keyframes chart-detail-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.chart-detail-card {
  background: var(--c-surface);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-2);
  padding: 22px;
  width: min(880px, 100%);
  max-height: min(720px, 100%);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.chart-detail-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.chart-detail-head .card-title { flex: 1; min-width: 0; }

.chart-detail-close { flex: none; margin-left: auto; }

.chart-detail-range { align-self: flex-start; }

.chart-detail-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 12px;
}

.chart-detail-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px;
  border-radius: 5px;
  background: var(--c-bg-soft);
}

.chart-detail-stat-label {
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--c-ink-faint);
  font-weight: 650;
}

.chart-detail-stat-value { font-size: 16px; font-weight: 700; }

.chart-detail-trend { background: color-mix(in srgb, var(--g2) 14%, var(--c-bg-soft)); }
.chart-detail-trend .chart-detail-stat-value { color: var(--g2); }

.chart-detail-chart { position: relative; }

@media (max-width: 640px) {
  .chart-detail-card { padding: 16px; gap: 12px; }
  .chart-detail-summary { grid-template-columns: repeat(2, 1fr); }
}

/* Barres horizontales (distributions) */
.hbar-list { display: flex; flex-direction: column; gap: 10px; }

.hbar-row {
  display: grid;
  grid-template-columns: 132px 1fr 34px;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
}

.hbar-label {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--c-ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hbar-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--g2); }

.hbar-track { height: 10px; background: var(--c-bg-soft); border-radius: var(--radius-pill); overflow: hidden; }

.hbar-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--g1), var(--g2));
  transition: width 0.35s ease;
}

.hbar-count { text-align: right; font-weight: 680; font-size: 13px; }

/* Corrélations (Bilans) */
.insight-list { display: flex; flex-direction: column; gap: 12px; }

.insight-row { display: flex; align-items: center; gap: 13px; }

.insight-ico {
  width: 36px;
  height: 36px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  flex: none;}

.insight-text { font-size: 13.5px; color: var(--c-ink-soft); line-height: 1.45; }

/* =========================
   Année en pixels (Bilans)
   ========================= */

/* Défile horizontalement plutôt que d'écraser les 31 colonnes sur mobile. */
.pixel-year-scroll { overflow-x: auto; margin-top: 4px; }

.pixel-year { display: flex; flex-direction: column; gap: 3px; width: max-content; }

.pixel-row { display: grid; grid-template-columns: 34px repeat(31, 18px); gap: 3px; align-items: center; }

.pixel-row-label {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--c-ink-faint);
  text-transform: uppercase;
}

.pixel-header-row .pixel-day-num {
  text-align: center;
  font-size: 9.5px;
  color: var(--c-ink-faint);
}

.pixel-cell {
  width: 18px;
  height: 18px;
  border-radius: 2px;
  background: var(--pixel-c, var(--c-ink-faint));
  border: none;
  transition: transform 0.1s ease;
}

.pixel-cell:not(.is-void):not(.is-future):hover { transform: scale(1.18); }

.pixel-cell.is-blank { background: var(--c-bg-soft); box-shadow: inset 0 0 0 1px var(--c-border); }

.pixel-cell.is-future { opacity: 0.25; pointer-events: none; }

.pixel-cell.is-void { background: transparent; }

/* =========================
   Écran de connexion / inscription
   ========================= */

.auth-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

/* Page d'accueil non connectée : présentation + grille de fonctionnalités
   au-dessus du formulaire (voir landing-auth ci-dessous) — contrairement à
   auth-screen (utilisé seul par la vue "genre manquant"), pas de
   min-height:100vh ici, la page grandit avec son contenu. */
.landing-shell { max-width: 980px; margin: 0 auto; padding: 48px 20px 8px; }

.landing-header { text-align: center; margin-bottom: 32px; }

.landing-title { font-size: 30px; letter-spacing: -0.5px; margin: 18px 0 14px; }

.landing-desc {
  color: var(--c-ink-soft);
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 640px;
  margin: 0 auto;
}

.landing-features { margin-bottom: 40px; }

/* Ancre de #rejoindre (bouton d'appel à l'action) : défilement doux plutôt
   qu'un saut sec vers le formulaire. */
html { scroll-behavior: smooth; }

.landing-pills {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 9px;
  margin-top: 22px;
}

/* Puces décoratives (pas de sélection/interaction) : neutralise le survol
   "sélectionnable" hérité de .chip. */
.landing-pill { cursor: default; }
.landing-pill:hover { transform: none; border-color: var(--c-border); color: var(--c-ink-soft); }

.landing-cta-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 28px;
}

.landing-cta { padding: 15px 36px; font-size: 15.5px; }

.landing-cta-hint { font-size: 12.5px; color: var(--c-ink-faint); margin: 0; }

.landing-title-sm { font-size: 24px; letter-spacing: -0.4px; margin: 0 0 8px; }

/* Section installation : l'argument le plus fort de la page d'accueil sur
   mobile — voir buildInstallSection() dans views/auth.js. Panneau teinté
   (plutôt qu'un simple bloc sur fond neutre) pour qu'elle se distingue
   visuellement du reste au premier coup d'œil, juste après l'accroche. */
.landing-install {
  margin: 8px 0 40px;
  padding: 32px 20px;
  border-radius: var(--radius-l);
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--g-app-1) 12%, var(--c-surface)),
    color-mix(in srgb, var(--g-app-2) 8%, var(--c-surface)));
  border: 1px solid color-mix(in srgb, var(--g-app-2) 25%, var(--c-border));
}

.landing-install-header { text-align: center; margin-bottom: 24px; }

.landing-install-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--g-app-2) 16%, var(--c-surface));
  color: var(--g-app-2);
  font-size: 12px;
  font-weight: 700;
  margin-bottom: 12px;
}

.landing-install-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 18px;
}

.install-card {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 88%, transparent);
  border-radius: var(--radius-m);
  padding: 22px;
  box-shadow: var(--shadow-1);
}

.install-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}

.install-card-cta { margin-top: 16px; }

.install-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: install-step;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.install-steps li {
  counter-increment: install-step;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  font-size: 13.5px;
  color: var(--c-ink-soft);
  line-height: 1.5;
}

.install-steps li::before {
  content: counter(install-step);
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 5px;
  background: linear-gradient(135deg, var(--g1), var(--g2));
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  display: grid;
  place-items: center;
}

.landing-auth { display: flex; justify-content: center; padding: 8px 20px 56px; }

.auth-card {
  width: 100%;
  max-width: 380px;
  /* Un peu plus opaque que --glass-bg : carte dense en champs de saisie,
     la lisibilité prime ici sur l'effet de transparence. */
  background: color-mix(in srgb, var(--c-surface) 96%, transparent);
  backdrop-filter: var(--glass-filter);
  border: 1px solid color-mix(in srgb, var(--c-border) 92%, transparent);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-2);
  padding: 34px 30px;
  text-align: center;
}

.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  margin-bottom: 22px;
}

.auth-brand-name { font-size: 15px; font-weight: 750; }

.auth-title { font-size: 22px; letter-spacing: -0.3px; }

.auth-sub { color: var(--c-ink-soft); font-size: 13.5px; margin: 6px 0 24px; }

.auth-google-btn { width: 100%; padding: 11px; font-size: 13.5px; }

.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--c-ink-faint);
  font-size: 12px;
  margin: 18px 0;
}

.auth-divider::before, .auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--c-border);
}

.auth-form { display: flex; flex-direction: column; gap: 16px; text-align: left; }

.auth-submit { width: 100%; padding: 12px; font-size: 14.5px; margin-top: 4px; }

.auth-error {
  color: var(--c-bad);
  font-size: 13px;
  margin: 0;
  min-height: 1px;
}

.auth-toggle {
  margin-top: 20px;
  font-size: 13px;
  color: var(--c-ink-soft);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.auth-toggle:hover { color: var(--g-app-2); }

.auth-legal { margin-top: 14px; font-size: 11.5px; color: var(--c-ink-faint); }
.auth-legal a { color: inherit; }
.auth-legal a:hover { color: var(--g-app-2); }

/* =========================
   Réglages
   ========================= */

.settings-stack { display: flex; flex-direction: column; gap: 18px; max-width: 640px; }

/* =========================
   Suivi des menstruations
   ========================= */

.cycle-stack { display: flex; flex-direction: column; gap: 18px; max-width: 760px; }

/* =========================
   Idées & bugs
   ========================= */

.feedback-stack { display: flex; flex-direction: column; gap: 18px; max-width: 760px; }

/* Espace le champ de saisie et le bouton d'envoi : un <form> n'est pas un
   conteneur flex par défaut, ses enfants (le champ, puis le bouton) se
   touchaient donc directement l'un sous l'autre. Le champ (.field) reste
   étiré en pleine largeur (align-items: stretch, la valeur par défaut) ;
   seul le bouton revient à sa largeur naturelle. */
.feedback-form { display: flex; flex-direction: column; gap: 14px; }
.feedback-form .btn { align-self: flex-start; }

/* Message tronqué sur une ligne (contrairement à .recap-label, prévu pour
   un libellé court de largeur fixe) + date reléguée en fin de ligne. */
.feedback-msg {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.feedback-date { flex: none; font-size: 12px; color: var(--c-ink-faint); }

.feedback-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  flex: none;
  font-size: 12px;
  font-weight: 640;
  color: var(--status-color);
  background: color-mix(in srgb, var(--status-color) 14%, transparent);
}

/* =========================
   Panel admin
   ========================= */

.admin-toolbar { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }

.admin-list { display: flex; flex-direction: column; gap: 10px; }

.admin-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--c-border);
  border-radius: 5px;
}

.admin-item-body { flex: 1; min-width: 0; }

.admin-item-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
}

.admin-item-author { font-weight: 640; font-size: 13px; color: var(--c-ink-soft); }

.admin-item-date { flex: none; font-size: 12px; color: var(--c-ink-faint); }

.admin-item-msg {
  margin: 0;
  font-size: 14px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.admin-item-footer { margin-top: 10px; }

.feedback-status-select {
  width: auto;
  padding: 6px 30px 6px 12px;
  font-size: 12.5px;
  font-weight: 640;
  border-radius: var(--radius-pill);
  color: var(--status-color, var(--c-ink-soft));
  border-color: color-mix(in srgb, var(--status-color, var(--c-border)) 45%, var(--c-border));
  background-color: color-mix(in srgb, var(--status-color, var(--c-surface-2)) 12%, var(--c-surface-2));
}

.setting-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 0;
}

/* =========================
   Amis
   ========================= */

/* Espacement entre les cartes (Ajouter/Reçues/Envoyées/Mes amis) — sans cette règle les
   cartes s'empilent au ras les unes des autres (comportement par défaut d'un <div>). */
.friends-stack { display: flex; flex-direction: column; gap: 20px; max-width: 640px; }

.card-title-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 21px;
  height: 21px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--g2) 18%, var(--c-surface));
  color: var(--g2);
  font-size: 12px;
  font-weight: 700;
  margin-left: auto;
}

.card-title-count[hidden] { display: none; }

.friend-search { display: flex; flex-direction: column; gap: 12px; }

.friend-search-form { display: flex; gap: 10px; }

.friend-search-form .input { flex: 1; }

.friend-search-hint { font-size: 12.5px; color: var(--c-ink-faint); }

.friend-search-hint[hidden] { display: none; }

.friend-list { display: flex; flex-direction: column; gap: 10px; }

.friend-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--c-border);
  border-radius: 5px;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.friend-row:hover { background: var(--c-bg-soft); border-color: var(--c-border-strong); }

.friend-row.is-clickable { cursor: pointer; }

.friend-row.is-clickable:focus-visible {
  outline: 2px solid var(--g2);
  outline-offset: 2px;
}

.friend-chevron { display: flex; color: var(--c-ink-faint); flex: none; }

.friend-info { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1; }

.friend-name {
  font-weight: 640;
  font-size: 14.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.friend-streak {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, var(--c-accent-1), var(--c-accent-2));
  color: #fff;
  font-size: 12px;
  font-weight: 650;
  flex: none;
}

.friend-actions { display: flex; align-items: center; gap: 8px; flex: none; margin-left: auto; }

.friend-status { font-size: 12.5px; color: var(--c-ink-faint); font-style: italic; white-space: nowrap; }

/* =========================
   Profil d'un ami
   ========================= */

.friend-profile-back { margin-bottom: 14px; }

.friend-profile-head { display: flex; align-items: center; gap: 16px; }

.recap-ico.friend-profile-ico { width: 52px; height: 52px; border-radius: 6px; }

.friend-profile-streak {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  color: var(--c-ink-soft);
  font-size: 13px;
}

.setting-row .field-label { text-transform: none; font-size: 14px; letter-spacing: 0; color: var(--c-ink); }

.setting-row .setting-desc { font-size: 12.5px; color: var(--c-ink-faint); margin-top: 2px; }

.setting-row .input, .setting-row .select { width: 150px; flex: none; }

.steps-config-list { display: flex; flex-direction: column; gap: 8px; }

.steps-config-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 5px;
  background: linear-gradient(120deg, color-mix(in srgb, var(--g1) 10%, transparent), color-mix(in srgb, var(--g2) 10%, transparent));
  border: 1px solid var(--c-border);
}

.steps-config-ico { display: flex; color: var(--g2); flex: none; }

.steps-config-label { font-size: 14px; color: var(--c-ink); flex: 1; min-width: 0; }

.steps-config-actions { display: flex; align-items: center; gap: 4px; flex: none; }

.steps-config-actions .btn-icon { width: 30px; height: 30px; }

.actions-row { display: flex; flex-wrap: wrap; gap: 10px; }

.about-text { font-size: 13.5px; color: var(--c-ink-soft); line-height: 1.6; }

.pill-warning {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0;
  padding: 10px 12px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--c-warn) 12%, transparent);
  color: var(--c-ink-soft);
  font-size: 13px;
  line-height: 1.5;
}
.pill-warning .icon { flex: none; margin-top: 1px; color: var(--c-warn); }

/* =========================
   Toasts
   ========================= */

.toast-container {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 100;
  pointer-events: none;
}

.toast {
  background: var(--c-ink);
  color: var(--c-surface);
  padding: 11px 20px;
  border-radius: var(--radius-pill);
  font-size: 13.5px;
  font-weight: 590;
  box-shadow: var(--shadow-2);
  animation: toast-in 0.25s ease;
}

.toast.toast-error { background: var(--c-bad); color: #fff; }
.toast.toast-success { background: linear-gradient(135deg, #43b57e, #33b8c4); color: #fff; }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* =========================
   Célébration d'encouragement (pluie de flammes)
   ========================= */

.encourage-rain {
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
  pointer-events: none;
}

.encourage-drop {
  position: absolute;
  top: -10%;
  color: var(--c-accent-2);
  filter: drop-shadow(0 4px 10px color-mix(in srgb, var(--c-accent-2) 55%, transparent));
  animation: encourage-fall var(--duration, 2.6s) ease-in var(--delay, 0s) forwards;
}

@keyframes encourage-fall {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 0; }
  8%   { opacity: 1; }
  100% { transform: translate(var(--drift, 0px), 115vh) rotate(var(--spin, 180deg)); opacity: 0.2; }
}

.encourage-message {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  max-width: min(90vw, 380px);
  padding: 30px 38px;
  border-radius: 8px;
  background: linear-gradient(135deg, var(--c-accent-1), var(--c-accent-2));
  color: #fff;
  text-align: center;
  box-shadow: 0 6px 20px color-mix(in srgb, var(--c-accent-2) 28%, transparent);
  animation: encourage-message-in 3.4s cubic-bezier(0.2, 0.7, 0.3, 1.1) forwards;
}

.encourage-message .icon { filter: drop-shadow(0 2px 6px color-mix(in srgb, #000 25%, transparent)); }

.encourage-message p {
  margin: 0;
  font-size: 21px;
  font-weight: 750;
  line-height: 1.3;
}

@keyframes encourage-message-in {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.7) rotate(-4deg); }
  14%  { opacity: 1; transform: translate(-50%, -50%) scale(1.08) rotate(2deg); }
  22%  { transform: translate(-50%, -50%) scale(1) rotate(0deg); }
  85%  { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0deg); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(0.92) rotate(0deg); }
}

/* =========================
   États vides
   ========================= */

.empty-state { text-align: center; padding: 60px 20px; color: var(--c-ink-faint); }

.empty-state .empty-icon {
  width: 74px;
  height: 74px;
  margin: 0 auto 14px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--g-app-1), var(--g-app-2));
}

/* =========================
   Responsive — mobile first en pratique :
   tiroir de navigation (hamburger) + parcours plein écran

   Passé un certain nombre d'onglets, une barre du bas façon icônes
   ne scale plus (libellés qui débordent, "Réglages" poussé hors de
   l'écran) : sur mobile, la barre latérale devient un tiroir plein
   écran ouvert via le bouton hamburger du bandeau du haut, plutôt
   qu'une rangée d'icônes compressée.
   ========================= */

@media (max-width: 820px) {
  .app { grid-template-columns: 1fr; }

  /* Pas de sidebar à ouvrir tant qu'on n'est pas connecté (écran de
     connexion / page d'accueil publique) : le bouton hamburger n'aurait
     rien à révéler. */
  .app.no-sidebar .mobile-topbar { display: none; }

  .mobile-topbar {
    display: flex;
    align-items: center;
    gap: 12px;
    position: sticky;
    top: 0;
    z-index: 60;
    padding: calc(10px + env(safe-area-inset-top)) 14px 10px;
    background: color-mix(in srgb, var(--c-surface) 90%, transparent);
    backdrop-filter: var(--glass-filter);
    border-bottom: 1px solid var(--c-border);
  }

  .mobile-menu-btn {
    position: relative;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    border-radius: 5px;
    color: var(--c-ink-soft);
    flex: none;
    transition: background 0.15s ease, color 0.15s ease;
  }
  .mobile-menu-btn:hover { background: var(--c-bg-soft); color: var(--c-ink); }

  .mobile-topbar-brand { display: flex; align-items: center; gap: 9px; min-width: 0; }
  .mobile-topbar-title { font-size: 15.5px; font-weight: 750; letter-spacing: 0.2px; }

  /* Fond assombri derrière le tiroir ouvert, ferme le menu au clic. */
  .sidebar-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(20, 14, 36, 0.44);
    z-index: 90;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
  }
  .sidebar-backdrop.is-open { display: block; opacity: 1; pointer-events: auto; }

  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    height: 100dvh;
    width: min(82vw, 300px);
    padding: calc(20px + env(safe-area-inset-top)) 14px 18px;
    border-right: 1px solid var(--c-border);
    box-shadow: var(--shadow-2);
    z-index: 100;
    transform: translateX(-100%);
    transition: transform 0.36s var(--ease-spring);
  }
  .sidebar.is-open { transform: translateX(0); }

  .sidebar-close-btn { display: grid; }

  .view { padding: 20px 14px 40px; }

  .view-header { margin-bottom: 16px; }

  .step-hero { margin: 0 -14px; padding: 24px 20px 20px; gap: 16px; }
  .step-badge { width: 60px; height: 60px; border-radius: 7px; }
  .step-body { padding: 26px 0; gap: 18px; }
  .wizard-nav { padding: 0 0 8px; }
  .wizard-nav .btn { min-width: 104px; }

  .hbar-row { grid-template-columns: 108px 1fr 30px; }
}

@media (max-width: 480px) {
  .inline-fields { flex-direction: column; }
  .view-title h2 { font-size: 21px; }
  .date-nav { width: 100%; justify-content: space-between; }
}

/* Accessibilité : focus visible au clavier */
:focus-visible { outline: 2.5px solid var(--g-app-2); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
