/**
 * Roddier App — Design System
 * Inspiré d'Apple HIG (macOS Sequoia / iOS 18) : monochrome blanc/noir,
 * surfaces hiérarchisées, labels à opacités graduées, system colors pour statuts.
 *
 * Structure :
 *   1. Tokens sémantiques (--bg-*, --label-*, --fill-*, --separator, --tint)
 *   2. System colors (rouge, vert, etc. valeurs Apple)
 *   3. Radii + ombres
 *   4. Aliases legacy (--navy, --paper, etc.) mappés vers les tokens
 *
 * En dark mode, seuls les tokens du bloc [data-theme="dark"] changent ;
 * tous les composants en aval suivent automatiquement.
 */

:root {
  color-scheme: light;

  /* ─── Gouttière de page unifiée : main, nav, footer et lecteur radio partagent
     LA même valeur. Redéfinie à >=1024px dans app-theme.css. ─── */
  --page-gutter: clamp(1rem, 3vw, 2.5rem);

  /* ─── 1. Backgrounds (Apple iOS grouped — page grise, cards blanches qui popent) ─── */
  --bg-primary:   #f2f2f7;            /* page : systemGroupedBackground */
  --bg-secondary: #ffffff;            /* cards : secondarySystemGroupedBackground */
  --bg-tertiary:  #f2f2f7;            /* sub-éléments dans card / inputs */
  --bg-elevated:  #ffffff;            /* modals, sheets, popovers */

  /* ─── 2. Fills (fonds interactifs translucides, comme systemFill) ─── */
  --fill-primary:    rgba(0,0,0,0.05);
  --fill-secondary:  rgba(0,0,0,0.04);
  --fill-tertiary:   rgba(0,0,0,0.03);
  --fill-quaternary: rgba(0,0,0,0.02);

  /* ─── 3. Labels (textes à 4 niveaux d'opacité — Apple labelColor) ─── */
  --label-primary:    #000000;
  --label-secondary:  rgba(60,60,67,0.78);  /* a11y : 0.60 échouait WCAG AA (3.4:1) → 0.78 ≈ 4.9:1 sur blanc et #f2f2f7 */
  --label-tertiary:   rgba(60,60,67,0.30);
  --label-quaternary: rgba(60,60,67,0.18);

  /* ─── 4. Separators (fines hairlines Apple) ─── */
  --separator:        rgba(60,60,67,0.29);
  --separator-opaque: #c6c6c8;

  /* ─── 5. Tint (accent — navy de charte, app colorée) ─── */
  --tint:           #0f2544;
  --tint-secondary: #16335a;

  /* ─── 6. System colors (statuts — valeurs iOS/macOS officielles light) ─── */
  --system-red:    #ff3b30;
  --system-orange: #ff9500;
  --system-yellow: #ffcc00;
  --system-green:  #34c759;
  --system-blue:   #007aff;
  --system-indigo: #5856d6;
  --system-purple: #af52de;
  --system-pink:   #ff2d55;
  --system-teal:   #5ac8fa;
  --system-gray:   #8e8e93;

  /* ─── 7. Radii Apple ─── */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;

  /* ─── 8. Shadows (subtiles, jamais lourdes — Apple n'aime pas le drop-shadow agressif) ─── */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.08);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.12);
  --shadow-xl: 0 24px 60px rgba(0,0,0,0.16);

  /* ─── 9. Aliases legacy (ne pas supprimer — ~200 sélecteurs en aval s'en servent) ─── */
  --navy:    var(--label-primary);
  --navy2:   #1a1a1a;
  /* Navy de MARQUE pour les FONDS/bordures (texte clair dessus) — stable, ne
     suit pas le thème comme --navy (qui sert de couleur de texte contrastée). */
  --brand-navy:  #0f2544;
  --brand-navy2: #16335a;
  --text:    var(--label-primary);
  /* Alias historiques : des feuilles par écran et les vues du module Code
     appellent --text-primary / --text-secondary, qui n'ont jamais été définis.
     Sans eux le texte gardait son repli marine et devenait illisible en sombre. */
  --text-primary:   var(--label-primary);
  --text-secondary: var(--label-secondary);
  --cream:   var(--bg-primary);        /* body = page grise Apple */
  --cream-2: var(--bg-tertiary);
  --paper:   var(--bg-secondary);       /* cards = blanc qui pop sur la page */
  --off:     var(--bg-tertiary);        /* sub-éléments = gris doux */
  --white:   var(--bg-secondary);       /* alias card blanc */
  --accent:    var(--tint);
  --accent-l:  var(--fill-primary);
  --accent-2:  var(--tint-secondary);
  --accent-2-l: var(--fill-secondary);
  --blue:    var(--tint);
  --blue-l:  var(--fill-primary);
  --blue-ll: var(--fill-tertiary);
  --slate:   var(--label-secondary);
  --slate-l: var(--label-tertiary);
  --border:  var(--separator);
  --border2: var(--separator-opaque);

  /* Statuts mappés vers system colors */
  --orange:   var(--system-orange);
  --orange-l: rgba(255,149,0,0.10);
  --green:    var(--system-green);
  --green-l:  rgba(52,199,89,0.10);
  --purple:   var(--system-purple);
  --purple-l: rgba(175,82,222,0.10);
  --pink:     var(--system-pink);
  --pink-l:   rgba(255,45,85,0.10);
  --cyan:     var(--system-teal);
  --cyan-l:   rgba(90,200,250,0.12);
  --amber:    var(--system-orange);
  --amber-l:  rgba(255,149,0,0.10);

  /* ─── Palette enrichie 2026-05-26 (premium subtil — usage parcimonieux) ───
     Pas de couleurs vives sur les surfaces de base : utiliser les fills pour
     teinter discrètement les KPI, callouts ou catégories. */
  --accent-3:    #6366f1;                  /* indigo doux : info / catégorie premium */
  --accent-3-l:  rgba(99,102,241,0.08);
  --accent-4:    #14b8a6;                  /* teal raffiné : data / stats */
  --accent-4-l:  rgba(20,184,166,0.08);
  --paper-warm:  #fafaf7;                  /* fond cards apaisé (~ cream-paper) */

  /* ─── Apple System Colors — couleur thématique par section (2026-05-26) ───
     Inspirée d'iOS Settings : chaque grande section a sa couleur d'icône.
     Vivacité moyenne (saturated mais pas fluorescent). Reste lisible : texte
     blanc sur fond saturé, texte navy sur fond soft. */
  --sys-blue:    #0a84ff;                  /* Tableau de bord */
  --sys-indigo:  #5e5ce6;                  /* Planning */
  --sys-purple:  #bf5af2;                  /* Statistiques */
  --sys-pink:    #ff375f;                  /* Communication / notifications */
  --sys-red:     #ff453a;                  /* Examens / urgences */
  --sys-orange:  #ff9f0a;                  /* Véhicules */
  --sys-yellow:  #ffd60a;                  /* Admin app */
  --sys-green:   #30d158;                  /* Élèves / formation */
  --sys-mint:    #66d4cf;                  /* RGPD / sécurité */
  --sys-teal:    #40c8e0;                  /* Comptabilité */
  --sys-cyan:    #64d2ff;                  /* Documents */
  --sys-gray:    #8e8e93;                  /* Paramètres */
  --sys-brown:   #ac8e68;                  /* Archives */

  /* Versions soft pour fonds tintés (8-10 % opacité en light) */
  --sys-blue-soft:    rgba(10,132,255,0.10);
  --sys-indigo-soft:  rgba(94,92,230,0.10);
  --sys-purple-soft:  rgba(191,90,242,0.10);
  --sys-pink-soft:    rgba(255,55,95,0.10);
  --sys-red-soft:     rgba(255,69,58,0.10);
  --sys-orange-soft:  rgba(255,159,10,0.10);
  --sys-yellow-soft:  rgba(255,214,10,0.14);
  --sys-green-soft:   rgba(48,209,88,0.10);
  --sys-mint-soft:    rgba(102,212,207,0.12);
  --sys-teal-soft:    rgba(64,200,224,0.12);
  --sys-cyan-soft:    rgba(100,210,255,0.12);
  --sys-gray-soft:    rgba(142,142,147,0.12);
  --sys-brown-soft:   rgba(172,142,104,0.12);

  /* Easing Apple-like — courbes naturelles pour micro-animations */
  --ease-out-smooth: cubic-bezier(0.32, 0.72, 0, 1);     /* iOS sheet present */
  --ease-spring:     cubic-bezier(0.22, 1, 0.36, 1);     /* hover lift naturel */

  /* Ring focus signature (au lieu de l'outline browser) */
  --ring-focus:  0 0 0 3px rgba(94,127,168,0.18);        /* halo bleu désaturé */

  /* Shadows multi-couches Apple — profondeur sans lourdeur */
  --shadow-soft:    0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04);
  --shadow-raised:  0 2px 6px rgba(0,0,0,0.06), 0 12px 28px rgba(0,0,0,0.08);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,0.10), 0 24px 60px rgba(0,0,0,0.14);

  /* ════════════════════════════════════════════════════════════════════
     KIT DE FONDATION (2026-06-18) — tokens partagés par le « UI kit »
     (public/css/ui-kit.css, sheet.css). N'écrasent RIEN ci-dessus : ce sont
     des AJOUTS. Les équivalents sombres sont dans le bloc [data-theme="dark"].
     ──────────────────────────────────────────────────────────────────── */

  /* ─── Mouvement — courbes + durées standardisées (micro-interactions) ─── */
  --ease:        cubic-bezier(0.22, 0.61, 0.36, 1);   /* sortie douce, défaut */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);   /* léger rebond (entrées) */
  --dur-fast: 0.15s;
  --dur:      0.25s;
  --dur-slow: 0.40s;

  /* ─── Ombres FROIDES 3 couches (teinte navy #0f2544, jamais noir pur) ───
     Profondeur Apple sans lourdeur. Complètent --shadow-sm/md/lg historiques
     (qui restent en noir) ; on préfère ces variantes navy pour le kit. */
  --shadow-sm: 0 1px 2px rgba(15,37,68,0.06), 0 1px 1px rgba(15,37,68,0.04);
  --shadow-md: 0 1px 2px rgba(15,37,68,0.06), 0 4px 14px rgba(15,37,68,0.08);
  --shadow-lg: 0 4px 14px rgba(15,37,68,0.08), 0 14px 36px rgba(15,37,68,0.12);

  /* ─── Rayons concentriques ───────────────────────────────────────────
     Convention « coins concentriques » : un enfant à N px de marge d'un
     parent de rayon R doit avoir un rayon (R − N) pour que les arrondis
     restent parallèles. Échelle : sm 6 → md 10 → lg 14 → xl 18 (existants),
     + pill = capsule pleine. */
  --r-pill: 100px;

  /* ─── Halo radial désaturé (charte « lumière bleue » : #5e7fa8) ─── */
  --halo-color: rgba(94, 127, 168, 0.20);

  /* ─── Glass du kit (bottom sheet / toast Dynamic Island) ─── */
  --glass-bg:     rgba(255, 255, 255, 0.72);
  --glass-border: rgba(255, 255, 255, 0.55);
  --scrim:        rgba(15, 37, 68, 0.32);   /* fond assombri sous une sheet */
  --island-bg:    rgba(20, 22, 28, 0.92);   /* pilule sombre flottante (toast) */
  --island-fg:    #f5f5f7;
}

/* Base — body en blanc pur (jour) / noir pur (nuit).
   Fond uni, pas de gradient ni halo coloré (philosophie minimaliste 2026-05-25). */
body.app-body {
  background: var(--cream);
  min-height: 100vh;    /* repli pour les navigateurs sans dvh */
  min-height: 100dvh;   /* hauteur dynamique : suit l'apparition/le repli de la barre
                           du navigateur (iOS Safari/Firefox) → le bas de l'app remplit
                           toujours l'écran, plus de zone vide ni de saut quand la barre
                           d'URL se réduit en pastille. */
  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  margin: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ─── Pages d'auth (login) ──────────────────────────────────────── */
.app-auth {
  min-height: calc(100vh - 80px);
  min-height: calc(100dvh - 80px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}
.app-auth-card {
  width: 100%;
  max-width: 440px;
  background: var(--paper);
  border-radius: 18px;
  padding: clamp(1.5rem, 5vw, 2.75rem);
  box-shadow: var(--shadow-xl);
  border: 1px solid var(--border);
  position: relative;
  overflow: hidden;
}
.app-auth-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand-navy), var(--accent-2), var(--accent));
}
.app-logo {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  margin-bottom: 1.5rem;
}
.app-logo-title {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.app-logo-sub {
  font-size: 0.78rem;
  color: var(--slate);
  font-weight: 500;
}
.app-auth-title {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--navy);
  margin: 0 0 0.4rem;
  letter-spacing: -0.02em;
}
.app-auth-lead {
  font-size: 0.88rem;
  color: var(--slate);
  margin: 0 0 1.5rem;
  line-height: 1.55;
}
.app-auth-help {
  font-size: 0.82rem;
  color: var(--slate);
  margin-top: 1.5rem;
  text-align: center;
  line-height: 1.6;
}
.app-auth-help a { color: var(--blue); text-decoration: none; font-weight: 600; }
.app-auth-help a:hover { text-decoration: underline; }

/* ─── Form (Apple HIG global) ───────────────────────────────────────
   Tous les formulaires .app-form heritent automatiquement du look moderne.
   Pour des sections en cards, ajouter class .form-fancy + .form-section
   (cf bloc dedie en bas du fichier).
   ────────────────────────────────────────────────────────────────── */
.app-form { display: flex; flex-direction: column; gap: 1rem; }
.app-form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.app-field { display: flex; flex-direction: column; gap: 0.4rem; }
.app-field-full { grid-column: 1 / -1; }
/* Grille de formulaire 2 colonnes : un champ seul sur la dernière rangée occupe toute
   la largeur (supprime le champ à moitié de carte avec un grand vide à droite). */
.app-form-grid > .app-field:nth-child(odd):last-child { grid-column: 1 / -1; }
.app-label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  letter-spacing: 0;
}
.app-form input[type="text"],
.app-form input[type="email"],
.app-form input[type="password"],
.app-form input[type="tel"],
.app-form input[type="date"],
.app-form input[type="month"],
.app-form input[type="week"],
.app-form input[type="time"],
.app-form input[type="number"],
.app-form input[type="search"],
.app-form input[type="url"],
.app-form select,
.app-filters select,
.app-form textarea {
  font-family: inherit;
  font-size: 0.95rem;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  background: var(--bg-secondary);
  color: var(--label-primary);
  transition: border-color 0.15s ease, box-shadow 0.18s ease, background 0.15s ease;
  width: 100%;
  box-sizing: border-box;
}
.app-form input:hover:not(:focus),
.app-form select:hover:not(:focus),
.app-filters select:hover:not(:focus),
.app-form textarea:hover:not(:focus) {
  border-color: var(--separator-opaque);
}
.app-form input:focus,
.app-form select:focus,
.app-filters select:focus,
.app-form textarea:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background-color: var(--bg-elevated);
}
.app-form textarea { resize: vertical; min-height: 90px; line-height: 1.5; }
.app-form select,
.app-filters select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2.5rem;
}
.app-form-actions {
  display: flex;
  gap: 0.7rem;
  grid-column: 1 / -1;
  justify-content: flex-end;
  margin-top: 0.5rem;
}
/* Checkbox / Radio Apple-style : accent-color au lieu du browser default */
.app-form input[type="checkbox"],
.app-form input[type="radio"] {
  accent-color: var(--tint);
  width: 18px;
  height: 18px;
  cursor: pointer;
}

/* ─── Boutons ───────────────────────────────────────────────────── */
.app-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.65rem 1.1rem;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  border-radius: 10px;
  cursor: pointer;
  text-decoration: none;
  background: var(--paper);
  color: var(--navy);
  border: 1.5px solid var(--border);
  transition: all 0.15s ease;
  letter-spacing: 0.01em;
}
.app-btn:hover {
  background: var(--off);
  border-color: var(--border2);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.app-btn-sm { padding: 0.45rem 0.85rem; font-size: 0.82rem; }

.app-btn-primary {
  background: var(--tint);
  color: var(--bg-primary) !important;
  border: 1.5px solid var(--tint);
}
.app-btn-primary:hover {
  background: var(--tint-secondary);
  border-color: var(--tint-secondary);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
.app-btn-outline { background: transparent; color: var(--label-primary); border: 1.5px solid var(--separator-opaque); }
.app-btn-outline:hover { border-color: var(--tint); color: var(--tint); background: var(--fill-tertiary); }
.app-btn-ghost {
  background: var(--off);
  color: var(--slate);
  border: 1px solid var(--border);
  padding: 0.55rem 0.85rem;
  border-radius: 8px;
  font-size: 0.82rem;
  font-weight: 500;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.app-btn-ghost:hover { background: var(--white); color: var(--navy); border-color: var(--border2); }
.app-btn-ghost-link {
  background: none;
  border: none;
  color: var(--blue);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.4rem 0;
  cursor: pointer;
  text-decoration: none;
  text-align: left;
}
.app-btn-ghost-link:hover { text-decoration: underline; }

/* ─── Alerts ────────────────────────────────────────────────────── */
.app-alert {
  padding: 0.85rem 1.1rem;
  border-radius: 10px;
  font-size: 0.88rem;
  margin-bottom: 1rem;
  border-left: 3px solid;
}
.app-alert-error { background: #fef2f2; color: #991b1b; border-color: #dc2626; }
.app-alert-info  { background: var(--blue-ll); color: var(--navy); border-color: var(--blue); }
/* Alerte de succès : elle manquait, du coup les vues improvisaient des couleurs en dur
   (îlot clair en thème sombre). Les jetons ci-dessous changent seuls avec le thème. */
.app-alert-success { background: var(--green-l); color: var(--navy); border-color: var(--system-green); }

/* ─── Nav top bar premium : sticky + backdrop-blur (luxury saas) ───── */
.app-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--separator);
}
:root[data-theme="dark"] .app-nav {
  background: rgba(28, 28, 30, 0.72);
}
.app-nav-admin {
  background: linear-gradient(135deg, var(--navy), var(--navy2));
  color: #fff;
  border-bottom-color: transparent;
}
.app-nav-inner {
  max-width: none;
  margin: 0;
  padding: 0.85rem var(--page-gutter);
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.app-nav-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  font-weight: 800;
  font-size: 1rem;
  color: var(--navy);
  letter-spacing: -0.01em;
  flex-shrink: 0;
}
.app-nav-admin .app-nav-brand { color: #fff; }
.app-nav-admin .app-nav-brand small { color: var(--blue-l); font-weight: 400; }
.app-nav-links {
  display: flex;
  gap: 0.4rem;
  flex: 1;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  min-width: 0;
}
.app-nav-links::-webkit-scrollbar { display: none; }
.app-nav-links a {
  padding: 0.5rem 0.85rem;
  border-radius: 8px;
  text-decoration: none;
  color: var(--label-secondary);
  font-size: 0.85rem;
  font-weight: 500;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}
.app-nav-admin .app-nav-links a { color: rgba(255,255,255,0.7); }
.app-nav-links a:hover { background: var(--fill-quaternary); color: var(--label-primary); }
.app-nav-admin .app-nav-links a:hover { background: rgba(255,255,255,0.08); color: #fff; }
.app-nav-links a.active { background: var(--fill-primary); color: var(--label-primary); font-weight: 600; }
.app-nav-admin .app-nav-links a.active { background: rgba(255,255,255,0.12); color: #fff; }
/* Mode compact : ajouté par JS (initNavFit) quand les liens débordent leur espace
   → nav en icônes seules (le label reste accessible via tooltip + lecteurs d'écran).
   Garantit qu'aucun item n'est rogné, quel que soit le nombre d'items / le rôle.

   ANTI-FLASH (FOUC) — selecteur :not(.nav-ready) : tant que fitNav (nav-hamburger.js)
   n'a pas mesuré et posé .nav-ready, on n'affiche QUE les icones. Sinon les libellés
   se peignent en taille réelle à la 1re frame, puis disparaissent quand .nav-compact
   est décidé → clignotement « texte qui apparaît/disparaît », visible surtout sur
   Safari (le primer synchrone mesure mal en plein parsing). Avec ce garde, les
   libellés n'apparaissent qu'APRÈS la mesure (donc jamais à tort), en mode barre
   pleine uniquement. Indépendant du timing JS, contrairement au primer. */
.app-nav-inner.nav-compact .app-nav-links a,
.app-nav:not(.nav-ready) .app-nav-inner .app-nav-links a { font-size: 0; padding: 0.5rem 0.55rem; gap: 0; }
.app-nav-inner.nav-compact .app-nav-links a .nav-icon,
.app-nav:not(.nav-ready) .app-nav-inner .app-nav-links a .nav-icon { margin-right: 0; }
.app-nav-inner.nav-compact .app-nav-switcher-label,
.app-nav:not(.nav-ready) .app-nav-switcher-label { display: none; }
.app-nav-user {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.app-nav-icon-btn {
  width: 38px;
  height: 38px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,0.7);
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}
.app-nav-admin .app-nav-icon-btn { color: rgba(255,255,255,0.7); }
.app-nav-admin .app-nav-icon-btn:hover { background: rgba(255,255,255,0.08); color: #fff; }
.app-nav-admin .app-nav-icon-btn.active { background: rgba(255,255,255,0.15); color: #fff; }
/* Variante hors admin (nav blanche normale) */
.app-nav:not(.app-nav-admin) .app-nav-icon-btn { color: #5e7fa8; }
.app-nav:not(.app-nav-admin) .app-nav-icon-btn:hover { background: var(--off); color: var(--tint); }
.app-nav-user-info { text-align: right; }
.app-nav-user-name { font-size: 0.85rem; font-weight: 700; color: var(--navy); line-height: 1.2; }
.app-nav-admin .app-nav-user-name { color: #fff; }
.app-nav-user-sub { font-size: 0.72rem; color: var(--slate); }
.app-nav-admin .app-nav-user-sub { color: var(--blue-l); }

/* ─── Switcher de rôle (gérant ↔ enseignant) ──────────────────── */
.app-nav-switcher {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--navy);
  background: var(--cream-2);
  border: 1px solid var(--border);
  border-radius: 100px;
  text-decoration: none;
  margin-right: 0.5rem;
  white-space: nowrap;
}
.app-nav-switcher:hover {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
}
.app-nav-admin .app-nav-switcher {
  background: rgba(255,255,255,0.1);
  color: #fff;
  border-color: rgba(255,255,255,0.2);
}
.app-nav-admin .app-nav-switcher:hover {
  background: rgba(255,255,255,0.2);
  border-color: rgba(255,255,255,0.4);
}
/* Écrans étroits : switcher en icône seule pour ne pas rogner le compte dans la nav */
@media (max-width: 1366px) {
  .app-nav-switcher-label { display: none; }
  .app-nav-switcher { padding: 0.4rem; margin-right: 0.35rem; }
}
/* Sur mobile (nav stack), masquer le label texte, garder l'icône */
@media (max-width: 768px) {
  .app-nav-switcher span { display: none; }
  .app-nav-switcher { padding: 0.4rem 0.5rem; }
}

/* ─── Main / Page header ────────────────────────────────────────── */
.app-main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
  position: relative;
}

/* ─── Zones de sécurité iOS (encoche / barre d'état / indicateur d'accueil) ───
   En plein écran (ajout à l'écran d'accueil) + viewport-fit=cover, le contenu
   passe bord à bord : on ré-insère les marges via env(). max() → AUCUN effet là
   où il n'y a pas d'encoche (Android, ordinateur, iPhone sans encoche, navigateur
   classique) car env() y vaut 0. Corrige aussi le paysage iOS (encoche latérale). */
@supports (padding: env(safe-area-inset-top)) {
  /* Barre d'état (portrait) : posé sur .app-nav (et non .app-nav-inner) pour
     s'appliquer AUSSI en mode replié, où .app-nav.is-collapsed .app-nav-inner
     redéfinit le padding (spécificité plus forte) et écraserait la marge. */
  .app-nav { padding-top: env(safe-area-inset-top); }
  /* Encoche latérale (paysage, barre dépliée). */
  .app-nav-inner {
    padding-left: max(clamp(1rem, 3vw, 2.5rem), env(safe-area-inset-left));
    padding-right: max(clamp(1rem, 3vw, 2.5rem), env(safe-area-inset-right));
  }
  .app-main {
    padding-left: max(1.5rem, env(safe-area-inset-left));
    padding-right: max(1.5rem, env(safe-area-inset-right));
  }
  .app-auth { padding-top: max(2rem, calc(env(safe-area-inset-top) + 1rem)); }
}
.app-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.75rem;
}
.app-page-header h1 {
  font-size: clamp(1.6rem, 4vw, 2.1rem);
  font-weight: 800;
  color: var(--navy);
  margin: 0.25rem 0 0.4rem;
  letter-spacing: -0.025em;
  line-height: 1.15;
}
.app-page-header p {
  font-size: 0.92rem;
  color: var(--slate);
  margin: 0;
}
/* Badge "tag" en haut des pages — comme sur le site (« NEWSLETTER », « SECTEURS »...) */
.app-section-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--blue-l);
  color: var(--blue);
  padding: 0.3rem 0.75rem;
  border-radius: 100px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 0.6rem;
}

/* ─── Cards (premium 2026-05-25 : paper bg + warm shadow) ─────────── */
.app-card {
  background: var(--paper);
  border: 1px solid var(--separator);
  border-radius: 14px;
  padding: 1.5rem;
  margin-bottom: 1.25rem;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
/* Les barres d'accent au-dessus des cards ont été retirées (palette Apple HIG : pas
   d'éléments décoratifs colorés sur les surfaces, le contenu typographique porte
   l'information visuelle). Les classes restent valides pour la compat. */
.app-card-soft { background: var(--off); border-color: var(--border); }
.app-card-success { background: linear-gradient(135deg, #f0fdf4, #fff); border-color: #86efac; }
.app-card-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy);
  margin: 0 0 1rem;
  letter-spacing: -0.01em;
}
.app-two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  margin-bottom: 1.25rem;
}
.app-two-col > .app-card { margin-bottom: 0; }
.app-muted {
  color: var(--slate);
  font-size: 0.9rem;
  line-height: 1.6;
}
.app-muted a { color: var(--blue); text-decoration: none; font-weight: 600; }
.app-muted a:hover { text-decoration: underline; }

/* ─── KPI grid ──────────────────────────────────────────────────── */
.app-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}
.app-kpi {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.1rem 1.3rem;
  position: relative;
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.app-kpi::before { content: none; }
.app-kpi-icon {
  position: absolute;
  top: 0.9rem; right: 0.9rem;
  width: 32px; height: 32px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.85;
}
.app-kpi-blue .app-kpi-icon   { background: #eff6ff; color: #2563eb; }
.app-kpi-green .app-kpi-icon  { background: #f0fdf4; color: #16a34a; }
.app-kpi-orange .app-kpi-icon { background: #fff7ed; color: #ea580c; }
.app-kpi-purple .app-kpi-icon { background: #faf5ff; color: #7c3aed; }
.app-kpi-pink .app-kpi-icon   { background: #fdf2f8; color: #db2777; }
.app-kpi:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }

/* Live pulse pour le KPI "visiteurs en direct" */
.app-live-dot {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #16a34a;
  box-shadow: 0 0 0 0 rgba(22,163,74,0.5);
  animation: livePulse 2s ease-in-out infinite;
  margin-right: 0.4rem;
  vertical-align: middle;
}
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 rgba(22,163,74,0.5); }
  70%  { box-shadow: 0 0 0 8px rgba(22,163,74,0); }
  100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); }
}

/* Variantes colorées des section tags */
.app-section-tag-green  { background: #f0fdf4; color: #16a34a; }
.app-section-tag-orange { background: #fff7ed; color: #ea580c; }
.app-section-tag-purple { background: #faf5ff; color: #7c3aed; }
.app-section-tag-pink   { background: #fdf2f8; color: #db2777; }
/* Mode sombre : ces variantes ont un pastel clair codé en dur (îlot clair sur
   page sombre). Teinte sombre + texte clair. Les variantes -indigo/-teal/-blue/-red
   sont déjà en variables de thème. */
:root[data-theme="dark"] .app-section-tag-green  { background: rgba(34,197,94,0.16);  color: #4ade80; }
:root[data-theme="dark"] .app-section-tag-orange { background: rgba(234,88,12,0.18);   color: #fb923c; }
:root[data-theme="dark"] .app-section-tag-purple { background: rgba(124,58,237,0.20);  color: #a78bfa; }
:root[data-theme="dark"] .app-section-tag-pink   { background: rgba(219,39,119,0.18);  color: #f472b6; }

/* ─── Toolbar / filter bar ───────────────────────────────────────
   Pour les barres de filtre en haut de page (newsletter list, etc.)
   Layout horizontal aligné, fond doux, look "search bar" pro. */
.app-toolbar {
  display: flex;
  align-items: stretch;
  gap: 0.6rem;
  padding: 0.85rem;
  background: linear-gradient(135deg, #f8fafc, #f1f5f9);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.app-toolbar-search {
  flex: 1;
  min-width: 240px;
  position: relative;
}
.app-toolbar-search svg {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--slate-l);
  pointer-events: none;
}
.app-toolbar-search input {
  width: 100%;
  height: 42px;
  padding: 0 0.85rem 0 2.5rem;
  font-family: inherit;
  font-size: 0.9rem;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
  color: var(--text);
  box-sizing: border-box;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.app-toolbar-search input:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(0,0,0,0.12);
}
.app-toolbar-select {
  position: relative;
  min-width: 200px;
}
.app-toolbar-select select {
  height: 42px;
  padding: 0 2rem 0 0.85rem;
  font-family: inherit;
  font-size: 0.88rem;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
  color: var(--text);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  width: 100%;
  box-sizing: border-box;
}
.app-toolbar-select::after {
  content: '';
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-25%);
  width: 8px; height: 8px;
  border-right: 2px solid var(--slate);
  border-bottom: 2px solid var(--slate);
  transform: translateY(-50%) rotate(45deg);
  margin-top: -2px;
  pointer-events: none;
}
.app-toolbar-select select:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(0,0,0,0.12);
}
.app-toolbar-btn {
  height: 42px;
  padding: 0 1.3rem;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  border-radius: 10px;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  white-space: nowrap;
}
.app-toolbar-btn-primary {
  background: var(--brand-navy);
  color: #fff;
  border: 1.5px solid var(--brand-navy);
}
.app-toolbar-btn-primary:hover { background: var(--brand-navy2); }
.app-toolbar-btn-ghost {
  background: transparent;
  color: var(--slate);
  border: 1.5px solid transparent;
  text-decoration: none;
}
.app-toolbar-btn-ghost:hover { color: var(--navy); background: var(--paper); border-color: var(--border); }
.app-kpi-label {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.4rem;
}
.app-kpi-value {
  font-size: 1.85rem;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.app-kpi-value-sm { font-size: 1.05rem; line-height: 1.3; }
.app-kpi-sub {
  font-size: 0.78rem;
  color: var(--slate);
  margin-top: 0.35rem;
}

/* ─── Tables ────────────────────────────────────────────────────── */
.app-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.app-table thead th {
  text-align: left;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--label-secondary);
  padding: 0.65rem 0.5rem 0.55rem;
  border-bottom: 1px solid var(--separator);
  background: transparent;
}
.app-table tbody td {
  padding: 0.85rem 0.5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.app-table tbody tr:last-child td { border-bottom: none; }
.app-cell-name { font-weight: 600; color: var(--navy); }
.app-cell-sub { font-size: 0.78rem; color: var(--slate); }
.app-row-archived { opacity: 0.5; }
.app-row-archived .app-cell-name::after {
  content: ' (archivé)';
  color: var(--slate);
  font-size: 0.75rem;
  font-weight: 400;
}

/* ─── Polish 2026-05-25 : composants gestion ─────────────────── */

/* Wrapper de table avec card-style (rounded + shadow + border) */
.app-table-wrap {
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0,0,0,0.05), 0 1px 3px rgba(0,0,0,0.04);
  margin-bottom: 1.25rem;
}
.app-table-wrap .app-table { margin: 0; }
.app-table-wrap > table { width: 100%; border-collapse: collapse; }
/* Conteneur de défilement horizontal posé par page-loader.js autour des tableaux
   non enveloppés (évite que leurs colonnes de droite soient coupées sur mobile). */
.app-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
/* Code en ligne (URLs, identifiants…) : doit se couper pour ne pas déborder
   l'écran sur mobile. Les blocs <pre><code> sont exclus (ils défilent). */
:not(pre) > code { overflow-wrap: anywhere; word-break: break-word; }
.app-table tbody tr {
  transition: background 0.15s ease;
}
.app-table tbody tr:hover {
  background: var(--blue-ll);
}
.app-table-zebra tbody tr:nth-child(even) { background: rgba(0,0,0,0.015); }
.app-table-zebra tbody tr:nth-child(even):hover { background: var(--blue-ll); }
/* Style minimaliste Apple : pas de fond, juste un fin séparateur en bas */
.app-table thead th {
  background: transparent;
  border-top: 0;
  border-bottom: 1px solid var(--separator);
}
.app-table th { padding: 0.7rem 0.9rem 0.55rem; }
.app-table td { padding: 0.85rem 0.9rem; }
.app-table th:first-child, .app-table td:first-child { padding-left: 1.1rem; }
.app-table th:last-child, .app-table td:last-child { padding-right: 1.1rem; }

/* Badges (statut, etc.) — petits pills colorés */
.app-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.22rem 0.62rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
  line-height: 1.3;
}
/* Pastille portant une PHRASE et non une etiquette courte. Sans cela, le « white-space:
   nowrap » de .app-badge produisait une pastille de 397px dans une carte de 320 : elle
   sortait de sa carte et recouvrait le contenu voisin. Les majuscules et l interlettrage,
   concus pour un mot, sont egalement abandonnes : illisibles sur une phrase. */
.app-badge--phrase {
  white-space: normal;
  text-align: left;
  max-width: 100%;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.35;
  border-radius: 10px;
  padding: 0.3rem 0.6rem;
}
.app-badge-success { background: #dcfce7; color: #16a34a; }
.app-badge-info    { background: #dbeafe; color: #1e40af; }
.app-badge-warning { background: #fef3c7; color: #92400e; }
.app-badge-danger  { background: #fee2e2; color: #991b1b; }
.app-badge-neutral { background: #e5e7eb; color: #374151; }
.app-badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* Tags (CPF, AAC, Pro, etc.) — légers, multi-couleurs */
.app-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 5px;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.02em;
}
.app-tag-blue   { background: var(--blue-ll); color: var(--navy); }
.app-tag-green  { background: var(--green-l); color: var(--green); }
.app-tag-amber  { background: var(--amber-l); color: var(--amber); }
.app-tag-red    { background: #fef2f2; color: #b91c1c; }
.app-tag-purple { background: var(--purple-l); color: var(--purple); }
.app-tag-slate  { background: #f1f5f9; color: var(--slate); }

/* Stat cards (KPI grand chiffre, ex: solde compta) */
.app-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
}
.app-stat-card {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.1rem 1.25rem;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.app-stat-card::before { content: none; }
.app-stat-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--slate);
  font-weight: 700;
  margin-bottom: 0.4rem;
}
.app-stat-value {
  font-size: 1.85rem;
  font-weight: 800;
  color: var(--tint);
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
/* Valeurs sémantiques colorées (choix direction : compta plus lisible, moins
   monochrome) : encaissé/positif en vert, dû/impayé en rouge, info en bleu. */
.app-stat-value-success { color: #16a34a; }
.app-stat-value-danger  { color: #dc2626; }
.app-stat-value-info    { color: #0369a1; }

/* Section header (titre + actions à droite) */
.app-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1rem;
}
.app-section-header h2 {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--navy);
  margin: 0;
  letter-spacing: -0.01em;
}

/* Empty state */
.app-empty-state {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--slate);
  font-style: italic;
}
.app-empty-state strong {
  color: var(--navy);
  font-style: normal;
  display: block;
  margin-bottom: 0.3rem;
}

/* Cards cliquables (dashboards type "Contrats actifs / Formules") */
.app-card-clickable {
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
  text-decoration: none;
  color: inherit;
  display: block;
}
.app-card-clickable:hover {
  transform: translateY(-2px);
  box-shadow: 0 20px 50px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.06);
  border-color: var(--blue);
}

/* Breadcrumb compact au-dessus du titre de page */
.app-breadcrumb {
  font-size: 0.78rem;
  color: var(--slate);
  margin: 0 0 0.3rem;
}
.app-breadcrumb a {
  color: var(--blue);
  text-decoration: none;
  font-weight: 600;
}
.app-breadcrumb a:hover { text-decoration: underline; }

/* Menu Actions ▾ (dropdown) */
.app-actions {
  position: relative;
  display: inline-block;
}
.app-actions > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.42rem 0.85rem;
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 6px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--navy);
  transition: all 0.15s ease;
  user-select: none;
}
.app-actions > summary:hover {
  background: var(--blue-ll);
  border-color: var(--blue);
}
.app-actions > summary::-webkit-details-marker { display: none; }
.app-actions > summary::marker { content: ''; }
.app-actions[open] > summary { background: var(--blue-ll); border-color: var(--blue); }
.app-actions-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.35rem;
  min-width: 220px;
  box-shadow: 0 12px 36px rgba(0,0,0,0.14);
  z-index: 50;
}
.app-actions-menu button, .app-actions-menu a {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.7rem;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 6px;
  font-size: 0.85rem;
  color: var(--text);
  text-decoration: none;
  transition: background 0.15s ease;
}
.app-actions-menu button:hover, .app-actions-menu a:hover {
  background: var(--blue-ll);
  color: var(--navy);
}
.app-actions-menu button.danger {
  color: #dc2626;
  font-weight: 600;
}
.app-actions-menu button.danger:hover {
  background: #fef2f2;
  color: #b91c1c;
}
.app-actions-menu hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0.35rem 0;
}

/* Filtres form inline pour les listes */
.app-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.85rem;
  align-items: end;
}

/* Couleur pastille (compagnon des entités colorées : élève, enseignant) */
.app-color-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 0.4rem;
}
.app-color-dot-lg { width: 14px; height: 14px; }

/* Définitions list (dl) pour fiches détails */
.app-defs {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.5rem 1.1rem;
  margin: 0;
  font-size: 0.88rem;
}
.app-defs dt {
  color: var(--slate);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  padding-top: 0.05rem;
}
.app-defs dd { margin: 0; color: var(--text); }
.app-defs dd strong { color: var(--navy); font-weight: 700; }

/* Grille de cards (overviews) */
.app-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
}

/* Container max-width pour les forms étroites */
.app-container-narrow { max-width: 760px; margin-left: auto; margin-right: auto; }

/* ═══════════════════════════════════════════════════════════════════
   PASSE PREMIUM 2026-05-25 — polish typographique + composants luxe
   ═══════════════════════════════════════════════════════════════════ */

/* Typo : tighter letter-spacing aux niveaux haut, weights ajustés */
.app-page-header h1 {
  font-size: clamp(1.6rem, 3.5vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--navy);
  margin: 0;
}
.app-page-header p {
  color: var(--slate);
  font-size: 0.92rem;
  line-height: 1.6;
  margin: 0.5rem 0 0;
  font-weight: 400;
}

/* Section title (h2) plus structuré */
.app-card-title {
  font-size: 0.78rem;
  font-weight: 800;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 1rem;
}
.app-card h2:not(.app-card-title) {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--navy);
  letter-spacing: -0.015em;
  margin: 0 0 0.5rem;
}

/* Bouton primary : effet de soulèvement + ombre warm */
.app-btn-primary {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
  font-weight: 600;
  letter-spacing: 0.005em;
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
  transition: all 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.app-btn-primary:hover {
  background: var(--brand-navy2);
  border-color: var(--brand-navy2);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(0,0,0,0.18), 0 2px 4px rgba(0,0,0,0.08);
}
.app-btn {
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 8px;
}
.app-btn-outline {
  background: var(--paper);
  border-color: var(--border2);
  color: var(--navy);
}
.app-btn-outline:hover {
  border-color: var(--navy);
  background: var(--white);
  color: var(--navy);
}

/* Stat cards : fond flat Apple, sans gradient ni accent décoratif */
.app-stat-card {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.3rem 1.4rem;
  text-align: center;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.app-stat-card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

/* Table thead refinements : Apple-style, sobre, fond transparent */
.app-table thead th {
  background: transparent;
  border-top: 0;
  border-bottom: 1px solid var(--separator);
  color: var(--label-secondary);
}
.app-table tbody tr:hover {
  background: var(--cream-2);
}
.app-table-zebra tbody tr:nth-child(even) {
  background: rgba(0, 0, 0, 0.02);
}
.app-table-wrap {
  background: var(--paper);
  border-color: var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-md);
}

/* Cards cliquables : meilleure animation */
.app-card-clickable {
  border-color: var(--border);
  width: 100%;
  box-sizing: border-box;
}
.app-card-clickable:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--accent-2);
}

/* Tags : harmonie avec warm palette */
.app-tag-blue   { background: var(--blue-l); color: var(--navy); }
.app-tag-amber  { background: var(--accent-2-l); color: var(--accent-2); }
.app-tag-purple { background: var(--accent-l); color: var(--accent); }

/* Page header : breadcrumb plus discret */
.app-breadcrumb {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--accent-2);
  margin: 0 0 0.45rem;
}
.app-breadcrumb a {
  color: var(--accent-2);
}
.app-breadcrumb a:hover {
  color: var(--accent);
}

/* Form fields : look premium */
.app-form input[type="text"],
.app-form input[type="email"],
.app-form input[type="tel"],
.app-form input[type="password"],
.app-form input[type="number"],
.app-form input[type="date"],
.app-form input[type="datetime-local"],
.app-form input[type="search"],
.app-form input[type="color"],
.app-form select,
.app-form textarea {
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 8px;
  padding: 0.65rem 0.9rem;
  font-size: 0.92rem;
  color: var(--text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  font-family: inherit;
}
.app-form input:focus,
.app-form select:focus,
.app-form textarea:focus {
  outline: none;
  border-color: var(--accent-2);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.10);
}
.app-label {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Nav links : meilleur hover */
.app-nav-links a {
  font-weight: 600;
  letter-spacing: -0.005em;
}
.app-nav-links a.active {
  background: var(--cream-2);
  color: var(--navy);
  font-weight: 700;
}
.app-nav-brand {
  letter-spacing: -0.02em;
}

/* Alertes, palette chaude : l'info reprend volontairement celle posée plus haut,
   l'avertissement n'existe qu'ici. */
.app-alert-info {
  background: var(--accent-2-l);
  color: var(--text);
  border-color: var(--accent-2);
}
.app-alert-warning {
  background: #fff8ea;
  color: #78410a;
  border-color: var(--amber);
}

/* App-main : full width sur grand écran, padding généreux sur les côtés */
.app-main {
  padding: 2rem var(--page-gutter) 2rem;
  max-width: none;
  margin: 0;
}
@media (max-width: 768px) {
  .app-main { padding: 1.5rem var(--page-gutter) 1.5rem; }
}
/* Nav inner : pareil, plein écran */
.app-nav-inner {
  max-width: none;
  padding: 0.85rem var(--page-gutter);
}
/* Footer inner pareil */
.app-footer-inner {
  max-width: none;
  padding: 0;
}

/* Footer pleine largeur (Apple-style) — voir aussi bloc structure plus bas */
.app-footer a { color: var(--label-secondary); text-decoration: none; }
.app-footer a:hover { color: var(--label-primary); text-decoration: underline; }

/* Defs list : look premium */
.app-defs dt {
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
}
.app-defs dd strong { color: var(--navy); font-weight: 700; }

/* Empty state : plus visible */
.app-empty-state {
  padding: 3rem 1rem;
  color: var(--slate);
}
.app-empty-state strong {
  color: var(--navy);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  display: block;
  margin-bottom: 0.4rem;
  font-style: normal;
}

/* Actions menu : meilleur visuel */
.app-actions > summary {
  background: var(--paper);
  border-color: var(--border2);
  font-weight: 600;
}
.app-actions > summary:hover {
  background: var(--cream-2);
  border-color: var(--accent-2);
}
.app-actions-menu {
  background: var(--paper);
  border-color: var(--border);
  box-shadow: var(--shadow-lg);
}
.app-actions-menu button:hover,
.app-actions-menu a:hover {
  background: var(--cream-2);
  color: var(--navy);
}

/* ─── Progression ───────────────────────────────────────────────── */
.app-progress-list { display: flex; flex-direction: column; gap: 0.9rem; }
.app-progress-row { display: flex; flex-direction: column; gap: 0.35rem; }
.app-progress-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--navy);
}
.app-progress-count {
  font-size: 0.78rem;
  color: var(--slate);
  font-weight: 500;
}
.app-progress-bar {
  height: 8px;
  background: var(--off);
  border-radius: 100px;
  overflow: hidden;
}
.app-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--blue), var(--brand-navy2));
  border-radius: 100px;
  transition: width 0.6s ease;
}

/* ─── Sessions list ─────────────────────────────────────────────── */
.app-session-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.app-session-item {
  display: flex;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}
.app-session-list-detailed .app-session-item { padding: 1.2rem 0; }
.app-session-item:last-child { border-bottom: none; }
.app-session-date {
  flex-shrink: 0;
  width: 90px;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--blue);
  font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.app-session-time {
  font-size: 0.72rem;
  color: var(--slate);
  font-weight: 500;
  margin-top: 0.15rem;
}
.app-session-body { flex: 1; min-width: 0; }
.app-session-type {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--navy);
  margin-bottom: 0.2rem;
}
.app-session-meta {
  font-size: 0.78rem;
  color: var(--slate);
  margin-bottom: 0.3rem;
}
.app-session-notes {
  font-size: 0.85rem;
  color: var(--text);
  line-height: 1.55;
  margin-top: 0.4rem;
  padding-left: 0.7rem;
  border-left: 2px solid var(--border2);
}
.app-session-themes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.5rem;
}
.app-theme-chip {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--blue-ll);
  color: var(--blue);
  border: 1px solid var(--blue-l);
}
.app-theme-chip[data-level="3"] { background: #ecfdf5; color: #15803d; border-color: #86efac; }
.app-theme-chip[data-level="4"] { background: var(--brand-navy); color: #fff; border-color: var(--brand-navy); }

/* ─── Theme picker (admin log-session) ──────────────────────────── */
.app-theme-cat {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.2rem 1.2rem;
  margin: 0 0 1rem;
}
.app-theme-cat legend {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--blue);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0 0.5rem;
}
.app-theme-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.85rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.app-theme-row:last-child { border-bottom: none; }
.app-theme-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  cursor: pointer;
  font-size: 0.88rem;
  color: var(--text);
}
.app-theme-check input { width: 16px; height: 16px; accent-color: var(--blue); cursor: pointer; }
.app-theme-row select {
  font-family: inherit;
  font-size: 0.78rem;
  padding: 0.35rem 2rem 0.35rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background-color: var(--white);
  color: var(--text);
}
.app-theme-row select:disabled { opacity: 0.4; background: var(--off); }

/* ─── Documents ─────────────────────────────────────────────────── */
.app-doc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.7rem; }
.app-doc-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1rem;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.app-doc-icon {
  width: 40px; height: 40px;
  background: var(--blue-ll);
  color: var(--blue);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.app-doc-body { flex: 1; min-width: 0; }
.app-doc-type {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.app-doc-title { font-weight: 600; color: var(--navy); font-size: 0.92rem; }
.app-doc-date { font-size: 0.78rem; color: var(--slate); margin-top: 0.15rem; }

/* ─── Credential display (after new student creation) ───────────── */
.app-cred-box {
  background: var(--off);
  border: 1px dashed var(--border2);
  border-radius: 10px;
  padding: 1rem 1.2rem;
  margin-top: 1rem;
  font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.app-cred-row {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.5rem 0;
}
.app-cred-row + .app-cred-row { border-top: 1px solid var(--border); }
.app-cred-label {
  font-family: inherit;
  font-size: 0.75rem;
  color: var(--slate);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  min-width: 130px;
}
.app-cred-value {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy);
  background: var(--paper);
  padding: 0.3rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  user-select: all;
}

/* ─── Footer Apple-style : 4 colonnes + ligne legal bottom ───────── */
.app-footer {
  background: var(--bg-secondary);
  border-top: 1px solid var(--separator);
  padding: 2rem var(--page-gutter) 1.25rem;
  margin-top: 1.5rem;
}
/* Mode enseignant : footer vitrine masqué UNIQUEMENT sur appareil tactile (tablette).
   Sur PC / écran avec souris (pointer fin), il reste affiché. */
@media (pointer: coarse) {
  .app-footer-ens { display: none !important; }
}
/* Tablette / tactile (html.app-touch-lock posé par head.ejs selon pointer:coarse) :
   - pas de zoom par double-tap (touch-action: manipulation), le scroll reste OK ;
   - sélection et copie de texte interdites (expérience appli verrouillée).
   La saisie dans les champs reste sélectionnable. Sur ordinateur (souris) : tout normal. */
html.app-touch-lock { touch-action: manipulation; }
html.app-touch-lock, html.app-touch-lock body {
  -webkit-user-select: none; -moz-user-select: none; user-select: none; -webkit-touch-callout: none;
}
html.app-touch-lock input, html.app-touch-lock textarea, html.app-touch-lock select,
html.app-touch-lock [contenteditable], html.app-touch-lock [contenteditable] * {
  -webkit-user-select: text; -moz-user-select: text; user-select: text;
}
.app-footer-inner {
  max-width: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  font-size: 0.78rem;
  color: var(--label-secondary);
}
.app-footer-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.5rem 2rem;
}
.app-footer-col strong {
  display: block;
  color: var(--label-primary);
  font-size: 0.78rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
  letter-spacing: 0.01em;
}
.app-footer-col p {
  margin: 0;
  font-size: 0.76rem;
  line-height: 1.55;
  color: var(--label-secondary);
}
.app-footer-brand { font-size: 0.88rem !important; letter-spacing: -0.01em; }
/* Marque (logo + nom) déplacée du bandeau du haut vers le footer (bas à gauche).
   Reprend le logo Roddier APP (ou le logo premium de l'école). Le SVG s'adapte déjà au
   thème (cercle/route inversés en sombre). */
.brand-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  margin-bottom: 0.5rem;
}
.brand-mark-logo { flex-shrink: 0; display: block; }
.brand-mark-img { height: 26px; max-width: 130px; object-fit: contain; display: block; }
.brand-mark-name {
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--navy);
  line-height: 1;
}
.brand-mark-name small { font-weight: 500; color: var(--label-secondary); letter-spacing: 0; }
.brand-mark:hover .brand-mark-name { color: var(--tint, #5e7fa8); }
:root[data-theme="dark"] .brand-mark-name { color: #f2f2f7; }
.app-footer-links {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.app-footer-links a {
  font-size: 0.76rem;
  color: var(--label-secondary);
  text-decoration: none;
}
.app-footer-links a:hover { color: var(--label-primary); text-decoration: underline; }
.app-footer-bottom {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--separator);
  font-size: 0.72rem;
  color: var(--label-secondary);  /* a11y : tertiary (0.30) = 1.7:1, illisible → secondary lisible */
  flex-wrap: wrap;
}
.app-footer-sep { opacity: 0.5; }
.app-footer-version {
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  font-size: 0.7rem;
}
@media (max-width: 640px) {
  /* Grilles de saisie déclarées en style inline (grid-template-columns à
     colonnes explicites, ex. "1fr 1fr" ou "130px 1fr 1.4fr auto") : un @media
     ne peut pas surclasser un style inline sans !important → passage en
     1 colonne. Garde-fous : on ne cible que les grilles contenant directement
     des champs (label/input/select/textarea) — jamais les grilles auto-fit /
     auto-fill (déjà fluides) ni les calendriers type planning (cellules div).
     :where() = spécificité nulle : toute règle !important dédiée (ex.
     .dispo-add-grid plus bas) garde le dernier mot. */
  :where([style*="grid-template-columns"]:not([style*="auto-fit"]):not([style*="auto-fill"]):has(> label, > input, > select, > textarea)) {
    grid-template-columns: 1fr !important;
  }
  .app-footer { padding: 1.5rem var(--page-gutter) 1rem; }
  .app-footer-cols { gap: 1.25rem; }
}

/* ─── Responsive ────────────────────────────────────────────────── */
@media (max-width: 880px) {
  .app-two-col { grid-template-columns: 1fr; }
  .app-form-grid { grid-template-columns: 1fr; }
  .app-nav-inner { gap: 1rem; padding: 0.7rem 1rem; }
  /* Une seule ligne : marque · liens (compactés en icônes par initNavFit) · utilisateur à droite.
     (On ne réordonne plus les liens en pleine largeur — ça renvoyait jour/nuit + déconnexion au milieu.) */
  .app-nav-user { margin-left: auto; }
  .app-main { padding: 1.5rem 1rem 3rem; }
  .app-card { padding: 1.2rem; }
  .app-table { font-size: 0.82rem; }
  .app-table thead th, .app-table tbody td { padding: 0.5rem 0.4rem; }
  .app-table th:nth-child(3),
  .app-table td:nth-child(3),
  .app-table th:nth-child(6),
  .app-table td:nth-child(6) { display: none; }
  .app-session-item { flex-direction: column; gap: 0.4rem; }
  .app-session-date { width: auto; }
  .app-theme-row { grid-template-columns: 1fr; }
  .app-theme-row select { justify-self: start; }
  .app-cred-row { flex-direction: column; gap: 0.2rem; }
  .app-cred-label { min-width: 0; }
}

/* ───────────────────────────────────────────────────────────────────
   PREMIUM LOOK & FEEL — Halos lumineux signature + micro-animations
   Cohérent avec roddier.pro (charte couleur Julien Roddier)
   ─────────────────────────────────────────────────────────────────── */

/* Halo signature sur le body (subtil, mode clair) */
body.app-body { position: relative; }
body.app-body::before {
  content: '';
  position: fixed;
  inset: 0;
  background:
    radial-gradient(ellipse 50% 40% at 95% 5%, rgba(0,0,0,0.07), transparent 70%),
    radial-gradient(ellipse 45% 35% at 5% 95%, rgba(22,163,74,0.05), transparent 70%);
  pointer-events: none;
  z-index: 0;
}
/* .app-nav exclu : il garde son position:sticky + z-index:100 (cf. plus haut)
   pour rester collant ET au-dessus du contenu (sinon le panneau notifications
   se retrouvait piégé sous les boutons de page). Il passe déjà au-dessus du
   fond animé grâce à son z-index:100 > -1. */
.app-main, .app-footer { position: relative; z-index: 1; }

/* Smooth color transitions sur tous les éléments (pour les changements de theme) */
.app-card, .app-kpi, .app-auth-card, .app-nav,
.app-form input, .app-form select, .app-form textarea,
.app-btn, .app-toolbar, .app-table tbody td {
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.2s ease, box-shadow 0.25s ease, transform 0.15s ease;
}

/* Anim subtile au load des cards */
@keyframes appCardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Entrée de PAGE : à chaque navigation, le contenu apparaît en fondu + léger glissé
   vers le haut (sensation « app qui s'ouvre / qu'on change »). Joue dans tous les cas. */
@keyframes appPageIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes appFadeOnly { from { opacity: 0; } to { opacity: 1; } }
.app-main { animation: appPageIn 0.42s var(--ease-out-smooth, cubic-bezier(0.22,0.61,0.36,1)) both; }
.app-card, .app-kpi { animation: appCardIn 0.35s ease backwards; }
.app-kpi:nth-child(1) { animation-delay: 0.05s; }
.app-kpi:nth-child(2) { animation-delay: 0.1s; }
.app-kpi:nth-child(3) { animation-delay: 0.15s; }
.app-kpi:nth-child(4) { animation-delay: 0.2s; }
.app-kpi:nth-child(5) { animation-delay: 0.25s; }
/* « Réduire les animations » : on garde une interface VIVANTE — entrées en simple
   fondu (sans glissé) et transitions douces conservées (couleur/opacité ne gênent
   pas). On ne coupe plus tout, sinon l'app paraît figée. */
@media (prefers-reduced-motion: reduce) {
  .app-main, .app-card, .app-kpi { animation: appFadeOnly 0.3s ease both; }
  .app-kpi { animation-delay: 0s; }
}

/* Barre de chargement de page (navigation lente) — cf page-loader.js. */
.app-page-loader {
  position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 99999;
  pointer-events: none; opacity: 0; transition: opacity 0.2s ease;
  background: linear-gradient(90deg, transparent, var(--accent-2, #0f2544), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
}
.app-page-loader.active { opacity: 1; animation: appLoaderSlide 1.05s ease-in-out infinite; }
@keyframes appLoaderSlide {
  0%   { background-position: -40% 0; }
  100% { background-position: 140% 0; }
}

/* Hover lift renforcé sur les cards interactives */
a.app-card:hover, .app-card.app-card-interactive:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 50px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.06);
}

/* ═══════════════════════════════════════════════════════════
   MODE BORNE (kiosk) — tablette dédiée
   Posé par device-id.js (html.app-kiosk) quand l'école active le mode borne sur
   l'appareil. Masque le compte / la déconnexion / le changement d'espace et le
   lanceur d'assistance ; un bouton discret (injecté par le JS) ouvre la sortie par
   code école. Combiné à l'Accès guidé iOS = tablette verrouillée sur Roddier APP.
   ═══════════════════════════════════════════════════════════ */
html.app-kiosk .app-nav-user,
html.app-kiosk .ai-launcher { display: none !important; }

/* ═══════════════════════════════════════════════════════════
   PLANNING — composants premium (jour / semaine / mois)
   Utilise uniquement des var() → s'adapte au dark mode tout seul.
   ═══════════════════════════════════════════════════════════ */
.app-planning-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  align-items: center;
  justify-content: space-between;   /* tabs à gauche, filtres à droite */
  margin: 1rem 0;
}
.app-planning-tabs {
  display: inline-flex;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 4px;
  gap: 0;
  height: 38px;
  box-sizing: border-box;
  box-shadow: var(--shadow-sm);
}
.app-planning-tab {
  display: inline-flex;
  align-items: center;
  padding: 0 1.1rem;
  border-radius: 100px;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  color: var(--slate);
  transition: color 0.18s, background 0.18s;
}
.app-planning-tab:hover { color: var(--navy); }
.app-planning-tab[aria-selected="true"] {
  background: var(--paper);
  color: var(--accent);
  box-shadow: 0 2px 6px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
}

/* Filtres Bureau / Enseignant — pills cohérents avec les tabs (38px de haut) */
.app-planning-filters {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}
.app-planning-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 38px;
  box-sizing: border-box;
  padding: 0 0.85rem 0 1rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 100px;
  transition: border-color 0.18s, box-shadow 0.18s;
  cursor: pointer;
}
.app-planning-filter:hover { border-color: var(--accent-2); box-shadow: var(--shadow-sm); }
.app-planning-filter:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0,0,0,0.10); }
.app-planning-filter-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--slate);
}
.app-planning-filter select {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  outline: 0;
  padding: 0 1.4rem 0 0;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: inherit;
  color: var(--navy);
  cursor: pointer;
  max-width: 200px;
  text-overflow: ellipsis;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235c6373' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.2rem center;
}

/* ─── Vue SEMAINE ─── */
.app-planning-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.6rem;
  margin: 1rem 0;
}
.app-planning-week-day {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.7rem;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.18s;
}
.app-planning-week-day:hover { box-shadow: var(--shadow-md); }
.app-planning-week-day.is-weekend { background: var(--off); }
.app-planning-week-day.is-today {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), var(--shadow-md);
}
.app-planning-week-day-head {
  margin-bottom: 0.55rem;
  text-align: center;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.45rem;
}
.app-planning-week-day-name {
  font-size: 0.68rem;
  text-transform: uppercase;
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
}
.app-planning-week-day.is-today .app-planning-week-day-name { color: var(--accent); }
.app-planning-week-day-num {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--navy);
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  letter-spacing: -0.02em;
}
.app-planning-week-day.is-today .app-planning-week-day-num { color: var(--accent); }
.app-planning-week-empty {
  font-size: 0.78rem;
  color: var(--slate);
  text-align: center;
  margin: auto 0;
  font-style: italic;
}
.app-planning-week-events { display: flex; flex-direction: column; gap: 0.35rem; }
.app-planning-week-evt {
  color: #fff;
  border-radius: 6px;
  padding: 0.4rem 0.55rem;
  font-size: 0.74rem;
  line-height: 1.3;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  transition: transform 0.12s;
}
.app-planning-week-evt:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(0,0,0,0.18); }
.app-planning-week-evt-time {
  font-weight: 700;
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  font-size: 0.66rem;
  opacity: 0.92;
}
.app-planning-week-evt-name { font-weight: 600; font-size: 0.78rem; }
.app-planning-week-evt-meta { opacity: 0.82; font-size: 0.66rem; }

/* ─── Vue MOIS ─── */
.app-planning-month-head {
  text-align: center;
  font-size: 0.68rem;
  text-transform: uppercase;
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.app-planning-month-cell {
  min-height: 90px;
  padding: 0.4rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.72rem;
}
.app-planning-month-cell.is-other-month { opacity: 0.45; background: var(--off); }
.app-planning-month-cell.is-today {
  background: var(--accent-l);
  border-color: var(--accent);
}
.app-planning-month-cell-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.3rem;
}
.app-planning-month-num { font-weight: 700; color: var(--navy); }
.app-planning-month-cell.is-today .app-planning-month-num { color: var(--accent); }
.app-planning-month-count { font-size: 0.62rem; color: var(--slate); }
.app-planning-month-evt {
  color: #fff;
  border-radius: 3px;
  padding: 1px 5px;
  margin-bottom: 2px;
  font-size: 0.62rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.app-planning-month-more {
  font-size: 0.62rem;
  color: var(--slate);
  text-decoration: none;
  font-weight: 600;
}
.app-planning-month-more:hover { color: var(--accent); }

/* ─── Planning : adaptation smartphone / petite tablette ───────────────────
   La vue JOUR (grille horaire) est traitée dans planning.ejs (largeur mini de
   colonne + carte défilante). Ici : vues SEMAINE / MOIS + barre d'outils. */
@media (max-width: 768px) {
  /* SEMAINE : 7 colonnes de ~50px illisibles → on empile en 2 colonnes
     (petite tablette) puis 1 colonne (téléphone, règle plus bas). */
  .app-planning-week { grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
  .app-planning-week-day { min-height: 0; }
}
@media (max-width: 540px) {
  /* SEMAINE : liste verticale pleine largeur (agenda) — events lisibles. */
  .app-planning-week { grid-template-columns: 1fr; }

  /* Barre d'outils : onglets en segmenté pleine largeur + filtres empilés. */
  .app-planning-toolbar { gap: 0.6rem; }
  .app-planning-tabs { width: 100%; justify-content: center; }
  .app-planning-tab { flex: 1; justify-content: center; padding: 0 0.6rem; }
  .app-planning-filters { width: 100%; }
  .app-planning-filter { flex: 1 1 auto; min-width: 0; }
  .app-planning-filter select { max-width: none; width: 100%; }

  /* MOIS : cellules plus compactes pour tenir la largeur sans déborder. */
  .app-planning-month-cell { min-height: 64px; padding: 0.3rem; }

  /* Actions d'en-tête : grille 3 colonnes compacte (au lieu de 7 boutons
     pleine largeur empilés). Le display:grid prime sur le style inline flex.
     Rangée 1 : ← Aujourd'hui →. Rangée 2 : Télécharger Aperçu Mail.
     « + Nouvel événement » occupe sa propre rangée pleine largeur. */
  .app-planning-actions {
    display: grid !important;
    /* !important : la règle d'en-tête fiche élève (.app-page-header>div:last-child)
       a une spécificité plus forte et imposerait 2 colonnes sinon. */
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 0.4rem;
  }
  .app-planning-actions .app-btn { padding: 0.55rem 0.4rem; font-size: 0.8rem; }
  .app-planning-actions #new-event-btn { grid-column: 1 / -1; }
}

/* ─── Légende ─── */
.app-planning-legend-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.75rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 100px;
  font-size: 0.78rem;
  color: var(--navy);
}

/* ── Theme switch : interrupteur 3 positions (Clair / Auto / Sombre) ──
   Ordre visuel gauche → droite : ☀ Clair · ⊙ Système · ☾ Sombre. */
.app-theme-switch {
  box-sizing: border-box;   /* la height 38 inclut border + padding, sinon le thumb (absolute) se décale par rapport aux opts (flex) */
  display: inline-flex;
  align-items: center;
  position: relative;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 4px;
  gap: 0;
  height: 38px;
  box-shadow: var(--shadow-sm);
}
.app-theme-switch-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 36px;
  height: 28px;
  background: #ffffff;
  border-radius: 100px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18), 0 0 0 1px rgba(0,0,0,0.08);
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.2s;
  z-index: 1;
}
:root[data-theme="dark"] .app-theme-switch-thumb {
  background: #ffffff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.50), 0 0 0 1px rgba(255,255,255,0.06);
}
:root[data-theme="dark"] .app-theme-switch-opt[aria-pressed="true"] {
  color: #000000;
}
.app-theme-switch-opt {
  position: relative;
  z-index: 2;
  width: 36px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: var(--slate);
  cursor: pointer;
  padding: 0;
  border-radius: 100px;
  transition: color 0.2s;
}
.app-theme-switch-opt svg { width: 15px; height: 15px; }
.app-theme-switch-opt:hover { color: var(--navy); }
.app-theme-switch-opt[aria-pressed="true"] { color: var(--accent); }

/* Position du thumb selon la pref active (largeur opt 36px) */
[data-theme-pref="light"] .app-theme-switch-thumb { transform: translateX(0); }
[data-theme-pref="auto"]  .app-theme-switch-thumb { transform: translateX(36px); }
[data-theme-pref="dark"]  .app-theme-switch-thumb { transform: translateX(72px); }
/* Fallback : avant que le bootstrap ait set la pref, pose le thumb sur "auto" */
:root:not([data-theme-pref]) .app-theme-switch-thumb { transform: translateX(36px); }

/* Variante en nav admin (fond sombre) */
.app-nav-admin .app-theme-switch {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.12);
}
.app-nav-admin .app-theme-switch-thumb {
  background: rgba(255,255,255,0.18);
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}
.app-nav-admin .app-theme-switch-opt { color: rgba(255,255,255,0.62); }
.app-nav-admin .app-theme-switch-opt:hover { color: #fff; }
.app-nav-admin .app-theme-switch-opt[aria-pressed="true"] { color: #fff; }

/* ── Compatibilité héritée : l'ancien .app-theme-toggle reste stylisé
   pour le cas où une vue n'aurait pas encore migré vers le switch. */
.app-theme-toggle {
  width: 36px; height: 30px;
  border-radius: 100px;
  background: var(--off);
  border: 1px solid var(--border);
  color: var(--slate);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
  font-family: inherit;
}
.app-theme-toggle:hover { color: var(--accent); border-color: var(--accent-2); }
.app-nav-admin .app-theme-toggle { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.12); color: rgba(255,255,255,0.75); }
.app-nav-admin .app-theme-toggle:hover { background: rgba(255,255,255,0.12); color: #fff; }
.app-theme-toggle .icon-sun,
.app-theme-toggle .icon-moon,
.app-theme-toggle .icon-system { width: 16px; height: 16px; display: none; }
[data-theme-pref="auto"]  .app-theme-toggle .icon-system { display: block; }
[data-theme-pref="light"] .app-theme-toggle .icon-sun    { display: block; }
[data-theme-pref="dark"]  .app-theme-toggle .icon-moon   { display: block; }
:root:not([data-theme-pref]) .app-theme-toggle .icon-system { display: block; }

/* ───────────────────────────────────────────────────────────────────
   DARK MODE — approche par INVERSION des variables CSS
   (cohérent avec dev.roddier.pro/assets/style.css)

   Stratégie : on inverse les variables de base de telle sorte que tout
   ce qui utilise var(--navy), var(--text), var(--white) etc. s'adapte
   automatiquement. Pas besoin d'override 50 sélecteurs.

   - var(--navy)  : couleur du texte sombre en clair → devient claire en dark
   - var(--white) : fond carte en clair → devient slate-navy en dark
   - var(--off)   : fond sub-carte → devient encore plus élevé
   - --blue reste un peu pareil (juste plus lumineux en dark)

   theme.js applique [data-theme="light"] ou "dark" au <html> (jamais vide).
   ─────────────────────────────────────────────────────────────────── */

:root[data-theme="dark"] {
  color-scheme: dark;

  /* ─── Backgrounds (Apple macOS dark — pas de noir pur, gris doux qui repose les yeux) ─── */
  --bg-primary:   #1c1c1e;            /* page : darkSystemGroupedBackground */
  --bg-secondary: #2c2c2e;            /* cards : secondarySystem dark */
  --bg-tertiary:  #3a3a3c;            /* sub-éléments / inputs */
  --bg-elevated:  #2c2c2e;            /* modals dark */

  /* ─── Fills (translucides, plus opaques qu'en light) ─── */
  --fill-primary:    rgba(255,255,255,0.16);
  --fill-secondary:  rgba(255,255,255,0.12);
  --fill-tertiary:   rgba(255,255,255,0.08);
  --fill-quaternary: rgba(255,255,255,0.05);

  /* ─── Labels (4 opacités, base blanche) ─── */
  --label-primary:    #ffffff;
  --label-secondary:  rgba(235,235,245,0.60);
  --label-tertiary:   rgba(235,235,245,0.30);
  --label-quaternary: rgba(235,235,245,0.18);

  /* ─── Separators (gris froid Apple) ─── */
  --separator:        rgba(84,84,88,0.65);
  --separator-opaque: #38383a;

  /* ─── Tint (accent — blanc en dark) ─── */
  --tint:           #ffffff;
  --tint-secondary: #f0f0f0;

  /* ─── System colors (variantes dark officielles Apple) ─── */
  --system-red:    #ff453a;
  --system-orange: #ff9f0a;
  --system-yellow: #ffd60a;
  --system-green:  #30d158;
  --system-blue:   #0a84ff;
  --system-indigo: #5e5ce6;
  --system-purple: #bf5af2;
  --system-pink:   #ff375f;
  --system-teal:   #64d2ff;
  --system-gray:   #8e8e93;

  /* ─── Shadows (peu de drop-shadow en dark — Apple privilégie les borders) ─── */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.50);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.60);
  --shadow-xl: 0 24px 60px rgba(0,0,0,0.70);

  /* ─── Status fills (dark : opacité bumpée pour rester lisible) ─── */
  --orange-l: rgba(255,159,10,0.16);
  --green-l:  rgba(48,209,88,0.16);
  --purple-l: rgba(191,90,242,0.16);
  --pink-l:   rgba(255,55,95,0.16);
  --cyan-l:   rgba(100,210,255,0.18);
  --amber-l:  rgba(255,159,10,0.16);

  /* ─── Aliases legacy override pour dark (--navy2 est en dur en light) ─── */
  --navy2: #f0f0f0;
  /* Navy de marque, un cran plus clair en sombre pour rester visible/lisible. */
  --brand-navy:  #21487a;
  --brand-navy2: #2d5b94;

  /* ─── Palette enrichie : variantes dark (un poil plus saturées pour lisibilité) ─── */
  --accent-3:    #818cf8;                  /* indigo plus clair en dark */
  --accent-3-l:  rgba(129,140,248,0.14);
  --accent-4:    #2dd4bf;                  /* teal vivifié */
  --accent-4-l:  rgba(45,212,191,0.14);
  --paper-warm:  #2c2c2e;                  /* alignement bg-secondary */

  /* ─── Apple System Colors dark — couleurs illuminées (convention iOS) ─── */
  --sys-blue:    #0a84ff;
  --sys-indigo:  #7d7aff;
  --sys-purple:  #d77eff;
  --sys-pink:    #ff5e85;
  --sys-red:     #ff6961;
  --sys-orange:  #ffbe55;
  --sys-yellow:  #ffe46b;
  --sys-green:   #5dde7f;
  --sys-mint:    #82e0db;
  --sys-teal:    #67d8ec;
  --sys-cyan:    #84def4;
  --sys-gray:    #a9a9b0;
  --sys-brown:   #c2a888;

  /* Softs plus opaques en dark pour rester perceptibles sur fond sombre */
  --sys-blue-soft:    rgba(10,132,255,0.18);
  --sys-indigo-soft:  rgba(125,122,255,0.20);
  --sys-purple-soft:  rgba(215,126,255,0.18);
  --sys-pink-soft:    rgba(255,94,133,0.18);
  --sys-red-soft:     rgba(255,105,97,0.18);
  --sys-orange-soft:  rgba(255,190,85,0.18);
  --sys-yellow-soft:  rgba(255,228,107,0.20);
  --sys-green-soft:   rgba(93,222,127,0.18);
  --sys-mint-soft:    rgba(130,224,219,0.20);
  --sys-teal-soft:    rgba(103,216,236,0.20);
  --sys-cyan-soft:    rgba(132,222,244,0.20);
  --sys-gray-soft:    rgba(169,169,176,0.20);
  --sys-brown-soft:   rgba(194,168,136,0.20);

  /* Ring focus (anneau plus visible sur fond sombre) */
  --ring-focus:  0 0 0 3px rgba(129,140,248,0.30);

  /* Shadows dark — fonctionnent surtout par contraste (Apple en met peu) */
  --shadow-soft:    0 1px 3px rgba(0,0,0,0.40), 0 4px 12px rgba(0,0,0,0.30);
  --shadow-raised:  0 2px 6px rgba(0,0,0,0.50), 0 12px 28px rgba(0,0,0,0.50);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,0.55), 0 24px 60px rgba(0,0,0,0.60);

  /* ─── Kit de fondation : équivalents sombres (2026-06-18) ───
     Mouvement + rayons sont indépendants du thème → pas redéfinis ici.
     Ombres : en sombre on revient à un noir profond (le navy clair ne pose
     pas sur fond noir). Glass + scrim + halo ajustés pour le fond sombre. */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.50);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.60);

  --halo-color:   rgba(94, 127, 168, 0.28);
  --glass-bg:     rgba(40, 42, 48, 0.72);
  --glass-border: rgba(255, 255, 255, 0.12);
  --scrim:        rgba(0, 0, 0, 0.55);
  --island-bg:    rgba(28, 30, 36, 0.94);
  --island-fg:    #f5f5f7;
}

/* Body en dark mode — fond noir pur, pas de halo coloré */
:root[data-theme="dark"] body.app-body {
  background: var(--cream);
  color: var(--text);
}
:root[data-theme="dark"] body.app-body::before {
  background: none;
}

/* Cards / surfaces qui utilisent fond #fff hardcodé (pas via var) */
:root[data-theme="dark"] .app-card,
:root[data-theme="dark"] .app-kpi,
:root[data-theme="dark"] .app-auth-card,
:root[data-theme="dark"] .app-nav:not(.app-nav-admin),
:root[data-theme="dark"] .app-footer {
  background: var(--white);
  border-color: var(--border);
  box-shadow: 0 10px 40px rgba(0,0,0,0.3), 0 2px 6px rgba(0,0,0,0.15);
}
:root[data-theme="dark"] .app-card-soft,
:root[data-theme="dark"] .app-doc-item,
:root[data-theme="dark"] .app-cred-box,
:root[data-theme="dark"] .app-card-success { background: var(--off); border-color: var(--border); }

/* Forms / inputs */
:root[data-theme="dark"] .app-form input,
:root[data-theme="dark"] .app-form select,
:root[data-theme="dark"] .app-form textarea,
:root[data-theme="dark"] .app-toolbar-search input,
:root[data-theme="dark"] .app-toolbar-select select { background-color: var(--off); border-color: var(--border); color: var(--text); }
:root[data-theme="dark"] .app-toolbar { background: linear-gradient(135deg, var(--white), var(--off)); border-color: var(--border); }

/* Nav admin garde son look navy (gradient sombre) en LIGHT comme en DARK */
.app-nav-admin {
  background: linear-gradient(135deg, #0f2544, #1a3a6b) !important;
  color: #fff;
  border-bottom-color: transparent;
}
.app-nav-admin .app-nav-brand,
.app-nav-admin .app-nav-brand span { color: #fff !important; }
.app-nav-admin .app-nav-brand small { color: #93c5fd !important; font-weight: 500; }
.app-nav-admin .app-nav-links a { color: rgba(255,255,255,0.72); }
.app-nav-admin .app-nav-links a:hover { background: rgba(255,255,255,0.10); color: #fff; }
.app-nav-admin .app-nav-links a.active { background: rgba(255,255,255,0.16); color: #fff; }

/* Tables / autres détails dark */
:root[data-theme="dark"] .app-table thead th { color: var(--slate); border-bottom-color: var(--border); }
:root[data-theme="dark"] .app-table tbody td { border-bottom-color: var(--border); }
:root[data-theme="dark"] .app-progress-bar { background: var(--border); }
:root[data-theme="dark"] .app-alert-error { background: rgba(220,38,38,0.15); color: #fca5a5; border-color: #dc2626; }
:root[data-theme="dark"] .app-alert-info { background: var(--blue-l); color: var(--text); border-color: var(--blue); }
:root[data-theme="dark"] .app-btn-ghost { background: var(--off); color: var(--slate); border-color: var(--border); }
:root[data-theme="dark"] .app-btn-ghost:hover { background: var(--border); color: var(--text); }

/* Override pour conserver background blanc/clair sur certains éléments
   ayant des fonds hardcodés dans les EJS (wiki tips, alerts, etc.) */
:root[data-theme="dark"] .wiki-tip { background: var(--off) !important; color: var(--text); border-color: var(--border) !important; }
:root[data-theme="dark"] .wiki-warn { background: rgba(234,88,12,0.10) !important; color: #fcd9b6 !important; border-color: rgba(234,88,12,0.4) !important; }
:root[data-theme="dark"] .wiki-section { background: var(--white); border-color: var(--border); color: var(--text); }
:root[data-theme="dark"] .wiki-section code { background: var(--off); color: #ffffff; border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc { background: var(--white); border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc a { background: var(--off); color: var(--text); border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc a:hover { background: var(--border); }

/* Force adaptive sur sections inline avec style background blanc/light */
/* Auto-assombrit les éléments à fond blanc en ligne. EXCEPTION : l'aperçu de
   signature mail doit rester blanc (simulation d'un email côté destinataire) —
   sinon son fond passait au sombre mais son texte navy en ligne restait navy
   → invisible. */
:root[data-theme="dark"] [style*="background:#fff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background: #fff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background:#ffffff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background:white"]:not(.signature-preview-wrapper) { background: var(--white) !important; color: var(--text) !important; }

/* Boutons primary en dark : même azur qu'en clair, texte blanc lisible */
:root[data-theme="dark"] .app-btn-primary {
  background: var(--th-grad, var(--brand-navy)) !important;
  border-color: transparent !important;
  color: #ffffff !important;
  box-shadow: 0 1px 2px rgba(0,0,0,0.35), 0 6px 16px rgba(37,99,235,0.30);
}
:root[data-theme="dark"] .app-btn-primary:hover {
  background: var(--th-grad-h, var(--brand-navy2)) !important;
  border-color: transparent !important;
  box-shadow: 0 4px 14px rgba(37,99,235,0.40);
}
:root[data-theme="dark"] .app-btn-outline { color: var(--text) !important; border-color: var(--border2); }
:root[data-theme="dark"] .app-btn-outline:hover { background: var(--off); color: var(--text) !important; border-color: #ffffff; }

/* Logo SVG : en dark on inverse — cercle blanc + route bleu nuit (harmonisé site). */
:root[data-theme="dark"] .app-logo-svg .logo-circle { fill: #ffffff !important; }
:root[data-theme="dark"] .app-logo-svg .logo-road   { stroke: #0f2544 !important; }
/* Logos statiques des pages d'entrée (login, inscription, erreurs — wrapper .app-logo) :
   même inversion en sombre que le logo de nav, sinon le rond bleu nuit se fond dans le
   fond sombre (#1c1c1e). Rond blanc + route bleu nuit. (Logos d'école custom = <img>, non visés.) */
:root[data-theme="dark"] .app-logo svg circle { fill: #ffffff; }
:root[data-theme="dark"] .app-logo svg path   { stroke: #0f2544; }

/* Le menu admin est TOUJOURS bleu marine (clair comme sombre). Le logo navy
   s'y fondrait (cercle navy sur fond navy → invisible). On force donc partout
   sur ce menu la variante inversée : disque blanc + route navy, bien visible. */
.app-nav-admin .app-logo-svg .logo-circle { fill: #ffffff !important; }
.app-nav-admin .app-logo-svg .logo-road   { stroke: #0f2544 !important; }
:root[data-theme="dark"] .app-nav-admin .app-logo-svg .logo-road { stroke: #0f2544 !important; }

/* Cards avec background light hardcodé via style inline (linear-gradient, rgba, etc.)
   → on les force en dark via une couche d'override. Couvre les patterns vus dans
   les EJS : .app-card avec style="background:linear-gradient(...,#eff6ff...)". */
:root[data-theme="dark"] .app-card[style*="linear-gradient"],
:root[data-theme="dark"] .app-card[style*="background:#fff"],
:root[data-theme="dark"] .app-card[style*="background: #fff"],
:root[data-theme="dark"] .app-card[style*="background:#fafafa"],
:root[data-theme="dark"] .app-card[style*="background:#f0fdf4"],
:root[data-theme="dark"] .app-card[style*="background:#fef3c7"] {
  background: var(--white) !important;
  border-color: var(--border) !important;
}
/* Surfaces blanches/claires brutes (sections, divs) → fond sombre */
:root[data-theme="dark"] section[style*="background:#fff"],
:root[data-theme="dark"] section[style*="background:linear-gradient"],
:root[data-theme="dark"] div[style*="background:#fafafa"],
:root[data-theme="dark"] div[style*="background:#f9fafb"],
:root[data-theme="dark"] div[style*="background:#f0f9ff"],
:root[data-theme="dark"] div[style*="background:#fef3c7"] {
  background: var(--white) !important;
  color: var(--text) !important;
}

/* Aperçu signature mail : forcer le rendu light (peu importe le mode actif)
   pour montrer ce qu'un destinataire verrait en light. Le code source à
   copier (dans la <pre>) garde son @media intact. */
.signature-preview-wrapper {
  color-scheme: light !important;
  background: #ffffff !important;
  color: #0f2544 !important;
}
.signature-preview-wrapper * {
  color-scheme: light !important;
}

/* ───────────────────────────────────────────────────────────────────
   RESPONSIVE — Renforcer petits écrans (<480px)
   ─────────────────────────────────────────────────────────────────── */
@media (max-width: 480px) {
  .app-main { padding: 1.25rem 0.85rem 2.5rem; }
  .app-card { padding: 1rem; border-radius: 12px; }
  .app-page-header h1 { font-size: 1.4rem; }
  .app-page-header p { font-size: 0.85rem; }
  .app-section-tag { font-size: 0.62rem; padding: 0.25rem 0.6rem; }
  .app-kpi { padding: 0.95rem 1rem; }
  .app-kpi-value { font-size: 1.55rem; }
  .app-kpi-label { font-size: 0.68rem; }
  .app-btn { padding: 0.65rem 1rem; font-size: 0.85rem; }
  .app-btn-sm { padding: 0.4rem 0.75rem; font-size: 0.78rem; }
  .app-toolbar { padding: 0.7rem; }
  .app-toolbar-search { min-width: 100%; }
  .app-toolbar-select { min-width: 100%; }
  .app-form-actions { flex-direction: column; align-items: stretch; }
  .app-form-actions .app-btn { width: 100%; }
  .app-nav-inner { padding: 0.6rem 0.85rem; gap: 0.6rem; }
  .app-nav-brand { font-size: 0.92rem; }
  .app-nav-links a { padding: 0.4rem 0.7rem; font-size: 0.8rem; }
  .app-nav-icon-btn, .app-theme-toggle { width: 34px; height: 34px; }
  .app-auth-card { padding: 1.5rem 1.25rem; border-radius: 14px; }
  .app-auth-title { font-size: 1.3rem; }
}

/* ═══════════════════════════════════════════════════════════
   MENU HAMBURGER MOBILE
   Sous 768px : la nav-links + nav-user se transforment en
   un panneau lateral qui slide-in depuis la droite, declenche
   par un bouton hamburger en haut a droite.
   ═══════════════════════════════════════════════════════════ */
.app-nav-hamburger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: transparent;
  border: 1px solid var(--separator);
  border-radius: 8px;
  cursor: pointer;
  color: var(--label-primary);
  padding: 0;
  margin-left: auto;
  flex-shrink: 0;
  transition: background 0.15s;
}
.app-nav-hamburger:hover { background: var(--fill-quaternary); }
.app-nav-hamburger .ham-line { transition: transform 0.25s ease, opacity 0.2s ease; transform-origin: center; }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-1 { transform: translate(0, 6px) rotate(45deg); }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-2 { opacity: 0; }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-3 { transform: translate(0, -6px) rotate(-45deg); }

/* Conteneur de tiroir mobile : neutre en desktop (les liens + le bloc user
   gardent leur place dans la barre), il ne devient un panneau qu'en <=768px. */
.app-nav-drawer { display: contents; }
/* La croix de fermeture du tiroir est créée en JS dans tous les cas. En desktop
   le tiroir est display:contents → la croix se retrouverait visible dans la barre
   (à droite du logo). On la masque par défaut ; le bloc <=768px la réaffiche. */
.app-nav-drawer-close { display: none; }

.app-nav-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 998;
  opacity: 0;
  transition: opacity 0.25s ease;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

/* Pas de scroll horizontal sur mobile : le tiroir de nav (position:fixed) ne doit
   pas élargir la page. clip = pas de conteneur de scroll (préserve position:sticky
   de .app-nav et des en-têtes de tableau) ; hidden en repli (anciens Safari). */
@media (max-width: 768px) {
  html, body { overflow-x: hidden; overflow-x: clip; }
}

/* ─── Nav repliée en menu hamburger ───────────────────────────────────────
   Déclenchée par la classe .is-collapsed posée par nav-hamburger.js : soit
   l'écran est étroit (<=768px), soit le contenu de la barre DÉBORDE (cas de la
   nav admin sur tablette, avec sa longue rangée d'icônes d'outils). Pilotée par
   mesure réelle → aucune icône rognée quel que soit le nombre d'items/la largeur. */
/* Sur WebKit/iOS, un ancetre porteur de backdrop-filter / filter / transform /
   will-change / contain (ou capture par une view transition nommee) devient le
   containing block de ses descendants position:fixed : le tiroir plein ecran se
   retrouverait rendu DANS la barre, derriere le contenu de la page. Barre
   repliee = AUCUNE de ces proprietes, jamais. */
.app-nav.is-collapsed {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  filter: none !important;
  transform: none !important;
  will-change: auto !important;
  contain: none !important;
  view-transition-name: none !important;
}
/* <=768px la barre est TOUJOURS repliee : on retire ces proprietes des la
   premiere peinture (avant que le JS ne pose .is-collapsed) et pour la capture
   des view transitions de navigation (elles imposent un confinement au rendu). */
@media (max-width: 768px) {
  .app-nav {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    filter: none !important;
    transform: none !important;
    will-change: auto !important;
    contain: none !important;
    view-transition-name: none !important;
  }
}
/* Fond opaque sur la barre repliée (le flou est retiré ci-dessus car il piégerait
   le tiroir position:fixed). La nav admin garde son dégradé navy. */
.app-nav.is-collapsed:not(.app-nav-admin),
:root[data-theme="dark"] .app-nav.is-collapsed:not(.app-nav-admin) { background: var(--bg-elevated); }
.app-nav.is-collapsed .app-nav-hamburger { display: inline-flex; }
.app-nav.is-collapsed .app-nav-inner { padding: 0.7rem 1rem; gap: 0.6rem; }

/* ── Anti-clignotement mobile (FOUC) ───────────────────────────────────────
   Sur ≤768px la barre est TOUJOURS repliée. Avant que nav-hamburger.js ne pose
   .is-collapsed (l'app se recharge entièrement à chaque navigation), on montre
   déjà le hamburger et on masque les liens/bloc utilisateur en ligne : la
   première peinture affiche l'état replié, sans flash de la barre complète à
   chaque changement de page. Le JS prend ensuite le relais (création du tiroir).
   Bonus : même si un 'resize' parasite (barre d'URL au scroll) retire un instant
   .is-collapsed, les liens restent masqués → pas de clignotement. */
@media (max-width: 768px) {
  .app-nav-hamburger { display: inline-flex; }
  .app-nav:not(.is-collapsed) .app-nav-links,
  .app-nav:not(.is-collapsed) .app-nav-user { display: none; }
}
/* Dans le tiroir (panneau vertical), on garde TOUJOURS les libellés : le mode
   icônes-seules (.nav-compact, pour une barre horizontale serrée) n'a aucun sens
   ici et viderait les intitulés du menu. */
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-links a { font-size: 0.95rem; padding: 0.7rem 0.85rem; gap: 0.6rem; }
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-links a .nav-icon { margin-right: 0.55rem; }
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-switcher-label { display: inline; }

/* Tiroir : panneau PLEIN ÉCRAN sous la barre, qui apparaît EN PLACE (fondu).
   .app-nav-drawer est créé par nav-hamburger.js (qui y déplace .app-nav-links +
   .app-nav-user). Hors repli il est neutre (display:contents, voir plus haut). */
.app-nav.is-collapsed .app-nav-drawer {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0;                 /* PLEIN ECRAN : couvre tout, aucune bande de page */
  box-sizing: border-box;
  background: var(--bg-elevated);
  z-index: 1300;            /* au-dessus de tout (y compris la bulle assistant) */
  padding: calc(0.7rem + env(safe-area-inset-top, 0px)) max(0.9rem, env(safe-area-inset-right, 0px)) calc(0.9rem + env(safe-area-inset-bottom, 0px)) max(0.9rem, env(safe-area-inset-left, 0px));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  gap: 0.2rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* Pas d'animation par défaut : .is-collapsed est posé (et remesuré) au
     chargement de CHAQUE page ; une transition ici fait « fondre » le tiroir
     plein écran de 1 → 0 à chaque navigation = clignotement. Les animations
     d'ouverture/fermeture sont réactivées via .nav-ready, posée par le JS APRÈS
     la 1re peinture (donc après le repli initial, qui reste instantané). */
  transition: none;
}
.app-nav.is-collapsed.nav-ready .app-nav-drawer {
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.app-nav.is-collapsed.is-mobile-open .app-nav-drawer {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.18s ease;
}
/* Nav admin = texte blanc : le panneau prend un fond navy pour rester lisible. */
.app-nav-admin.is-collapsed .app-nav-drawer { background: var(--brand-navy); }
/* Croix de fermeture en haut du panneau plein écran. */
.app-nav.is-collapsed .app-nav-drawer-close {
  align-self: flex-end;
  flex: none;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--separator);
  border-radius: 9px;
  color: var(--label-primary);
  cursor: pointer;
  margin: 0 0 0.4rem;
}
.app-nav-admin.is-collapsed .app-nav-drawer-close { color: #fff; border-color: rgba(255,255,255,0.3); }

/* Liens + bloc user : flux normal dans le panneau */
.app-nav.is-collapsed .app-nav-drawer .app-nav-links,
.app-nav.is-collapsed .app-nav-drawer .app-nav-user {
  position: static;
  transform: none;
  width: auto;
  max-width: none;
  height: auto;
  background: transparent;
  box-shadow: none;
  padding: 0;
  flex: none;
  overflow: visible;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
}
.app-nav.is-collapsed .app-nav-drawer .app-nav-user {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: auto;            /* compte / déconnexion poussés en bas du tiroir */
  padding-top: 0.8rem;
  border-top: 1px solid var(--separator);
}
.app-nav.is-collapsed .app-nav-links a {
  padding: 0.7rem 0.8rem;
  font-size: 0.95rem;
  border-radius: 10px;
  width: 100%;
  box-sizing: border-box;   /* padding inclus → le lien ne déborde pas de 11px */
  justify-content: flex-start;
  gap: 0.7rem;
}
.app-nav.is-collapsed .app-nav-user-info { text-align: left; }

/* Menu OUVERT : le hamburger reste visible AU-DESSUS du tiroir et se transforme en
   croix (animation ham-line existante) -> la croix est EXACTEMENT a la place du burger
   (haut-droite). Cliquer dessus referme (meme bouton, meme handler). La croix separee
   du tiroir devient inutile. */
.app-nav.is-mobile-open .app-nav-hamburger {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  right: 13px;
  z-index: 1401;
  display: inline-flex !important;
}
.app-nav.is-collapsed .app-nav-drawer-close { display: none !important; }

/* Tiroir mobile : JAMAIS de scroll horizontal. overflow-y:auto passe overflow-x a
   'auto' -> un libelle un poil trop large (metrique de police du device) permettait de
   scroller a droite et coupait les icones a gauche. On force overflow-x:hidden partout
   dans le tiroir et on garantit que les rangees se retrecissent (min-width:0, box-sizing). */
.app-nav.is-collapsed .app-nav-drawer,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links { overflow-x: hidden; max-width: 100%; }
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links a,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links .app-nav-grouptrigger,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links .app-nav-dropdown { min-width: 0; max-width: 100%; box-sizing: border-box; }

/* Sous-menu (rubrique dépliée) DANS le tiroir mobile : accordéon INSÉRÉ dans la liste,
   opaque, SANS effet verre. Sinon app-theme.css le force en position:absolute (il flotte
   par-dessus) et liquid-glass.css lui met un backdrop-filter (il floute les icônes
   colorées derrière -> dégradé parasite). Scopé .is-mobile-open (jamais desktop). */
.nav-layout-side .app-nav.is-mobile-open:not(.app-nav-admin):not(.super-nav) .app-nav-drawer .app-nav-dropdown {
  position: static;
  width: 100%;
  min-width: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: none;
  box-shadow: none;
  padding: 0.1rem 0 0.3rem 1.4rem;
}

/* TIROIR MOBILE OUVERT = liste VERTICALE. Une regle @media(max-width:900px) force
   .app-nav-links en flex-direction:row (barre horizontale des navs sidebar) ; par
   specificite elle l'emportait dans le tiroir -> liens en ligne, etires sur toute la
   hauteur (menu ouvert casse). On reprend la main avec une specificite superieure,
   scopee a .is-mobile-open UNIQUEMENT (n'affecte JAMAIS l'etat ferme). */
.nav-layout-side .app-nav.is-mobile-open:not(.app-nav-admin):not(.super-nav) .app-nav-drawer .app-nav-links {
  flex-direction: column;
  align-items: stretch;
  overflow-y: auto;
  overflow-x: hidden;
  width: 100%;
  max-width: 100%;
}
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links > a,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links > .app-nav-group { flex: 0 0 auto; width: 100%; }


/* Tiroir ADMIN : le bloc « outils » est une rangée d'icônes SEULES (support,
   santé, réglages, déconnexion…). Empilé tel quel dans le tiroir, il déborde et
   reste illisible (aucun libellé). On le déplie en liste verticale pleine largeur,
   chaque outil affichant son libellé (aria-label) à côté de l'icône. */
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user {
  flex-direction: column;
  align-items: stretch;
  align-self: stretch;
  flex-wrap: nowrap;
  width: 100%;
  margin-left: 0;          /* annule le margin-left:auto qui le poussait à droite */
  margin-top: 0.4rem;
  gap: 0.15rem;
  border-top-color: rgba(255, 255, 255, 0.16);
}
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user > span { display: none !important; } /* séparateurs verticaux (style inline → !important) */
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user .app-nav-icon-btn {
  width: 100%;
  box-sizing: border-box;   /* padding inclus → ne déborde pas la largeur du tiroir */
  height: auto;
  justify-content: flex-start;
  gap: 0.7rem;
  padding: 0.7rem 0.8rem;
  border-radius: 10px;
}
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user .app-nav-icon-btn::after {
  content: attr(aria-label);
  font-size: 0.95rem;
  font-weight: 500;
}

/* ═══════════════════════════════════════════════════════════
   RESPONSIVE MOBILE COMPLET (iPhone SE / 11 / 12 / 13 / 14)
   Cible 375px-480px : passage propre en 1 colonne, tables
   horizontalement scrollables, header buttons stack, etc.
   ═══════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
  /* Grilles génériques : passage en 1 colonne propre */
  .app-stat-grid { grid-template-columns: repeat(2, 1fr); gap: 0.6rem; }

  /* Tables : wrapper horizontal pour éviter le débordement viewport */
  .app-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .app-table { font-size: 0.82rem; }
  .app-table th, .app-table td { padding: 0.5rem 0.55rem; white-space: nowrap; }
  /* (Plus de display:block ici : il faisait rétrécir les tableaux étroits — leur
     contenu ne remplissait plus la carte. Les tableaux gardent width:100% (donc
     pleine largeur quand le contenu est étroit) et page-loader.js les enveloppe
     dans .app-table-scroll quand ils sont trop larges → défilement.) */

  /* Modales : prennent toute la largeur dispo (la boîte, pas le voile plein écran) */
  .app-modal-card,
  dialog.app-modal { max-width: calc(100vw - 1rem) !important; margin: 0.5rem; }
  .app-modal-body, .app-modal-body { padding: 0.9rem 1rem; }
  .app-modal-header h3 { font-size: 1rem; }

  /* Page header : titre + actions stackés */
  .app-page-header { flex-direction: column; align-items: stretch; gap: 0.8rem; }
  .app-page-header > div:first-child { width: 100%; }
  .app-page-header h1 { font-size: 1.25rem; }

  /* Pied de formulaire « pleine largeur » (marges négatives calées sur le padding
     desktop) : sur mobile le padding de carte est plus petit → le débord négatif
     dépassait l'écran. On annule le débord horizontal. */
  .admin-sticky-footer { margin-left: 0 !important; margin-right: 0 !important; padding-left: 0.4rem !important; padding-right: 0.4rem !important; }

  /* Quick-add menu : full width mobile */
  .quick-add-wrapper { width: 100%; }
  .quick-add-wrapper .quick-add-trigger { width: 100%; justify-content: center; }
  .quick-add-menu { left: 0; right: 0; min-width: 0; }

  /* Nav : geree par les regles hamburger (cf bloc precedent @media 768px) */
}

@media (max-width: 480px) {
  /* Header fiche élève : boutons en grille 2 colonnes */
  .app-page-header > div:last-child:not(:only-child) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    width: 100%;
  }
  .app-page-header > div:last-child:not(:only-child) > * { width: 100%; }

  /* Stats grid : 1 colonne sur très petit */
  .app-stat-grid { grid-template-columns: 1fr; }

  /* Tabs (rh-tabs, parametres-tabs) : scroll horizontal */
  .parametres-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; }
  .parametres-tabs::-webkit-scrollbar { display: none; }
  .param-tab { flex-shrink: 0; white-space: nowrap; }

  /* Filtres compacts */
  .app-filters { flex-direction: column; align-items: stretch; }
  .app-filters > * { width: 100%; }

  /* Form grids dans modales : 1 colonne pure */
  .app-modal-body .form-grid { grid-template-columns: 1fr !important; gap: 0.7rem; }

  /* Formulaires d'ajout de dispo (espace élève) : 3 champs (jour/heure/heure)
     côte à côte débordaient la carte sur smartphone → 2 colonnes, champs au
     large. Le bouton + Ajouter (4e cellule du form hebdo) passe sous la ligne. */
  .dispo-add-grid { grid-template-columns: 1fr 1fr !important; }
  .dispo-add-grid > * { min-width: 0; }

  /* Padding interne réduit */
  .app-card { padding: 0.85rem; }
}

/* Safe area iOS notch */
@supports (padding: env(safe-area-inset-bottom)) {
  .app-main { padding-bottom: max(2rem, env(safe-area-inset-bottom) + 1rem); }
}
/* Dégagement des boutons flottants mobiles (menu rond 52px à gauche, Julia à droite,
   ancrés fixed en bas : bottom ≈ 1rem + safe-area) : le dernier contenu doit pouvoir
   défiler AU-DESSUS de la bande qu'ils occupent (~68px). Posé sur le footer (présent
   sur quasi toutes les pages) et, à défaut de footer, sur .app-main. Aucun effet
   desktop (>768px : le menu rond est masqué et Julia reste sous le footer). */
@media (max-width: 768px) {
  .app-footer { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 5rem); }
  body:not(:has(.app-footer)) .app-main { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 5.5rem); }
}

/* ═══════════════════════════════════════════════════════════
   IMPRESSION — règles @media print pour exporter en PDF propre
   (utilisé par le bouton Imprimer du planning et fiches élève/véhicule)
   ═══════════════════════════════════════════════════════════ */
@media print {
  /* Reset hauteur/marges agressif pour éviter les pages vides */
  html, body, body.app-body {
    margin: 0 !important;
    padding: 0 !important;
    background: #fff !important;
    color: #000 !important;
    color-scheme: light !important;
    min-height: 0 !important;
    height: auto !important;
    overflow: visible !important;
  }
  body.app-body::before, body.app-body::after {
    content: none !important;
    display: none !important;
    background: none !important;
  }

  /* Force palette claire pour le print, peu importe le thème actif */
  :root, :root[data-theme="dark"] {
    --cream: #fff; --cream-2: #fff; --paper: #fff; --off: #f5f5f5;
    --navy: #000; --navy2: #222; --text: #000;
    --slate: #555; --border: #ccc; --border2: #aaa;
    --accent: #000; --accent-2: #1a1a1a;
  }

  /* Masquer toute la chrome navigationnelle et interactive */
  .app-nav, .app-footer,
  .app-planning-toolbar,
  .app-planning-actions,
  .app-page-header > div:nth-child(2),
  .app-btn, button {
    display: none !important;
  }

  /* Layout flatten : pas de padding excessif qui pousse à la page suivante */
  .app-main {
    padding: 0 !important;
    max-width: none !important;
    margin: 0 !important;
  }

  /* Cards : pas d'ombre, pas de "page-break-inside: avoid" qui crée des pages
     vides quand la carte est plus grande qu'une page. On laisse le navigateur
     gérer naturellement les sauts de page. */
  .app-card {
    box-shadow: none !important;
    border: 0.5pt solid #ccc !important;
    margin: 0 0 0.3cm 0 !important;
    padding: 0.3cm !important;
    overflow: visible !important;
    page-break-inside: auto !important;
    break-inside: auto !important;
  }

  /* Header impression compact */
  .app-page-header {
    margin: 0 0 0.3cm 0 !important;
    padding: 0 !important;
  }
  .app-page-header h1 { font-size: 13pt !important; margin: 0 !important; line-height: 1.2 !important; }
  .app-page-header p  { font-size: 9pt !important; margin: 0 !important; color: #555 !important; }

  /* Planning grille : pas de scroll, hauteur naturelle */
  #planning-grid {
    overflow: visible !important;
    overflow-x: visible !important;
    height: auto !important;
    page-break-inside: auto !important;
    break-inside: auto !important;
  }
  .planning-evt {
    box-shadow: none !important;
    border: 0.5pt solid rgba(0,0,0,0.25);
    page-break-inside: avoid;
  }

  /* Masquer la légende du planning en print (économie de place) */
  .app-planning-legend-tag { display: none !important; }
  .app-card:has(.app-planning-legend-tag) { display: none !important; }

  /* Liens dépouillés en print : pas d'underline */
  a { color: inherit !important; text-decoration: none !important; }

  /* Format A4 paysage pour le planning (le plus large) */
  @page {
    size: A4 landscape;
    margin: 0.8cm;
  }
}

/* ───────────────────────────────────────────────────────────────────
   LOGO ANIMÉ — Cercle navy qui pulse + route blanche qui se dessine
   Cohérent avec dev.roddier.pro (le site vitrine)
   ─────────────────────────────────────────────────────────────────── */
/* Tracé arrondi qui se dessine puis s'efface de GAUCHE À DROITE (entrée + sortie),
   harmonisé avec le site. Uniquement des dashoffset >= 0 (iOS/WebKit écrase les
   négatifs → « se dessinait puis sautait ») : dasharray 1200 (période 2400 → 0 et
   2400 = « plein »), saut instantané 0->2400 invisible (step-end) puis 2400->1200
   = effacement gauche->droite. */
@keyframes roadDraw {
  0%   { stroke-dashoffset: 1200; }
  15%  { stroke-dashoffset: 0; }
  64%  { stroke-dashoffset: 0; animation-timing-function: step-end; }
  65%  { stroke-dashoffset: 2400; }
  90%  { stroke-dashoffset: 1200; }
  100% { stroke-dashoffset: 1200; }
}
@keyframes circlePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
.app-logo-svg .logo-circle {
  transform-origin: 512px 512px;
  /* circlePulse retirée 2026-05-24 — préférence Julien : logo statique */
}
.app-logo-svg .logo-road {
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: roadDraw 13s ease-in-out infinite;
  animation-delay: 0.2s;
}
@media (prefers-reduced-motion: reduce) {
  .app-logo-svg .logo-circle, .app-logo-svg .logo-road { animation: none !important; }
  .app-logo-svg .logo-road { stroke-dashoffset: 0; opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════
   FORM FANCY — styles partagés pour les formulaires premium
   (inscription, login, recover, profile). Approche : sections
   avec icônes, inputs au focus glow tint, boutons proéminents.
   ═══════════════════════════════════════════════════════════ */

/* Container plus large pour les formulaires multi-sections */
.app-auth-wide { align-items: flex-start; padding-top: 3rem; padding-bottom: 3rem; }
.app-auth-card-form { max-width: 600px; }

/* Callout tarif (page inscription) */
.price-callout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.25rem;
  background: linear-gradient(135deg, var(--bg-tertiary), var(--bg-secondary));
  border: 1px solid var(--separator);
  border-radius: 14px;
  margin: 0 0 1.5rem;
  box-shadow: var(--shadow-sm);
}
.price-callout-trial { font-size: 0.95rem; font-weight: 700; color: var(--label-primary); }
.price-callout-amount {
  font-size: 1.6rem; font-weight: 800; color: var(--label-primary);
  letter-spacing: -0.02em; font-feature-settings: 'tnum';
}
.price-callout-sub { font-size: 0.78rem; color: var(--label-secondary); margin-top: 0.15rem; }
.price-callout-right { text-align: right; }

/* Alertes form */
.form-alert {
  display: flex;
  gap: 0.85rem;
  padding: 1rem 1.1rem;
  border-radius: 12px;
  font-size: 0.88rem;
  margin: 0 0 1.25rem;
}
.form-alert-error {
  background: rgba(255,59,48,0.08);
  border-left: 3px solid var(--system-red);
  color: var(--label-primary);
}
.form-alert-icon { font-size: 1.2rem; flex-shrink: 0; color: var(--system-red); line-height: 1; }

/* Form fancy : sections, champs, focus glow */
.form-fancy { display: flex; flex-direction: column; gap: 1.25rem; }
.form-section {
  background: var(--bg-tertiary);
  border: 1px solid var(--separator);
  border-radius: 14px;
  padding: 1.25rem 1.35rem 1.35rem;
  position: relative;
}
.form-section-head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: -0.25rem -0.25rem 1.1rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--separator);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--label-secondary);
}
.form-section-icon { width: 16px; height: 16px; color: var(--label-primary); flex-shrink: 0; }

.form-field { display: block; margin-bottom: 0.85rem; }
.form-field:last-child { margin-bottom: 0; }
.form-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  margin-bottom: 0.4rem;
}
.form-label-hint { font-weight: 400; color: var(--label-tertiary); font-size: 0.78rem; }

.form-fancy input[type="text"],
.form-fancy input[type="email"],
.form-fancy input[type="password"],
.form-fancy input[type="tel"],
.form-fancy input[type="number"],
.form-fancy input[type="date"],
.form-fancy input[type="time"],
.form-fancy textarea,
.form-fancy select {
  width: 100%;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  background-color: var(--bg-secondary);
  color: var(--label-primary);
  font-size: 0.95rem;
  font-family: inherit;
  transition: border-color 0.15s ease, box-shadow 0.18s ease, background 0.15s ease;
  box-sizing: border-box;
}
.form-fancy input:hover, .form-fancy textarea:hover, .form-fancy select:hover {
  border-color: var(--separator-opaque);
}
.form-fancy input:focus, .form-fancy textarea:focus, .form-fancy select:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background: var(--bg-elevated);
}

.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.85rem; margin-bottom: 0.85rem; }
.form-grid-cp-ville { display: grid; grid-template-columns: 1fr 2fr; gap: 0.85rem; margin-bottom: 0.85rem; }
@media (max-width: 480px) {
  .form-grid-2, .form-grid-cp-ville { grid-template-columns: 1fr; }
}

/* SIREN avec status à droite */
.form-field-with-status { position: relative; }
.form-field-status {
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--label-secondary);
  max-width: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}
.form-field-status.is-loading { color: var(--label-secondary); }
.form-field-status.is-success { color: var(--system-green); }
.form-field-status.is-error   { color: var(--system-red); }

/* Checkbox style amélioré */
.form-checkbox-inline {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.85rem 1rem;
  background: var(--fill-tertiary);
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.5;
  cursor: pointer;
  transition: background 0.15s ease;
  margin-bottom: 0.85rem;
}
.form-checkbox-inline:hover { background: var(--fill-secondary); }
.form-checkbox-inline input[type="checkbox"] {
  margin: 0.18rem 0 0;
  width: 18px; height: 18px;
  accent-color: var(--tint);
  flex-shrink: 0;
}

/* Bouton submit plus impactant */
.form-submit-btn {
  width: 100%;
  padding: 1rem;
  font-size: 1rem;
  font-weight: 700;
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.form-submit-btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
}

/* Widget Altcha */
.altcha-widget {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.7rem 0.95rem;
  background: var(--fill-tertiary);
  border: 1px solid var(--separator);
  border-radius: 10px;
  font-size: 0.85rem;
  color: var(--label-secondary);
  margin-bottom: 1rem;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.altcha-icon { width: 16px; height: 16px; flex-shrink: 0; }
.altcha-widget.is-success {
  background: rgba(52,199,89,0.08);
  border-color: rgba(52,199,89,0.3);
  color: var(--system-green);
}
.altcha-widget.is-error {
  background: rgba(255,59,48,0.08);
  border-color: rgba(255,59,48,0.3);
  color: var(--system-red);
}

/* ═══════════════════════════════════════════════════════════════════
   PREMIUM POLISH 2026-05-26 — micro-finitions Apple HIG
   Strictement additif : ne casse aucun composant existant, ne fait
   qu'enrichir les détails de profondeur / typographie / focus.
   Toutes les variables référencées sont définies dans :root.
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Typo : chiffres tabular sur les valeurs financières/comptables ─── */
.app-kpi-value,
.app-stat-value,
.price-callout-amount,
.app-table td .number,
.app-cell-amount {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'kern' 1;
}

/* ─── Titres : letter-spacing fin sur les gros titres (Apple HIG) ─── */
.app-page-header h1 {
  font-feature-settings: 'kern' 1, 'ss01' 1;
}
.app-auth-title,
.app-kpi-value {
  font-feature-settings: 'kern' 1;
}

/* ─── Focus ring uniforme : remplace les box-shadow ad-hoc ─── */
.app-form input:focus,
.app-form select:focus,
.app-form textarea:focus,
.form-fancy input:focus,
.form-fancy textarea:focus,
.form-fancy select:focus,
.app-toolbar-search input:focus,
.app-toolbar-select select:focus {
  box-shadow: var(--ring-focus);
}

/* Labels un poil plus marqués (lisibilité forms) */
.app-form .app-label,
.form-fancy .form-label {
  font-weight: 600;
}

/* ─── Boutons : :active feedback tactile subtil (iOS-like) ─── */
.app-btn:active,
.app-toolbar-btn:active,
.form-submit-btn:active {
  transform: scale(0.985);
  transition-duration: 0.06s;
}
.app-btn-primary {
  /* Ombre interne très légère pour donner du volume au bouton plein */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10), 0 1px 2px rgba(0,0,0,0.10);
}
.app-btn-primary:hover {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12), 0 6px 18px rgba(0,0,0,0.18), 0 2px 4px rgba(0,0,0,0.08);
}

/* ─── Cards : transition cubic-bezier naturelle ─── */
.app-card,
.app-kpi,
.app-stat-card,
.app-card-clickable {
  transition:
    transform 0.18s var(--ease-spring),
    box-shadow 0.20s var(--ease-spring),
    border-color 0.18s ease;
}

/* ─── KPI : ombres multi-couches (déjà premium, on ajoute une nuance) ─── */
.app-kpi {
  box-shadow: var(--shadow-soft);
}
.app-kpi:hover {
  box-shadow: var(--shadow-raised);
}
/* Teintes catégorielles très légères pour signifier le type de KPI
   (utilisation libre — applique .app-kpi-tint-X aux KPI). */
.app-kpi-tint-revenue  { background: linear-gradient(180deg, rgba(52,199,89,0.04), var(--paper) 60%); }
.app-kpi-tint-students { background: linear-gradient(180deg, var(--accent-3-l), var(--paper) 60%); }
.app-kpi-tint-data     { background: linear-gradient(180deg, var(--accent-4-l), var(--paper) 60%); }
.app-kpi-tint-alert    { background: linear-gradient(180deg, rgba(255,149,0,0.05), var(--paper) 60%); }

/* ─── Dialogs <dialog> : frosted glass + ring focus (iOS / macOS sheet) ─── */
dialog {
  background: var(--bg-elevated);
  color: var(--label-primary);
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  padding: 0;
  box-shadow: var(--shadow-overlay);
  max-width: 92vw;
}
dialog::backdrop {
  background: rgba(0,0,0,0.32);
  -webkit-backdrop-filter: saturate(140%) blur(6px);
  backdrop-filter: saturate(140%) blur(6px);
}
:root[data-theme="dark"] dialog::backdrop {
  background: rgba(0,0,0,0.55);
}

/* Apparition « liquide » (Apple sheet) : la boîte émerge avec un léger
   dépassement (ressort) au lieu d'un fondu plat — déclenchée auto sur dialog[open] */
@keyframes appDialogIn {
  0%   { opacity: 0; transform: translateY(14px) scale(0.94); }
  62%  { opacity: 1; transform: translateY(-2px) scale(1.008); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
dialog[open] {
  animation: appDialogIn 0.34s var(--ease-out-smooth);
}
/* Même ouverture pour les modales <div class="app-modal"> (système .show) : on anime
   la carte (équivalent de la boîte du <dialog>) avec les MÊMES keyframes/durée →
   ouverture cohérente entre « Modifier », « Examen », « Contacter », planning, etc. */
.app-modal.show .app-modal-card {
  animation: appDialogIn 0.34s var(--ease-out-smooth);
}
@media (prefers-reduced-motion: reduce) {
  dialog[open] { animation: none; }
  .app-modal.show .app-modal-card { animation: none; }
}

/* ─── Système modal unifié (<dialog>) ─────────────────────────────
   Squelette commun pour toutes les modales : Contact, Pièce, Code,
   Dossier, etc. Utilise <dialog class="app-modal"> + sub-éléments.
   Toutes les pages chargent app.css → CSS partagé, zéro duplication.
   ─────────────────────────────────────────────────────────────── */
/* Surface commune à TOUTES les modales : <dialog class="app-modal"> ET le
   système .app-modal/.app-modal-card. UNE seule définition → rendu identique
   (verre adaptatif), zéro duplication. */
dialog.app-modal,
.app-modal-card {
  /* border-box : indispensable pour que le padding (parfois inline, ex. dossier
     ou code-modal) soit INCLUS dans la largeur/hauteur. Sans ça, sur mobile, la
     boîte = largeur + padding débordait l'écran (408px > 390) et dépassait en
     hauteur sans pouvoir défiler. */
  box-sizing: border-box;
  border: 1px solid var(--lg-border, var(--separator));
  border-radius: 16px;
  box-shadow: var(--lg-highlight, 0 0 0 transparent), var(--lg-shadow-lg, var(--shadow-overlay, 0 32px 80px rgba(15,37,68,0.32)));
  background: var(--lg-surface-strong, var(--bg-elevated));
  -webkit-backdrop-filter: blur(30px) saturate(180%);
  backdrop-filter: blur(30px) saturate(180%);
  color: var(--label-primary);
  overflow: hidden;
}
/* Dialog natif : taille + centrage par le navigateur (::backdrop). */
dialog.app-modal { max-width: 600px; width: calc(100% - 2rem); padding: 0; }
.app-modal-sm { max-width: 440px; }
.app-modal-lg { max-width: 820px; }
/* Overlay du système .app-modal (pas de <dialog> → div de fond + centrage flex). */
.app-modal {
  position: fixed; inset: 0; z-index: 1100;
  /* border-box : sans ca, la marge interieure s ajoutait a la largeur d ecran
     (446 px sur un telephone de 430) et la pop-up n etait plus centree. */
  box-sizing: border-box;
  display: none; align-items: center; justify-content: center; padding: 1rem;
  background: rgba(10, 18, 32, 0.28);
  /* PAS de backdrop-filter ici : il créerait un "backdrop root" qui empêcherait
     la carte (.app-modal-card, blur30) de flouter la PAGE — elle ne flouterait que
     le voile, d'où un rendu différent du <dialog>. C'est la carte qui floute. */
}
.app-modal.show { display: flex; }
/* Un <dialog> non ouvert DOIT rester masqué (display:none de l'UA). Les pop-ups
   quick-add portent <dialog class="app-modal sheet"> ; or .sheet (css/sheet.css,
   composant KIT div-sheet) déclare « display:flex » et est chargé APRÈS app.css →
   à spécificité égale (0,1,0) il l'emportait sur .app-modal{display:none}, et avec
   .app-modal{inset:0} la feuille n'était plus poussée hors écran → les modales
   restaient AFFICHÉES (voile flou) sur le dashboard. On restaure explicitement le
   masquage des <dialog> fermés : spécificité (0,2,1) → bat .sheet et .app-modal,
   sans [open] donc neutre dès l'ouverture par showModal(). */
dialog.app-modal:not([open]) { display: none; }
/* Modales natives <dialog class="app-modal"> ouvertes via showModal() : affichées par
   l'attribut [open] (pas .show). Contrairement aux <div class="app-modal"> (overlay
   plein écran + .app-modal-card centrée), ici le <dialog> EST la boîte (contenu en
   enfants directs : header/body/footer ou titre/form/sections). On le rend donc comme
   une CARTE centrée empilée verticalement (le voile vient du ::backdrop natif).
   Sans flex-direction:column, les enfants se mettaient EN LIGNE (flex row) → CSS cassé. */
dialog.app-modal[open] {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0;
  margin: auto;
  width: calc(100% - 2rem);
  max-width: 600px;
  height: fit-content;
  max-height: calc(100vh - 2rem);
  padding: 0;
  overflow: auto;
}
.app-modal-card {
  width: 100%; max-height: calc(100vh - 2rem);
  display: flex; flex-direction: column; box-sizing: border-box;
}
.app-modal-card.size-sm  { max-width: 380px; }
.app-modal-card.size-md  { max-width: 520px; }
.app-modal-card.size-lg  { max-width: 720px; }
.app-modal-card.size-xl  { max-width: 960px; }
.app-modal-card.size-xxl { max-width: min(1180px, 96vw); }

.app-modal-header,
.app-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.35rem 1.5rem 1.15rem;
  border-bottom: 1px solid var(--separator);
  gap: 0.8rem;
  flex-shrink: 0;
}
.app-modal-header h2,
.app-modal-header h3,
.app-modal-header h3,
.app-modal-title {
  margin: 0;
  font-size: 1.12rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--label-primary);
  line-height: 1.25;
}
.app-modal-close,
.app-modal-close {
  background: var(--fill-quaternary);
  border: none;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--label-secondary);
  border-radius: 50%;
  flex-shrink: 0;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.app-modal-close:hover,
.app-modal-close:hover {
  background: var(--fill-tertiary);
  color: var(--label-primary);
  transform: scale(1.06);
}
.app-modal-close:active,
.app-modal-close:active { transform: scale(0.94); }

.app-modal-body,
.app-modal-body {
  padding: 1.35rem 1.5rem;
  overflow-y: auto;
}
.app-modal-body { max-height: calc(85vh - 9rem); }
.app-modal-body { flex: 1 1 auto; min-height: 0; }  /* scroll dans la carte flex */
.app-modal-body > p:first-child { margin-top: 0; }
.app-modal-body > p:last-child  { margin-bottom: 0; }

/* Sous-section dans le body (style fieldset arrondi) */
.app-modal-section {
  margin-top: 1rem;
  padding: 0.95rem 1.1rem;
  border: 1px solid var(--separator);
  border-radius: 10px;
  background: var(--fill-quaternary);
}
.app-modal-section:first-child { margin-top: 0; }
.app-modal-section-title {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--label-secondary);
}

/* Form fields dans modale (labels + inputs) */
.app-modal-field {
  display: block;
  margin-bottom: 1rem;
}
.app-modal-field:last-child { margin-bottom: 0; }
.app-modal-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  margin-bottom: 0.45rem;
}
.app-modal input[type="text"],
.app-modal input[type="email"],
.app-modal input[type="tel"],
.app-modal input[type="number"],
.app-modal input[type="date"],
.app-modal input[type="datetime-local"],
.app-modal input[type="file"],
.app-modal select,
.app-modal textarea,
.app-modal-card input:not([type="checkbox"]):not([type="radio"]),
.app-modal-card select,
.app-modal-card textarea {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  font-family: inherit;
  font-size: 0.93rem;
  background: var(--bg-secondary);
  color: var(--label-primary);
  box-sizing: border-box;
  transition: border-color 0.15s, box-shadow 0.18s, background 0.15s;
}
.app-modal input[type="file"],
.app-modal-card input[type="file"] { padding: 0.5rem 0.85rem; }
.app-modal input:hover:not(:focus),
.app-modal select:hover:not(:focus),
.app-modal textarea:hover:not(:focus),
.app-modal-card input:hover:not(:focus),
.app-modal-card select:hover:not(:focus),
.app-modal-card textarea:hover:not(:focus) {
  border-color: var(--separator-opaque);
}
.app-modal input:focus,
.app-modal select:focus,
.app-modal textarea:focus,
.app-modal-card input:focus,
.app-modal-card select:focus,
.app-modal-card textarea:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background-color: var(--bg-elevated);
}
.app-modal textarea,
.app-modal-card textarea { resize: vertical; min-height: 110px; }
/* Selects de modale : même chevron que .app-form select (plus de flèche OS native) */
.app-modal select,
.app-modal-card select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2.5rem;
}

/* Cartes radio (Email/SMS, etc.) */
.app-modal-radio-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-bottom: 1.1rem;
}
.app-modal-radio-card {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  cursor: pointer;
  font-size: 0.92rem;
  background: var(--bg-secondary);
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}
.app-modal-radio-card:hover { background: var(--bg-elevated); }
.app-modal-radio-card:has(input:disabled) { opacity: 0.45; cursor: not-allowed; }
.app-modal-radio-card:has(input:checked) {
  border-color: var(--tint);
  background: var(--bg-elevated);
  box-shadow: 0 0 0 3px var(--fill-primary);
}
.app-modal-radio-card input { margin: 0; accent-color: var(--tint); }
.app-modal-radio-card > span {
  display: flex; flex-direction: column;
  line-height: 1.3; font-weight: 600;
}
.app-modal-radio-card small {
  font-size: 0.74rem; font-weight: 400;
  color: var(--label-secondary); margin-top: 0.15rem;
}

/* Footer collé au bas (boutons d'action) */
.app-modal-footer,
.app-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0.95rem 1.5rem;
  border-top: 1px solid var(--separator);
  background: var(--bg-tertiary);
  border-radius: 0 0 16px 16px;
  flex-wrap: wrap;
  flex-shrink: 0;
}

/* Spécifique au système .app-modal (markup label > span, form-grid, etc. —
   pas de <dialog>). Le reste du style est mutualisé avec .app-modal ci-dessus. */
.app-modal-body label { display: block; margin-bottom: 0.95rem; }
.app-modal-body label > span {
  display: block; font-size: 0.82rem; font-weight: 600;
  color: var(--label-primary); margin-bottom: 0.4rem;
}
.app-modal-body .form-grid {
  display: grid; gap: 0.95rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.app-modal-body .form-row-full { grid-column: 1 / -1; }
.app-modal-card input[type="checkbox"],
.app-modal-card input[type="radio"] {
  accent-color: var(--tint); width: 18px; height: 18px; cursor: pointer;
}
.app-modal-footer .app-btn-secondary {
  background: var(--bg-secondary); color: var(--label-primary);
  border: 1.5px solid var(--separator);
}
.app-modal-footer .app-btn-secondary:hover {
  background: var(--bg-elevated); border-color: var(--separator-opaque);
}
.app-modal-error {
  margin: 0 1.5rem 1rem; padding: 0.85rem 1.1rem;
  background: rgba(255, 59, 48, 0.08); color: var(--label-primary);
  border-left: 3px solid var(--system-red); border-radius: 10px;
  font-size: 0.88rem; display: none;
}
.app-modal-error.show { display: block; }
.app-modal-error ul { margin: 0.4rem 0 0 1.2rem; padding: 0; }
@media (max-width: 540px) {
  .app-modal-card { max-width: 100% !important; max-height: calc(100vh - 1rem); }
  .app-modal-footer { flex-direction: column-reverse; }
  .app-modal-footer .app-btn { width: 100%; }
}

/* Erreurs dans modale */
.app-modal-error {
  margin-top: 0.5rem;
  padding: 0.7rem 0.95rem;
  background: rgba(255, 59, 48, 0.08);
  color: #a51d14;
  border-left: 3px solid var(--system-red, #ff3b30);
  border-radius: 10px;
  font-size: 0.88rem;
}

/* Backdrop : déjà défini sur dialog::backdrop dans la section précédente,
   mais on force le blur pour les modales app (cohérent macOS sheet). */
.app-modal::backdrop {
  background: rgba(10, 18, 32, 0.28);
  /* Pas de flou sur le voile (cohérence avec les modales <div>) : c'est la boîte
     verre (dialog.app-modal / .app-modal-card, blur30) qui floute la page. */
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

@media (max-width: 560px) {
  .app-modal-radio-grid { grid-template-columns: 1fr; }
  .app-modal {
    width: calc(100% - 1rem);
    border-radius: 16px;
  }
  .app-modal-header { padding: 1.1rem 1.2rem 1rem; }
  .app-modal-body   { padding: 1.1rem 1.2rem; }
  .app-modal-footer {
    padding: 1rem 1.2rem;
    flex-direction: column-reverse;
  }
  .app-modal-footer .app-btn { width: 100%; }
}

/* ─── Affordance de défilement horizontal des tableaux ───────────────
   page-loader.js pose .can-scroll-left / .can-scroll-right sur les conteneurs
   qui défilent (.app-table-scroll / .app-table-wrap / .compo-tablewrap) selon
   la position : une ombre est peinte au bord où il reste des colonnes.
   background-attachment par défaut (scroll) = l'ombre reste collée au bord
   pendant que le contenu défile. Pas de bande opaque : les panneaux « verre »
   (signature-premium) restent translucides. Placé APRÈS la règle background
   raccourcie de .app-table-wrap (plus haut) pour que l'image survive. */
.app-table-scroll, .app-table-wrap, .compo-tablewrap {
  --edge-hint-l: transparent;
  --edge-hint-r: transparent;
  background-image:
    radial-gradient(farthest-side at 0 50%, var(--edge-hint-l), transparent),
    radial-gradient(farthest-side at 100% 50%, var(--edge-hint-r), transparent);
  background-position: left center, right center;
  background-size: 14px 100%, 14px 100%;
  background-repeat: no-repeat;
}
.can-scroll-left { --edge-hint-l: var(--edge-hint, rgba(11, 27, 58, 0.22)); }
.can-scroll-right { --edge-hint-r: var(--edge-hint, rgba(11, 27, 58, 0.22)); }
:root[data-theme="dark"] .can-scroll-left,
:root[data-theme="dark"] .can-scroll-right { --edge-hint: rgba(0, 0, 0, 0.6); }

/* ─── Tables : header sticky discret (utile sur listes longues) ─── */
.app-table-wrap {
  box-shadow: var(--shadow-soft);
}
.app-table-wrap.sticky-head thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--paper);
  backdrop-filter: saturate(120%);
}

/* ─── Mode tablette enseignant (page leçon en cours) ─────────────
   Zones touch agrandies, boutons primaires plus visibles, inputs
   confortables pour saisie sur écran tactile en environnement
   véhicule (parfois en mouvement, gants possibles).
   ─────────────────────────────────────────────────────────────── */
.lecon-tablet .app-btn {
  min-height: 48px;
  padding: 0.85rem 1.4rem;
  font-size: 0.95rem;
  font-weight: 600;
}
.lecon-tablet .app-btn-primary {
  min-height: 52px;
  padding: 1rem 1.6rem;
  font-size: 1rem;
  box-shadow: 0 4px 12px rgba(15, 37, 68, 0.15);
}
.lecon-tablet .app-form input[type="text"],
.lecon-tablet .app-form input[type="number"],
.lecon-tablet .app-form input[type="time"],
.lecon-tablet .app-form input[type="date"],
.lecon-tablet .app-form select,
.lecon-tablet .app-form textarea {
  min-height: 48px;
  padding: 0.85rem 1rem;
  font-size: 1rem;
  border-radius: 10px;
}
.lecon-tablet .app-form textarea {
  min-height: 110px;
}
.lecon-tablet .app-form label {
  display: block;
  margin-bottom: 1rem;
}
.lecon-tablet .app-card {
  padding: 1.4rem 1.5rem;
}
/* Boutons radio/checkbox plus larges pour le tactile */
.lecon-tablet input[type="radio"],
.lecon-tablet input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--tint);
}
/* Grilles de compétences : cellules plus grandes */
.lecon-tablet .competence-grid label,
.lecon-tablet .competence-row {
  min-height: 56px;
  padding: 0.7rem 0.95rem;
}
@media (max-width: 720px) {
  .lecon-tablet .app-form > div[style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
  }
}

/* ─── Segmented control (sous-onglets Paramètres / RH) ───────────
   UISegmentedControl iOS — pill background avec onglet actif rempli.
   Utilisé par parametres-tabs.ejs et rh-tabs.ejs. */
.parametres-tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--fill-tertiary);
  border-radius: var(--radius-md, 10px);
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.param-tab {
  padding: 0.5rem 0.95rem;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--label-secondary);
  text-decoration: none;
  border-radius: 8px;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}
.param-tab:hover { color: var(--label-primary); background: var(--fill-quaternary); }
.param-tab.is-active {
  color: var(--label-primary);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm), 0 0 0 0.5px var(--separator);
  font-weight: 600;
}

/* ─── Paramètres : onglets regroupés en sections étiquetées ──────────
   parametres-tabs.ejs (version groupée). Chaque rubrique est un petit
   segmented control surmonté d'un libellé. rh-tabs.ejs conserve la barre
   plate .parametres-tabs ci-dessus — ne pas mélanger les deux. */
.param-sections {
  display: flex;
  flex-wrap: wrap;
  gap: 1.1rem 1.5rem;
  align-items: flex-start;
  margin-bottom: 1.5rem;
}
.param-group { display: flex; flex-direction: column; gap: 0.4rem; }
.param-group-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--label-tertiary, var(--label-secondary));
  padding-left: 0.3rem;
}
.param-group-tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--fill-tertiary);
  border-radius: var(--radius-md, 10px);
  flex-wrap: wrap;
}
@media (max-width: 720px) {
  .param-sections { gap: 0.9rem; }
  .param-group { width: 100%; }
  .param-group-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; }
  .param-group-tabs::-webkit-scrollbar { display: none; }
}

/* ─── Section tags : variantes douces avec la palette enrichie ─── */
.app-section-tag-indigo { background: var(--accent-3-l); color: var(--accent-3); }
.app-section-tag-teal   { background: var(--accent-4-l); color: var(--accent-4); }

/* ─── Tags : alignement avec la nouvelle palette ─── */
.app-tag-indigo { background: var(--accent-3-l); color: var(--accent-3); }
.app-tag-teal   { background: var(--accent-4-l); color: var(--accent-4); }

/* ─── Nav : transition plus naturelle des hovers ─── */
.app-nav-links a {
  transition:
    background-color 0.16s var(--ease-spring),
    color 0.16s ease;
}

/* ─── Inputs hover : feedback de chemin (avant focus) ─── */
.app-form input:not(:focus):hover,
.app-form select:not(:focus):hover,
.app-form textarea:not(:focus):hover {
  border-color: var(--separator-opaque);
}

/* ─── Card clickable : lift plus tendre (au lieu du -3px brutal) ─── */
.app-card-clickable:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-raised);
}

/* ─── Smooth scroll global (Apple-like) ─── */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ─── Liens : jamais le bleu souligné du navigateur (app monochrome) ───
   Les liens "bruts" (sans classe) prennent la couleur du texte courant ; le
   soulignement n'apparaît qu'au survol et uniquement pour eux (les liens stylés
   — boutons, cellules, nav — gardent leur propre rendu via des sélecteurs plus
   spécifiques). */
a { color: inherit; text-decoration: none; }
a:not([class]):hover { text-decoration: underline; }

/* ─── Sélection texte : couleur cohérente avec le tint ─── */
::selection {
  background: var(--fill-primary);
  color: var(--label-primary);
}

/* ─── Scrollbar fine (WebKit/Blink) — Apple touch ─── */
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-thumb {
  background: var(--separator);
  border-radius: 100px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--separator-opaque);
  background-clip: padding-box;
  border: 2px solid transparent;
}
*::-webkit-scrollbar-track { background: transparent; }


/* ──────────────────────────────────────────────────────────────────────
 * Apple System Colors — couleur thématique par section (2026-05-26)
 * ──────────────────────────────────────────────────────────────────────
 * Inspiré d'iOS Settings : chaque grande section a sa couleur. La couleur
 * sert d'indicateur visuel, pas de décoration gratuite.
 *
 * Classes opt-in :
 *  - .nav-icon            : box arrondie 28×28 autour des SVG de la nav
 *                           (couleur appliquée via classe .nav-icon-{section})
 *  - .app-tag-{color}     : pastille (déjà : indigo, teal, blue, green, etc.)
 *  - .app-btn-{color}     : variante de .app-btn-primary teintée
 *  - .app-kpi-tint-{name} : fond dégradé doux d'une catégorie
 *  - .app-section-bar-{c} : barre verticale à gauche d'un titre de section
 *  - .app-empty-tint-{c}  : empty state au fond légèrement coloré
 * ────────────────────────────────────────────────────────────────────── */

/* Box colorée façon iOS Settings autour des icônes nav.
   On la met sur la <span class="nav-icon"> qui wrappe le SVG.
   Reste rétro-compatible : les nav existantes sans .nav-icon continuent
   d'afficher leur SVG inline. */
.app-nav-links a .nav-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  margin-right: 0.45rem;
  flex-shrink: 0;
  background: var(--fill-secondary);
  color: var(--label-secondary);
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s var(--ease-spring);
}
.app-nav-links a .nav-icon svg {
  width: 14px;
  height: 14px;
  display: block;
  stroke: currentColor;
}
.app-nav-links a:hover .nav-icon  { transform: scale(1.04); }
.app-nav-links a.active .nav-icon { box-shadow: 0 1px 2px rgba(0,0,0,0.18); }

/* Icônes de nav plus grandes côté client (écoles / élèves / enseignants).
   Le back-office admin (.app-nav-admin) garde sa taille d'origine. Demande Julien. */
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-icon { width: 36px; height: 36px; border-radius: 9px; }
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-icon svg { width: 22px; height: 22px; }
/* Pastille un peu plus lisible sur l'icône agrandie. */
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-badge { min-width: 17px; height: 17px; line-height: 17px; font-size: 0.62rem; top: -6px; right: -7px; }

/* Pastille de notification posée sur l'icône d'une section (même style que la
   messagerie). Le compteur est injecté en JS depuis /gestion/notifications.json. */
.app-nav-links a .nav-icon { position: relative; }
.app-nav-links a .nav-badge {
  position: absolute; top: -5px; right: -6px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--system-red, #ff3b30);
  color: #fff; font-size: 0.6rem; font-weight: 700; line-height: 16px;
  text-align: center; box-shadow: 0 0 0 2px var(--bg-secondary, #fff);
  pointer-events: none;
}
.app-nav-links a .nav-badge[hidden] { display: none; }

/* Variantes thématiques : fond saturé + icône blanche (sur nav claire) */
.nav-icon-blue   { background: var(--sys-blue)   !important; color: #fff !important; }
.nav-icon-indigo { background: var(--sys-indigo) !important; color: #fff !important; }
.nav-icon-purple { background: var(--sys-purple) !important; color: #fff !important; }
.nav-icon-pink   { background: var(--sys-pink)   !important; color: #fff !important; }
.nav-icon-red    { background: var(--sys-red)    !important; color: #fff !important; }
.nav-icon-orange { background: var(--sys-orange) !important; color: #fff !important; }
.nav-icon-yellow { background: var(--sys-yellow) !important; color: #1a1a1a !important; }
.nav-icon-green  { background: var(--sys-green)  !important; color: #fff !important; }
.nav-icon-mint   { background: var(--sys-mint)   !important; color: #1a1a1a !important; }
.nav-icon-teal   { background: var(--sys-teal)   !important; color: #fff !important; }
.nav-icon-cyan   { background: var(--sys-cyan)   !important; color: #1a1a1a !important; }
.nav-icon-gray   { background: var(--sys-gray)   !important; color: #fff !important; }
.nav-icon-brown  { background: var(--sys-brown)  !important; color: #fff !important; }

/* Back-office admin (.app-nav-admin, gradient sombre) : garde les box saturées
   (icône blanche, lisibles sur fond foncé). Les navs CLIENT (école / enseignant /
   élève / parent) passent en style « Apple » : glyphe en trait, et seul le module
   ACTIF (cliqué) reprend un CARRÉ PLEIN dans SA couleur (.nav-icon-<couleur>). La
   couleur marque l'écran courant + les pastilles de notification, pas toute la rangée. */
html:not(.nav-layout-side) .app-nav:not(.app-nav-admin) .app-nav-links a:not(.active) .nav-icon {
  background: transparent !important;
  color: color-mix(in srgb, var(--label-primary) 68%, transparent) !important;
  box-shadow: none !important;
}
html:not(.nav-layout-side) .app-nav:not(.app-nav-admin) .app-nav-links a:not(.active):hover .nav-icon { color: var(--label-primary) !important; }
/* Actif : on NE surcharge PAS le fond → la classe .nav-icon-<couleur> ci-dessus
   reprend la main (fond --sys-X + glyphe blanc). Demande Julien : « le carré
   en couleur plutôt qu'en noir ». */
/* La nav brandée d'une école utilise le MÊME traitement : depuis le Liquid Glass,
   sa barre est le matériau verre (le dégradé de marque app.css:4139 est reprise par
   liquid-glass.css, chargé après) — donc glyphes en trait + actif en --brand-primary
   (la couleur de l'école), parfaitement lisibles sur le verre. Pas de règle dédiée. */
/* Demande Julien (2026-06-10) : PAS d'« encadrement » (pastille de fond du lien actif)
   autour du carré de couleur. Sur le verre + fond de saison vif, cette pastille
   `a.active` (gris translucide) se teintait et formait un cadre disgracieux. L'écran
   courant est déjà signalé par l'icône colorée + le libellé en gras → on retire la
   pastille pour les navs CLIENT. L'admin (nav sombre opaque) garde la sienne. */
.app-nav:not(.app-nav-admin) .app-nav-links a.active { background: transparent !important; }
.app-nav:not(.app-nav-admin) .app-nav-links a:hover  { background: transparent !important; }

/* ─── Popover « Apparence » de la nav (theme-switch.ejs, showIntensity) ───
   Loge le curseur d'intensité du fond pour TOUS les rôles utilisateurs (élève /
   enseignant / parent / client) sans élargir la barre. Surface verre = mêmes tokens
   que le reste du système Liquid Glass → s'adapte clair/sombre tout seul. */
.app-appearance-wrap { position: relative; display: inline-flex; align-items: center; }
.app-appearance-trigger { color: var(--label-secondary, #6b7280); }
.app-appearance-trigger[aria-expanded="true"] { color: var(--label-primary); background: var(--off, rgba(0,0,0,0.05)); }
/* Super-nav navy (espace super-admin) : le bouton d'intensité porte app-btn-ghost
   (fond clair + bordure, pensé pour surfaces claires) → il jure sur le navy. On
   l'aligne EXACTEMENT sur les autres icônes de la barre (.app-nav-icon-btn).
   Scopé .app-nav-admin → aucun impact sur les navs claires (client/enseignant). */
.app-nav-admin .app-btn-ghost.app-appearance-trigger {
  width: 38px; height: 38px; padding: 0; justify-content: center;
  background: transparent; border: none; border-radius: 8px;
  box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  color: rgba(255, 255, 255, 0.7); transition: background 0.15s, color 0.15s;
}
.app-nav-admin .app-appearance-trigger svg { width: 18px; height: 18px; }
.app-nav-admin .app-btn-ghost.app-appearance-trigger:hover { background: rgba(255, 255, 255, 0.08); color: #fff; border-color: transparent; }
.app-nav-admin .app-btn-ghost.app-appearance-trigger[aria-expanded="true"] { background: rgba(255, 255, 255, 0.15); color: #fff; }
.app-appearance-pop {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 1200;
  width: 248px;
  padding: 0.9rem 1rem 1rem;
  background: var(--lg-surface-strong, var(--bg-elevated, #fff));
  border: 1px solid var(--lg-border, rgba(0,0,0,0.08));
  border-radius: 16px;
  box-shadow: var(--lg-highlight, none), var(--lg-shadow-lg, 0 16px 44px rgba(0,0,0,0.20));
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 18px)) saturate(1.6);
  backdrop-filter: blur(var(--lg-blur-card, 18px)) saturate(1.6);
}
.app-appearance-pop[hidden] { display: none; }
.app-appearance-pop-title { font-weight: 650; font-size: 0.86rem; margin: 0 0 0.7rem; color: var(--label-primary); }
.app-appearance-pop-row { display: flex; align-items: center; gap: 0.55rem; }
.app-appearance-pop-row span { font-size: 0.72rem; color: var(--label-tertiary, #9ca3af); white-space: nowrap; }
.app-appearance-pop-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--brand-primary, var(--brand-navy)); cursor: pointer; }
.app-appearance-pop-note { margin: 0.7rem 0 0; font-size: 0.72rem; line-height: 1.4; color: var(--label-tertiary, #9ca3af); }
/* Tablette/mobile : la nav-user passe dans le tiroir et le bouton peut être n'importe
   où dans la rangée → un popover ancré au déclencheur déborderait. On le passe en
   FEUILLE ancrée au bas de l'écran (fixed + marges G/D) : largeur contrainte par le
   viewport, donc aucun débordement possible, et c'est le geste mobile naturel.
   Reste un descendant DOM de .app-appearance-wrap → le clic-extérieur marche toujours. */
@media (max-width: 768px) {
  .app-appearance-pop {
    position: fixed;
    top: auto;
    left: 12px;
    right: 12px;
    bottom: 14px;
    width: auto;
    z-index: 2000;
    /* Feuille opaque (lisible par-dessus le tiroir) + voile sombre plein écran
       (spread box-shadow, aucun élément ajoute) : vraie feuille d'action. Le voile
       n'intercepte pas le clic → taper a cote referme (clic hors .app-appearance-wrap). */
    background: var(--bg-elevated, #fff);
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.34), 0 -8px 30px rgba(0, 0, 0, 0.18);
  }
}

/* ─── Tags : palette complète (s'ajoute à app-tag-blue/green/amber/red/purple/slate/indigo/teal) ─── */
.app-tag-pink   { background: var(--sys-pink-soft);   color: var(--sys-pink); }
.app-tag-orange { background: var(--sys-orange-soft); color: var(--sys-orange); }
.app-tag-yellow { background: var(--sys-yellow-soft); color: #b47e00; }
.app-tag-mint   { background: var(--sys-mint-soft);   color: #0d8e87; }
.app-tag-cyan   { background: var(--sys-cyan-soft);   color: #0c89c2; }
.app-tag-gray   { background: var(--sys-gray-soft);   color: var(--sys-gray); }
.app-tag-brown  { background: var(--sys-brown-soft);  color: #7c5f3e; }
/* En dark : textes éclaircis (les soft-* sont déjà ré-opacifiés par data-theme dark) */
:root[data-theme="dark"] .app-tag-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-tag-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-tag-cyan   { color: var(--sys-cyan); }
:root[data-theme="dark"] .app-tag-brown  { color: var(--sys-brown); }

/* ─── Section tags : équivalent (existant) — extensions de palette ─── */
.app-section-tag-blue   { background: var(--sys-blue-soft);   color: var(--sys-blue); }
.app-section-tag-red    { background: var(--sys-red-soft);    color: var(--sys-red); }
.app-section-tag-orange { background: var(--sys-orange-soft); color: var(--sys-orange); }
.app-section-tag-yellow { background: var(--sys-yellow-soft); color: #b47e00; }
.app-section-tag-mint   { background: var(--sys-mint-soft);   color: #0d8e87; }
.app-section-tag-cyan   { background: var(--sys-cyan-soft);   color: #0c89c2; }
.app-section-tag-gray   { background: var(--sys-gray-soft);   color: var(--sys-gray); }
:root[data-theme="dark"] .app-section-tag-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-section-tag-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-section-tag-cyan   { color: var(--sys-cyan); }

/* ─── Boutons d'action thématiques (dérivés de .app-btn-primary) ─── */
.app-btn-blue,
.app-btn-indigo,
.app-btn-purple,
.app-btn-pink,
.app-btn-red,
.app-btn-orange,
.app-btn-yellow,
.app-btn-green,
.app-btn-mint,
.app-btn-teal,
.app-btn-cyan,
.app-btn-gray,
.app-btn-brown {
  color: #fff;
  border: 1.5px solid transparent;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.12);
  transition: filter 0.15s ease, transform 0.10s ease;
}
.app-btn-blue   { background: var(--sys-blue);   border-color: var(--sys-blue); }
.app-btn-indigo { background: var(--sys-indigo); border-color: var(--sys-indigo); }
.app-btn-purple { background: var(--sys-purple); border-color: var(--sys-purple); }
.app-btn-pink   { background: var(--sys-pink);   border-color: var(--sys-pink); }
.app-btn-red    { background: var(--sys-red);    border-color: var(--sys-red); }
.app-btn-orange { background: var(--sys-orange); border-color: var(--sys-orange); }
.app-btn-yellow { background: var(--sys-yellow); border-color: var(--sys-yellow); color: #1a1a1a; }
.app-btn-green  { background: var(--sys-green);  border-color: var(--sys-green); }
.app-btn-mint   { background: var(--sys-mint);   border-color: var(--sys-mint); color: #0a3633; }
.app-btn-teal   { background: var(--sys-teal);   border-color: var(--sys-teal); }
.app-btn-cyan   { background: var(--sys-cyan);   border-color: var(--sys-cyan); color: #0a2533; }
.app-btn-gray   { background: var(--sys-gray);   border-color: var(--sys-gray); }
.app-btn-brown  { background: var(--sys-brown);  border-color: var(--sys-brown); }
.app-btn-blue:hover,
.app-btn-indigo:hover,
.app-btn-purple:hover,
.app-btn-pink:hover,
.app-btn-red:hover,
.app-btn-orange:hover,
.app-btn-yellow:hover,
.app-btn-green:hover,
.app-btn-mint:hover,
.app-btn-teal:hover,
.app-btn-cyan:hover,
.app-btn-gray:hover,
.app-btn-brown:hover { filter: brightness(0.94); }

/* Dark mode : on garde les couleurs vives (illuminées via les variables dark) */
:root[data-theme="dark"] .app-btn-blue,
:root[data-theme="dark"] .app-btn-indigo,
:root[data-theme="dark"] .app-btn-purple,
:root[data-theme="dark"] .app-btn-pink,
:root[data-theme="dark"] .app-btn-red,
:root[data-theme="dark"] .app-btn-orange,
:root[data-theme="dark"] .app-btn-green,
:root[data-theme="dark"] .app-btn-teal,
:root[data-theme="dark"] .app-btn-gray,
:root[data-theme="dark"] .app-btn-brown { color: #fff !important; }
:root[data-theme="dark"] .app-btn-yellow,
:root[data-theme="dark"] .app-btn-mint,
:root[data-theme="dark"] .app-btn-cyan  { color: #1a1a1a !important; }

/* ─── KPI tints : extensions palette System (light gradient vers paper) ─── */
.app-kpi-tint-blue   { background: linear-gradient(180deg, var(--sys-blue-soft),   var(--paper) 60%); }
.app-kpi-tint-indigo { background: linear-gradient(180deg, var(--sys-indigo-soft), var(--paper) 60%); }
.app-kpi-tint-purple { background: linear-gradient(180deg, var(--sys-purple-soft), var(--paper) 60%); }
.app-kpi-tint-pink   { background: linear-gradient(180deg, var(--sys-pink-soft),   var(--paper) 60%); }
.app-kpi-tint-red    { background: linear-gradient(180deg, var(--sys-red-soft),    var(--paper) 60%); }
.app-kpi-tint-orange { background: linear-gradient(180deg, var(--sys-orange-soft), var(--paper) 60%); }
.app-kpi-tint-yellow { background: linear-gradient(180deg, var(--sys-yellow-soft), var(--paper) 60%); }
.app-kpi-tint-green  { background: linear-gradient(180deg, var(--sys-green-soft),  var(--paper) 60%); }
.app-kpi-tint-mint   { background: linear-gradient(180deg, var(--sys-mint-soft),   var(--paper) 60%); }
.app-kpi-tint-teal   { background: linear-gradient(180deg, var(--sys-teal-soft),   var(--paper) 60%); }
.app-kpi-tint-cyan   { background: linear-gradient(180deg, var(--sys-cyan-soft),   var(--paper) 60%); }
.app-kpi-tint-gray   { background: linear-gradient(180deg, var(--sys-gray-soft),   var(--paper) 60%); }
.app-kpi-tint-brown  { background: linear-gradient(180deg, var(--sys-brown-soft),  var(--paper) 60%); }

/* ─── Section bar : barre verticale colorée à gauche d'un titre de section
       (ajouter la classe sur un <h2> ou un .app-section-header) ─── */
.app-section-bar-blue,
.app-section-bar-indigo,
.app-section-bar-purple,
.app-section-bar-pink,
.app-section-bar-red,
.app-section-bar-orange,
.app-section-bar-yellow,
.app-section-bar-green,
.app-section-bar-mint,
.app-section-bar-teal,
.app-section-bar-cyan,
.app-section-bar-gray,
.app-section-bar-brown {
  padding-left: 0.7rem;
  border-left: 3px solid currentColor;
}
.app-section-bar-blue   { color: var(--sys-blue); }
.app-section-bar-indigo { color: var(--sys-indigo); }
.app-section-bar-purple { color: var(--sys-purple); }
.app-section-bar-pink   { color: var(--sys-pink); }
.app-section-bar-red    { color: var(--sys-red); }
.app-section-bar-orange { color: var(--sys-orange); }
.app-section-bar-yellow { color: #b47e00; }
.app-section-bar-green  { color: var(--sys-green); }
.app-section-bar-mint   { color: #0d8e87; }
.app-section-bar-teal   { color: var(--sys-teal); }
.app-section-bar-cyan   { color: #0c89c2; }
.app-section-bar-gray   { color: var(--sys-gray); }
.app-section-bar-brown  { color: #7c5f3e; }
:root[data-theme="dark"] .app-section-bar-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-section-bar-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-section-bar-cyan   { color: var(--sys-cyan); }
:root[data-theme="dark"] .app-section-bar-brown  { color: var(--sys-brown); }
/* On force navy/text sur le titre lui-même pour la lisibilité, la couleur
   ne sert qu'à la barre via currentColor → border-left */
.app-section-bar-blue,
.app-section-bar-indigo,
.app-section-bar-purple,
.app-section-bar-pink,
.app-section-bar-red,
.app-section-bar-orange,
.app-section-bar-yellow,
.app-section-bar-green,
.app-section-bar-mint,
.app-section-bar-teal,
.app-section-bar-cyan,
.app-section-bar-gray,
.app-section-bar-brown { /* la couleur ci-dessus pilote la barre via currentColor */ }
.app-section-bar-blue   > h1, .app-section-bar-blue   > h2,
.app-section-bar-indigo > h1, .app-section-bar-indigo > h2,
.app-section-bar-purple > h1, .app-section-bar-purple > h2,
.app-section-bar-pink   > h1, .app-section-bar-pink   > h2,
.app-section-bar-red    > h1, .app-section-bar-red    > h2,
.app-section-bar-orange > h1, .app-section-bar-orange > h2,
.app-section-bar-yellow > h1, .app-section-bar-yellow > h2,
.app-section-bar-green  > h1, .app-section-bar-green  > h2,
.app-section-bar-mint   > h1, .app-section-bar-mint   > h2,
.app-section-bar-teal   > h1, .app-section-bar-teal   > h2,
.app-section-bar-cyan   > h1, .app-section-bar-cyan   > h2,
.app-section-bar-gray   > h1, .app-section-bar-gray   > h2,
.app-section-bar-brown  > h1, .app-section-bar-brown  > h2 { color: var(--navy); }

/* ─── Empty states tintés (fond pâle de la couleur thématique) ─── */
.app-empty-tint-blue,
.app-empty-tint-indigo,
.app-empty-tint-purple,
.app-empty-tint-pink,
.app-empty-tint-red,
.app-empty-tint-orange,
.app-empty-tint-yellow,
.app-empty-tint-green,
.app-empty-tint-mint,
.app-empty-tint-teal,
.app-empty-tint-cyan,
.app-empty-tint-gray,
.app-empty-tint-brown {
  border-radius: var(--radius-md);
  border: 1px dashed var(--separator);
}
.app-empty-tint-blue   { background: var(--sys-blue-soft); }
.app-empty-tint-indigo { background: var(--sys-indigo-soft); }
.app-empty-tint-purple { background: var(--sys-purple-soft); }
.app-empty-tint-pink   { background: var(--sys-pink-soft); }
.app-empty-tint-red    { background: var(--sys-red-soft); }
.app-empty-tint-orange { background: var(--sys-orange-soft); }
.app-empty-tint-yellow { background: var(--sys-yellow-soft); }
.app-empty-tint-green  { background: var(--sys-green-soft); }
.app-empty-tint-mint   { background: var(--sys-mint-soft); }
.app-empty-tint-teal   { background: var(--sys-teal-soft); }
.app-empty-tint-cyan   { background: var(--sys-cyan-soft); }
.app-empty-tint-gray   { background: var(--sys-gray-soft); }
.app-empty-tint-brown  { background: var(--sys-brown-soft); }


/* ──────────────────────────────────────────────────────────────────────
 * Custom Branding (option premium) — 2026-05-26
 * ──────────────────────────────────────────────────────────────────────
 * Quand une école active l'option Custom Branding, ses pages injectent
 *   <style>:root { --brand-primary: #xxxxxx; }</style>
 * en tête. Les sélecteurs ci-dessous appliquent cette variable aux
 * endroits stratégiques de l'app (header nav + boutons primaires +
 * pills d'onglet actif), avec fallback sur --navy (branding app).
 *
 * Le fallback est important : si la variable n'est pas définie, l'app
 * garde l'apparence de l'application — pas de cascade cassée.
 * ────────────────────────────────────────────────────────────────────── */

/* Navigation : background teinté quand une école a son branding actif */
.app-nav.app-nav-branded {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--brand-primary, var(--navy)) 92%, transparent),
    color-mix(in srgb, var(--brand-primary, var(--navy)) 80%, transparent));
  border-bottom-color: transparent;
  color: #fff;
}
.app-nav.app-nav-branded .app-nav-brand,
.app-nav.app-nav-branded .app-nav-user-name,
.app-nav.app-nav-branded .app-nav-user-info { color: #fff; }
.app-nav.app-nav-branded .app-nav-brand small { color: rgba(255,255,255,0.78); font-weight: 400; }
.app-nav.app-nav-branded .app-nav-user-sub { color: rgba(255,255,255,0.7); }
.app-nav.app-nav-branded .app-nav-links a { color: rgba(255,255,255,0.75); }
.app-nav.app-nav-branded .app-nav-links a:hover { background: rgba(255,255,255,0.10); color: #fff; }
.app-nav.app-nav-branded .app-nav-links a.active { background: rgba(255,255,255,0.18); color: #fff; }
.app-nav.app-nav-branded .app-nav-icon-btn { color: rgba(255,255,255,0.85); }
.app-nav.app-nav-branded .app-nav-icon-btn:hover { background: rgba(255,255,255,0.10); color: #fff; }

/* Logo custom uploadé par l'école — léger fond blanc pour PNG transparent */
.app-logo-custom {
  background: rgba(255,255,255,0.95);
  padding: 2px 6px;
  border-radius: 6px;
}
.app-nav:not(.app-nav-branded) .app-logo-custom { background: transparent; padding: 0; }

/* ═══════════════════════════════════════════════════════════
   Modale fiche élève : grille 4 colonnes sectionnée
   (partagée par "Nouvel élève" et "Modifier" — eleves-list + eleve-detail)
   ═══════════════════════════════════════════════════════════ */
.eleve-edit-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem 0.8rem;
  max-height: 75vh;
  overflow-y: auto;
}
.eleve-edit-grid label > span {
  font-size: 0.74rem;
  font-weight: 500;
  color: var(--label-secondary);
  margin-bottom: 0.2rem;
  display: block;
}
@media (max-width: 720px) {
  .eleve-edit-grid { grid-template-columns: repeat(2, 1fr); }
  .eleve-edit-grid > label[style*="grid-column:span 3"],
  .eleve-edit-grid > label[style*="grid-column:span 4"] { grid-column: 1/-1 !important; }
}


/* ===== Bannières de statut (.app-flash) & toasts (window.appToast) =====
   Sobre, façon Apple : liseré gauche coloré + fond teinté qui s'adapte au
   mode sombre (color-mix avec la surface). Pas de verre : une alerte doit
   rester parfaitement lisible. Compatible avec les bannières serveur
   existantes (sans icône) ET les toasts (avec icône SVG). */
.app-flash {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.8rem 1rem;
  border: 1px solid var(--separator);
  border-left: 3px solid var(--label-secondary);
  border-radius: 12px;
  background: var(--fill-tertiary);
  color: var(--label-primary);
  font-size: 0.9rem;
  line-height: 1.4;
}
.app-flash > svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; }
.app-flash > span { flex: 1 1 auto; min-width: 0; }
.app-flash-success { border-left-color: var(--system-green);  background: color-mix(in srgb, var(--system-green) 12%, var(--bg-secondary)); }
.app-flash-success > svg { color: var(--system-green); }
.app-flash-error   { border-left-color: var(--system-red);    background: color-mix(in srgb, var(--system-red) 12%, var(--bg-secondary)); }
.app-flash-error > svg { color: var(--system-red); }
.app-flash-warning { border-left-color: var(--system-orange); background: color-mix(in srgb, var(--system-orange) 14%, var(--bg-secondary)); }
.app-flash-warning > svg { color: var(--system-orange); }
.app-flash-info    { border-left-color: var(--system-blue);   background: color-mix(in srgb, var(--system-blue) 12%, var(--bg-secondary)); }
.app-flash-info > svg { color: var(--system-blue); }

/* Pile de toasts : un seul conteneur, au premier plan (au-dessus de la nav,
   des modales, de la bulle d'aide). Corrige le toast qui passait sous le
   bouton « Ajouter ». */
#app-toast-stack {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: min(360px, calc(100vw - 2rem));
  pointer-events: none;
}
#app-toast-stack .app-flash {
  pointer-events: auto;
  cursor: pointer;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg, 0 8px 28px rgba(15, 37, 68, 0.18));
  animation: appToastIn 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#app-toast-stack .app-flash-success { background: color-mix(in srgb, var(--system-green) 12%, var(--bg-elevated)); }
#app-toast-stack .app-flash-error   { background: color-mix(in srgb, var(--system-red) 12%, var(--bg-elevated)); }
#app-toast-stack .app-flash-warning { background: color-mix(in srgb, var(--system-orange) 14%, var(--bg-elevated)); }
#app-toast-stack .app-flash-info    { background: color-mix(in srgb, var(--system-blue) 12%, var(--bg-elevated)); }
@keyframes appToastIn {
  from { opacity: 0; transform: translateY(16px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #app-toast-stack .app-flash { animation: none; }
}

/* ===== Toast « Dynamic Island » (opts.island = true) =====================
   Pilule SOMBRE flottante, centrée en haut, qui s'étire à l'apparition
   (largeur + opacité) puis se replie à la sortie. Lisible (texte clair sur
   fond sombre quel que soit le thème) ; la couleur du type est portée par
   l'icône uniquement, pour garder l'aspect « île » uni. */
#app-toast-island {
  position: fixed;
  top: max(0.75rem, env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  z-index: 10001;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: max-content;
  max-width: min(440px, calc(100vw - 1.5rem));
  pointer-events: none;
}
.app-island {
  pointer-events: auto;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 1.1rem;
  border-radius: var(--r-pill, 100px);
  background: var(--island-bg, rgba(20,22,28,0.92));
  color: var(--island-fg, #f5f5f7);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.3;
  box-shadow: var(--shadow-lg);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
  transform-origin: top center;
  animation: appIslandIn 0.42s var(--ease-spring, cubic-bezier(0.34,1.56,0.64,1));
}
.app-island > svg { flex: 0 0 auto; width: 17px; height: 17px; }
.app-island > span { flex: 1 1 auto; min-width: 0; }
.app-island-success > svg { color: var(--system-green); }
.app-island-error   > svg { color: var(--system-red); }
.app-island-warning > svg { color: var(--system-orange); }
.app-island-info    > svg { color: var(--system-blue); }
.app-island--out { animation: appIslandOut 0.26s var(--ease, ease) forwards; }
@keyframes appIslandIn {
  from { opacity: 0; transform: scaleX(0.4) scaleY(0.7) translateY(-8px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}
@keyframes appIslandOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: scaleX(0.5) scaleY(0.6) translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
  .app-island { animation: none; }
  .app-island--out { animation: none; opacity: 0; }
}

/* ════════════════════════════════════════════════════════════════════
   Assistant IA omniprésent (public/ai-assist.js)
   - Boutons « Rédiger avec l'IA » auto-injectés sur les champs data-ai-task
   - Lanceur + panneau de discussion flottants (toutes les pages staff)
   Sparkle navy, verre cohérent avec les modales, thème-aware.
   ════════════════════════════════════════════════════════════════════ */
.ai-spark { vertical-align: -3px; color: var(--accent-2, #5e7fa8); fill: currentColor; flex: 0 0 auto; }

/* ── Boutons sur les champs ─────────────────────────────────────────── */
.ai-field-tools {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px;
  margin: 8px 0 2px;
}
.ai-field-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; font-size: 0.85rem; font-weight: 600;
  color: var(--tint, #0f2544);
  background: color-mix(in srgb, var(--accent-2, #5e7fa8) 13%, var(--bg-elevated));
  border: 1px solid color-mix(in srgb, var(--accent-2, #5e7fa8) 32%, transparent);
  border-radius: 999px; cursor: pointer;
  transition: background .18s var(--ease-out-smooth), transform .12s var(--ease-out-smooth), box-shadow .18s;
}
.ai-field-btn:hover { background: color-mix(in srgb, var(--accent-2, #5e7fa8) 22%, var(--bg-elevated)); box-shadow: var(--shadow-soft); }
.ai-field-btn:active { transform: translateY(1px); }
.ai-field-btn:disabled { opacity: .6; cursor: default; }
.ai-field-btn.is-busy .ai-spark { animation: aiSpin 1s linear infinite; }
.ai-field-status { font-size: 0.8rem; color: var(--label-secondary); }
.ai-field-status.is-ok { color: #16a34a; }
.ai-field-status.is-err { color: #dc2626; }
.ai-field-status.is-warn { color: #b45309; }
.ai-field-status .ai-undo { color: var(--tint); text-decoration: underline; }
@keyframes aiSpin { to { transform: rotate(360deg); } }

/* ── Lanceur flottant ───────────────────────────────────────────────── */
.ai-launcher {
  position: fixed; left: max(20px, env(safe-area-inset-left)); bottom: max(20px, env(safe-area-inset-bottom));
  /* Au-dessus de tout : rien ne doit passer devant l'assistant.
     Il etait auparavant sous les pop-up parce que, sur telephone, il se posait sur le
     coin des boutons Enregistrer / Annuler et recevait le clic a leur place. La bonne
     reponse n'etait pas de le baisser, mais de ne pas mettre de boutons sous lui : le
     pied des pop-up lui reserve sa place (voir `.app-modal-ouverte` plus bas). */
  z-index: 100000;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 18px; border: none; border-radius: 999px; cursor: pointer;
  color: #fff; font-weight: 650; font-size: 0.95rem;
  background: linear-gradient(135deg, #16335a 0%, #0f2544 100%);
  box-shadow: 0 10px 28px rgba(15,37,68,0.38), inset 0 1px 0 rgba(255,255,255,0.12);
  transition: transform .18s var(--ease-out-smooth), box-shadow .18s, opacity .2s;
}
.ai-launcher .ai-spark { color: #cfe0ff; }
.ai-launcher:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(15,37,68,0.46), inset 0 1px 0 rgba(255,255,255,0.16); }
.ai-launcher:active { transform: translateY(0); }
.ai-launcher.is-open { opacity: 0; pointer-events: none; }
@media (max-width: 640px) {
  .ai-launcher { padding: 13px; }
  .ai-launcher-label { display: none; }
}
@media print { .ai-launcher, .ai-assistant { display: none !important; } }

/* ── Fil de discussion support (tickets) — bulles lisibles clair ET sombre ──
   N'utilise PAS var(--navy) (redéfini en couleur de texte) : couleurs explicites
   contrastées dans les deux thèmes. « mine » = bulle bleue alignée à droite,
   « them » = surface neutre alignée à gauche. */
.tk-thread { display: flex; flex-direction: column; gap: 0.8rem; }
.tk-row { display: flex; }
.tk-row.mine { justify-content: flex-end; }
.tk-bubble {
  max-width: 80%; padding: 0.7rem 0.9rem; border-radius: 14px;
  border-bottom-left-radius: 4px;
  background: var(--bg-tertiary); color: var(--text);
}
.tk-row.mine .tk-bubble {
  background: #2f5e8f; color: #fff;
  border-bottom-left-radius: 14px; border-bottom-right-radius: 4px;
}
.tk-meta { font-size: 0.7rem; opacity: 0.7; margin-bottom: 0.2rem; }
.tk-body { font-size: 0.9rem; white-space: pre-wrap; word-wrap: break-word; }

/* Suggestions contextuelles (puces de verre) — adaptées à la page courante */
.ai-suggestions { display: flex; flex-wrap: wrap; gap: 7px; padding: 2px 2px 6px; }
.ai-chip {
  font: inherit; font-size: 0.82rem; line-height: 1.3; text-align: left;
  padding: 7px 12px; border-radius: 999px; cursor: pointer;
  color: var(--label-primary);
  background: color-mix(in srgb, var(--accent-2, #5e7fa8) 13%, var(--bg-elevated));
  border: 1px solid color-mix(in srgb, var(--accent-2, #5e7fa8) 30%, transparent);
  transition: background .15s, border-color .15s, transform .1s;
}
.ai-chip:hover { background: color-mix(in srgb, var(--accent-2, #5e7fa8) 22%, var(--bg-elevated)); border-color: var(--accent-2, #5e7fa8); }
.ai-chip:active { transform: translateY(1px); }

/* ── Panneau de discussion ──────────────────────────────────────────── */
.ai-assistant {
  position: fixed; left: max(20px, env(safe-area-inset-left)); bottom: max(20px, env(safe-area-inset-bottom)); z-index: 1210;
  width: 380px; max-width: calc(100vw - 32px); height: 72vh; max-height: 620px;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--lg-surface-strong, rgba(255,255,255,0.80)); color: var(--label-primary);
  border: 1px solid var(--lg-border, var(--separator)); border-radius: var(--radius-lg, 18px);
  box-shadow: var(--lg-shadow-lg, var(--shadow-overlay));
  -webkit-backdrop-filter: blur(30px) saturate(180%); backdrop-filter: blur(30px) saturate(180%);
  animation: aiPanelIn .26s var(--ease-out-smooth);
}
.ai-assistant[hidden] { display: none; }
@keyframes aiPanelIn { from { opacity: 0; transform: translateY(14px) scale(.98); } to { opacity: 1; transform: none; } }
.ai-assistant-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--separator);
}
.ai-assistant-title { display: inline-flex; align-items: center; gap: 8px; font-weight: 680; }
.ai-assistant-title .ai-spark { color: var(--accent-2, #5e7fa8); }
.ai-assistant-head-actions { display: flex; gap: 4px; }
.ai-assistant-clear, .ai-assistant-close {
  border: none; background: transparent; cursor: pointer; color: var(--label-secondary);
  width: 30px; height: 30px; border-radius: 8px; font-size: 1.05rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s;
}
.ai-assistant-clear:hover, .ai-assistant-close:hover { background: var(--fill-tertiary); color: var(--label-primary); }
.ai-assistant-msgs {
  flex: 1 1 auto; overflow-y: auto; padding: 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.ai-msg {
  max-width: 86%; padding: 9px 12px; border-radius: 14px;
  font-size: 0.9rem; line-height: 1.45; white-space: pre-wrap; word-wrap: break-word;
}
.ai-msg-user { align-self: flex-end; background: linear-gradient(135deg, #16335a, #0f2544); color: #fff; border-bottom-right-radius: 5px; }
.ai-msg-assistant { align-self: flex-start; background: var(--fill-secondary); color: var(--label-primary); border-bottom-left-radius: 5px; }
.ai-typing { display: inline-flex; gap: 4px; align-items: center; }
.ai-typing span { width: 7px; height: 7px; border-radius: 50%; background: var(--label-secondary); opacity: .5; animation: aiTyping 1.1s infinite ease-in-out; }
.ai-typing span:nth-child(2) { animation-delay: .18s; }
.ai-typing span:nth-child(3) { animation-delay: .36s; }
@keyframes aiTyping { 0%, 60%, 100% { transform: translateY(0); opacity: .4; } 30% { transform: translateY(-4px); opacity: .9; } }
.ai-assistant-form {
  display: flex; align-items: flex-end; gap: 8px; padding: 10px 12px 4px;
  border-top: 1px solid var(--separator);
}
.ai-assistant-text {
  flex: 1 1 auto; resize: none; min-height: 38px; max-height: 140px;
  padding: 9px 12px; border: 1px solid var(--separator); border-radius: 12px;
  background: var(--bg-base, var(--bg-elevated)); color: var(--label-primary);
  font: inherit; font-size: 0.9rem;
}
.ai-assistant-text:focus { outline: none; border-color: var(--accent-2, #5e7fa8); box-shadow: var(--ring-focus); }
.ai-assistant-send {
  flex: 0 0 auto; width: 40px; height: 40px; border: none; border-radius: 12px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; color: #fff;
  background: linear-gradient(135deg, #16335a, #0f2544);
  transition: transform .12s var(--ease-out-smooth), opacity .15s;
}
.ai-assistant-send:hover { transform: translateY(-1px); }
.ai-assistant-send:active { transform: translateY(0); }
.ai-assistant-ctx {
  display: flex; align-items: center; gap: 7px; padding: 4px 14px 12px;
  font-size: 0.8rem; color: var(--label-secondary); cursor: pointer;
}
.ai-assistant-ctx input { accent-color: var(--tint, #0f2544); }
.ai-assistant-support {
  padding: 10px 14px 12px; border-top: 1px solid var(--separator, rgba(0,0,0,0.07));
  display: flex; flex-direction: column; gap: 6px;
}
.ai-assistant-ticket {
  width: 100%; padding: 9px 12px; border: 1px solid var(--separator, #d0d7e2);
  background: var(--off, #f5f7fb); color: var(--navy, #0f2544); border-radius: 9px;
  font-size: 0.82rem; font-weight: 600; cursor: pointer; transition: border-color .15s, background .15s;
}
.ai-assistant-ticket:hover { border-color: var(--accent, #5e7fa8); background: var(--paper, #fff); }
.ai-assistant-ticket:disabled { opacity: 0.6; cursor: default; }
.ai-assistant-tickets-link {
  font-size: 0.76rem; color: var(--label-secondary); text-align: center; text-decoration: none;
}
.ai-assistant-tickets-link:hover { text-decoration: underline; }
.ai-assistant-ticket.is-emphasis { border-color: var(--accent, #5e7fa8); background: var(--paper, #fff); box-shadow: 0 0 0 3px rgba(94,127,168,0.18); }
.ai-assistant-call {
  display: block; width: 100%; padding: 9px 12px; text-align: center; box-sizing: border-box;
  background: #dc2626; color: #fff; border-radius: 9px; font-size: 0.82rem; font-weight: 700; text-decoration: none;
}
.ai-assistant-call:hover { background: #b91c1c; }
@media (max-width: 640px) {
  .ai-assistant { right: 0; left: 0; bottom: 0; width: 100%; max-width: 100%; height: 80vh; border-radius: 18px 18px 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ai-assistant { animation: none; }
  .ai-field-btn.is-busy .ai-spark, .ai-typing span { animation: none; }
}


/* ════════════════════════════════════════════════════════════════════
   Bandeau « mode dev » (staging/dev uniquement — rendu par head.ejs quand
   isDevEnv, jamais en production). Meme bandeau que la vitrine roddier.dev.
   pointer-events:none : pur marqueur, ne bloque jamais un clic.
   ════════════════════════════════════════════════════════════════════ */
.app-dev-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  background: #d70015;  /* a11y : #ff3b30 = 3.5:1 sous le blanc → #d70015 ≈ 4.6:1 */
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  /* Hauteur FIXE = exactement le decalage applique au body et a la nav (1.85rem) :
     bandeau et barre sont jointifs quel que soit le rendu de police du moteur
     (en padding seul, la hauteur reelle variait -> ~5 px de jour sous le bandeau). */
  height: 1.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 1rem;
  z-index: 9999;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.20);
  pointer-events: none;
}
.app-dev-banner::before { content: '\26A0  '; }
/* Le contenu et la nav collante descendent de la hauteur du bandeau. */
body.has-dev-banner { padding-top: 1.85rem; }
body.has-dev-banner .app-nav { top: 1.85rem; }
/* Jamais a l'impression (factures, attestations, fiches). */
@media print {
  .app-dev-banner { display: none !important; }
  body.has-dev-banner { padding-top: 0 !important; }
}

/* ─── Révision du Code : accessibilité (allophones / dys) ─────────────────────
 * L'examen ETG est en FRANÇAIS uniquement : on ne traduit pas, on aide à apprendre
 * EN FRANÇAIS. Mode « lecture facilitée » = typo plus grande/aérée + contraste
 * renforcé, activé via une classe sur <body> (préférence persistée localStorage).
 * Respecte la palette de marque (navy #0f2544). */

/* Variante en français simplifié de l'explication (« En clair : … »). */
.code-explication-simple {
  display: block;
  margin-top: 0.5rem;
  color: var(--text-primary, #0f2544);
  font-weight: 400;
}
.code-explication-simple-tag { font-weight: 600; }

/* Bouton « Écouter » / bascule lecture facilitée en cours d'action. */
.code-tts-btn.is-speaking { background: var(--white); border-color: var(--navy, #0f2544); }

/* Mode lecture facilitée : agrandit et aère le texte de la révision, renforce le
 * contraste. Ciblé sur l'écran de révision uniquement (#quiz-app et sa toolbar). */
body.code-lecture-facilitee #quiz-app { line-height: 1.7; }
body.code-lecture-facilitee #quiz-app .code-enonce {
  font-size: 1.35rem !important;
  line-height: 1.6;
  letter-spacing: 0.01em;
  color: #0f2544;
}
body.code-lecture-facilitee #quiz-app .code-option {
  font-size: 1.12rem;
  padding-top: 0.7rem;
  padding-bottom: 0.7rem;
  line-height: 1.5;
}
body.code-lecture-facilitee #quiz-app .code-feedback { font-size: 1.05rem; line-height: 1.65; }
body.code-lecture-facilitee #quiz-app .code-explication-simple { font-size: 1.08rem; }


/* === Ruban d'environnement (staging/dev only) — remplace le bandeau pleine largeur ===
   Convention repandue : petit ruban diagonal en coin haut-droit, ne pousse plus le contenu. */
.app-dev-banner, .sent-dev-banner, .dev-banner {
  top: 15px !important; left: -46px !important; right: auto !important; bottom: auto !important;
  width: auto !important; height: auto !important;
  transform: rotate(-45deg) !important; transform-origin: center !important;
  background: #b45309 !important; color: #fff !important;
  padding: 4px 48px !important; font-size: 10px !important; font-weight: 800 !important; letter-spacing: .16em !important;
  box-shadow: 0 2px 8px rgba(0,0,0,.35) !important; display: block !important; border-radius: 0 !important;
}
.app-dev-banner::before, .sent-dev-banner::before, .dev-banner::before { content: '' !important; }
body.has-dev-banner { padding-top: 0 !important; }
/* Ce rappel a zero ne concerne que les barres accrochees EN HAUT. La barre du bas
   (tab bar telephone) est accrochee en bas : lui imposer top:0 l etirait sur toute
   la hauteur de l ecran et elle recouvrait la page entiere, plus rien n etait cliquable. */
body.has-dev-banner .app-nav, body.has-dev-banner nav:not(.app-tabbar), body.has-dev-banner .rd-progress { top: 0 !important; }


/* ─── Lecteur radio (pied de page global) ────────────────────────────────── */
.rmb{--rmb-accent:#2563eb;box-sizing:border-box;width:100%;margin:0 0 1.25rem;padding:.55rem .6rem;border:1px solid var(--separator);border-radius:18px;background:var(--bg-secondary);box-shadow:0 6px 24px rgba(15,37,68,.07)}
.rmb[hidden]{display:none}
.rmb-bar{display:flex;align-items:center;gap:.55rem;min-width:0}
.rmb-art{position:relative;flex:0 0 auto;width:46px;height:46px;border-radius:12px;overflow:hidden;display:block}
.rmb-cover{width:100%;height:100%;object-fit:cover;display:block}
.rmb-ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:.85rem;letter-spacing:.02em;background:#5e7fa8}
.rmb-ph[hidden]{display:none}
.rmb-now{flex:1 1 auto;min-width:0;padding-left:.15rem}
.rmb-now b{display:block;font-size:.9rem;font-weight:700;line-height:1.2;color:var(--label-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-now small{display:block;color:var(--label-secondary);font-size:.76rem;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb.buf .rmb-now small{opacity:.6}

.rmb-ctrls{display:flex;align-items:center;gap:.15rem;flex:0 0 auto}
.rmb-btn{display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-secondary);cursor:pointer;padding:0}
.rmb-btn svg{width:18px;height:18px}
.rmb-btn-nav{width:34px;height:34px}
.rmb-btn-nav:hover{background:rgba(37,99,235,.1);color:var(--rmb-accent)}
.rmb-btn-main{width:42px;height:42px;background:var(--rmb-accent);color:#fff;box-shadow:0 3px 10px rgba(37,99,235,.28)}
.rmb-btn-main svg{width:20px;height:20px}
.rmb-btn-main:hover{filter:brightness(1.06)}

.rmb-fav{flex:0 0 auto;position:relative;width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-tertiary,#9aa8bd);cursor:pointer;padding:0}
.rmb-fav svg{width:18px;height:18px}
/* Même règle qu'ailleurs : l'étoile reste petite, la zone touchée fait 44×44.
   L'écart de .55rem entre les boutons suffit, aucun voisin n'est mordu. */
.rmb-fav::after{content:"";position:absolute;inset:-5px}
.rmb-fav:hover{background:rgba(37,99,235,.1)}
.rmb-fav.on{color:#e0a107}
.rmb-fav.on svg{fill:currentColor}
.rmb-fav:disabled{opacity:.35;cursor:default}

.rmb-volwrap{display:flex;align-items:center;gap:.3rem;flex:0 1 auto;min-width:0}
.rmb-vol{flex:0 1 90px;min-width:60px;accent-color:var(--rmb-accent);cursor:pointer}
.rmb-icbtn{flex:0 0 auto;height:34px;min-width:34px;display:inline-flex;align-items:center;justify-content:center;gap:.35rem;padding:0 .5rem;border:0;border-radius:10px;background:transparent;color:var(--label-secondary);cursor:pointer;font:inherit;font-size:.78rem;font-weight:600}
.rmb-icbtn svg{width:17px;height:17px;flex:0 0 auto}
.rmb-icbtn:hover{background:rgba(37,99,235,.1);color:var(--rmb-accent)}
.rmb-icbtn.on{background:var(--rmb-accent);color:#fff}
.rmb-stations .rmb-lb{white-space:nowrap}

/* Panneau stations : recherche + favoris épinglés + bibliothèque */
.rmb-panel{margin-top:.55rem;padding-top:.55rem;border-top:1px solid var(--separator)}
.rmb-panel[hidden]{display:none}
.rmb-searchrow{position:relative;display:flex;align-items:center}
.rmb-search-ico{position:absolute;left:.6rem;display:inline-flex;color:var(--label-tertiary,#9aa8bd);pointer-events:none}
.rmb-search-ico svg{width:16px;height:16px}
.rmb-search{width:100%;box-sizing:border-box;padding:.5rem .7rem .5rem 2.1rem;border:1px solid var(--separator);border-radius:12px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.85rem}
.rmb-search:focus{outline:none;border-color:var(--rmb-accent);box-shadow:0 0 0 3px rgba(37,99,235,.14)}

/* Pastilles de filtre du lecteur : une seule rangee, qui defile si elle deborde.
   Le compte a cote du libelle evite d'ouvrir un filtre pour decouvrir qu'il est vide. */
/* Proposition apres trois echecs de reconnexion : discrete, mais atteignable. */
.rmb-suivante{display:inline-block;margin-left:.15rem;padding:0 .35rem;border:0;background:transparent;
  color:var(--rmb-accent,#2563eb);font:inherit;font-size:inherit;font-weight:600;
  text-decoration:underline;cursor:pointer}
.rmb-suivante:hover{opacity:.8}

.rmb-chips{display:flex;gap:.3rem;margin-top:.5rem;overflow-x:auto;overflow-y:hidden;padding-bottom:.2rem;scrollbar-width:thin}
.rmb-chips::-webkit-scrollbar{height:4px}
.rmb-chips::-webkit-scrollbar-thumb{background:rgba(0,0,0,.18);border-radius:99px}
.rmb-chip-f{flex:0 0 auto;display:inline-flex;align-items:center;gap:.3rem;
  border:1px solid var(--separator,#e3e6ec);background:transparent;color:inherit;
  border-radius:999px;padding:.24rem .6rem;font-size:.76rem;font-weight:600;
  cursor:pointer;white-space:nowrap;line-height:1.3}
.rmb-chip-f:hover{background:rgba(37,99,235,.07)}
.rmb-chip-f.on{background:var(--rmb-accent,#2563eb);border-color:var(--rmb-accent,#2563eb);color:#fff}
.rmb-chip-n{font-size:.68rem;font-weight:500;opacity:.62}
.rmb-chip-f.on .rmb-chip-n{opacity:.8}
@media (max-width:640px){.rmb-chip-f{font-size:.8rem;padding:.3rem .65rem}}

.rmb-favrow{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;margin-top:.5rem}
.rmb-favrow[hidden]{display:none}
.rmb-favlab{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--label-tertiary,#9aa8bd);margin-right:.15rem}
.rmb-chip{padding:.25rem .6rem;border:1px solid var(--separator);border-radius:999px;background:var(--bg-primary);color:var(--label-primary);font:inherit;font-size:.76rem;font-weight:600;cursor:pointer;white-space:nowrap}
.rmb-chip:hover{border-color:var(--rmb-accent);color:var(--rmb-accent)}

.rmb-list{margin-top:.5rem;max-height:236px;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:2px}
.rmb-row{display:flex;align-items:center;gap:.2rem;border-radius:10px;min-width:0}
.rmb-row:hover{background:rgba(37,99,235,.07)}
.rmb-row.on{background:rgba(37,99,235,.12)}
.rmb-rowmain{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:.5rem;padding:.35rem .4rem;border:0;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
.rmb-rowph{flex:0 0 auto;width:26px;height:26px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:#fff;font-size:.63rem;font-weight:800}
.rmb-rowtx{min-width:0;display:block}
.rmb-rowtx b{display:block;font-size:.8rem;font-weight:600;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-rowtx em{display:block;font-style:normal;font-size:.7rem;color:var(--label-tertiary,#9aa8bd);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-row.on .rmb-rowtx b{color:var(--rmb-accent)}
.rmb-rowfav{flex:0 0 auto;width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-tertiary,#9aa8bd);cursor:pointer;padding:0}
.rmb-rowfav svg{width:14px;height:14px}
.rmb-rowfav[aria-pressed="true"]{color:#e0a107}
.rmb-rowfav[aria-pressed="true"] svg{fill:currentColor}
.rmb-empty{margin:.6rem 0 .2rem;text-align:center;font-size:.8rem;color:var(--label-secondary)}
.rmb-empty[hidden]{display:none}

/* Mobile : deux lignes nettes — station + transport, puis outils. */
@media (max-width:640px){
  .rmb-bar{flex-wrap:wrap;row-gap:.45rem}
  .rmb-art{order:0;width:40px;height:40px}
  .rmb-now{order:1;flex:1 1 0}
  .rmb-ctrls{order:2}
  .rmb-fav{order:3}
  .rmb-volwrap{order:4;flex:1 1 auto;min-width:110px}
  .rmb-vol{flex:1 1 auto;min-width:52px}
  .rmb-stations{order:5;margin-left:auto}
  .rmb-more{order:6}
  .rmb-stations .rmb-lb{display:none}
  .rmb-list{grid-template-columns:1fr;max-height:210px}
}

/* ─── Bloc compact du lecteur dans la barre latérale ──────────────────────
   Lecture/pause + station en cours + coupure du son + volume, à côté de la
   recherche et de la déconnexion. Toujours à portée, sur toutes les pages. */

/* ── Fenêtre plein écran « lecteur complet » (/musique) ─────────────────────── */
.rmb-modal{position:fixed;inset:0;z-index:1200;display:flex;align-items:stretch;justify-content:center;background:rgba(8,18,33,.55)}
.rmb-modal[hidden]{display:none}
/* Fenetre rangee : invisible et hors d'atteinte, mais TOUJOURS affichee — un
   element retire de l'affichage peut voir son media suspendu, et fermer la
   fenetre ne doit pas couper la musique. */
.rmb-modal-rangee{visibility:hidden;opacity:0;pointer-events:none}
.rmb-modal-sheet{position:relative;width:100%;max-width:920px;margin:auto;height:100%;max-height:100%;background:var(--bg-primary,#f4f6f9);overflow:auto;box-shadow:0 12px 50px rgba(0,0,0,.35);-webkit-overflow-scrolling:touch}
.rmb-modal-close{position:sticky;top:0;z-index:2;display:block;margin:.5rem .5rem -1.6rem auto;width:40px;height:40px;border:0;border-radius:50%;background:var(--bg-secondary,#fff);color:var(--label-primary,#0f2544);font-size:1.5rem;line-height:1;cursor:pointer;box-shadow:0 2px 12px rgba(15,37,68,.18)}
.rmb-modal-body{padding:0 1rem 1.5rem}
.rmb-modal-loading{padding:3rem 1rem;text-align:center;color:var(--label-secondary,#7d94b5)}
body.rmb-modal-open{overflow:hidden}
@media (min-width:640px){
  .rmb-modal{padding:2.5vh 1rem}
  .rmb-modal-sheet{height:auto;max-height:95vh;border-radius:20px}
}


/* ─── Lecteur : égaliseur, arrêt programmé, mode compact ────────────────────
   Trois ajouts nés du même usage : une radio d'ambiance dans un local ouvert
   toute la journée. */

/* L'égaliseur vit dans le coin de la pochette : il ne coûte aucune place à lui
   seul, et c'est la seule façon de voir que ça joue sans monter le son. */
.rmb-eq{position:absolute;right:3px;bottom:3px;display:none;align-items:flex-end;gap:1.5px;height:11px;padding:1.5px 2px;border-radius:3px;background:rgba(0,0,0,.42)}
.rmb-joue .rmb-eq{display:flex}
.rmb-eq i{display:block;width:2px;height:3px;border-radius:1px;background:#fff;transform-origin:bottom;animation:rmb-eq-danse .9s ease-in-out infinite}
.rmb-eq i:nth-child(2){animation-duration:.66s;animation-delay:.14s}
.rmb-eq i:nth-child(3){animation-duration:1.08s;animation-delay:.3s}
@keyframes rmb-eq-danse{0%,100%{height:3px}50%{height:9px}}

/* L'arrêt programmé affiche ce qu'il reste, en minutes. Chiffres alignés : le
   compte à rebours ne doit pas faire danser la barre. */
.rmb-veille .rmb-lb{font-variant-numeric:tabular-nums;white-space:nowrap}

/* Mode compact : on garde de quoi reconnaître et arrêter, on retire le reste.
   Ce n'est pas un masquage cosmétique — les commandes retirées restent
   accessibles au clavier et dans le panneau. */
.rmb-replie{padding:.35rem .5rem}
.rmb-replie .rmb-art{width:32px;height:32px;border-radius:9px}
.rmb-replie .rmb-now small,
.rmb-replie .rmb-btn-nav,
.rmb-replie .rmb-fav,
.rmb-replie .rmb-volwrap,
.rmb-replie .rmb-veille,
.rmb-replie .rmb-more{display:none}
.rmb-replie .rmb-btn-main{width:34px;height:34px}
.rmb-replie .rmb-btn-main svg{width:16px;height:16px}
.rmb-replie .rmb-stations .rmb-lb{display:none}

/* Les raccourcis, écrits là où on ouvre le lecteur : un raccourci que personne
   ne connaît ne sert à rien. */
.rmb-aide{margin:.6rem 0 .1rem;color:var(--label-tertiary,#9aa8bd);font-size:.72rem;line-height:1.7}
.rmb-aide kbd{display:inline-block;min-width:1.1em;padding:.05em .35em;border:1px solid var(--separator);border-bottom-width:2px;border-radius:4px;background:var(--bg-primary);color:var(--label-secondary);font:inherit;font-size:.9em;text-align:center}

/* Le panneau de stations s'ouvre au lieu d'apparaître. */
@media (prefers-reduced-motion: no-preference){
  .rmb-panel:not([hidden]){animation:rmb-ouvre .18s ease-out}
  @keyframes rmb-ouvre{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
}

@media (prefers-reduced-motion: reduce){
  .rmb-eq i{animation:none;height:6px}
}


/* ─── Le quai : le lecteur d'un service, range en bas de page ────────────────
   Spotify, Deezer et Tidal ne se laissent pas commander de l'exterieur. Leur
   lecteur vient donc se ranger tel quel, avec LEURS boutons. Le cadre ne bouge
   pas dans la page — le deplacer le rechargerait — c'est la fenetre qui change
   de forme autour de lui. */
/* Le coin bas-droit est deja pris par le bouton de l assistant : la bande se pose
   au-dessus de lui plutot que de se faire recouvrir. */
.rmb-modal-quai{position:fixed;inset:auto 0 0 auto;display:block;background:transparent;
  z-index:1150;pointer-events:none;padding:0 .75rem 5.25rem 0}
.rmb-modal-quai .rmb-modal-sheet{pointer-events:auto;width:min(460px,calc(100vw - 1.5rem));
  max-width:460px;height:auto;max-height:none;margin:0 0 0 auto;border-radius:16px;
  overflow:hidden;box-shadow:0 10px 40px rgba(8,18,33,.28)}
.rmb-modal-quai .rmb-modal-body{padding:0}

/* Tout ce qui sert a CHOISIR disparait : au quai, on ecoute, on ne choisit plus. */
.rmb-modal-quai .mz-top,
.rmb-modal-quai .mz-tabs,
.rmb-modal-quai .mz-input,
.rmb-modal-quai .mz-results,
.rmb-modal-quai .mz-hint,
.rmb-modal-quai .mz-quai{display:none}

/* Seul le panneau du service choisi reste. */
.rmb-modal-quai .mz-panel{display:none}
.rmb-modal-quai[data-quai=spotify] .mz-panel[data-panel=spotify],
.rmb-modal-quai[data-quai=deezer]  .mz-panel[data-panel=deezer],
.rmb-modal-quai[data-quai=tidal]   .mz-panel[data-panel=tidal],
.rmb-modal-quai[data-quai=youtube] .mz-panel[data-panel=youtube]{display:block}

/* Les integrations s'adaptent a la hauteur qu'on leur laisse : on demande leur
   forme compacte, sans toucher a leur adresse — la changer les rechargerait. */
.rmb-modal-quai .mz-frame,
.rmb-modal-quai .mz-frame--spotify{height:152px;border:0;display:block;width:100%}
.rmb-modal-quai[data-quai=deezer] .mz-frame{height:96px}

/* La croix reste, et elle ARRETE : elle ne range pas. */
.rmb-modal-quai .rmb-modal-close{position:absolute;top:.35rem;right:.35rem;margin:0;
  width:28px;height:28px;font-size:1.05rem;z-index:3}

/* La barre du bas quand elle pilote un service plutot qu'une radio. */
.rmb-service .rmb-fav{opacity:.3}
/* Sur un service qu'on ne commande pas, nos fleches et notre volume n'agiraient
   sur rien : ils sont retires, pas grises pour faire joli. */
.rmb-non-pilotable .rmb-btn-nav,
.rmb-non-pilotable .rmb-volwrap,
.rmb-non-pilotable .rmb-fav{display:none}

@media (max-width:640px){
  .rmb-modal-quai{inset:auto 0 0 0;padding:0 .5rem 5rem}
  .rmb-modal-quai .rmb-modal-sheet{width:100%;max-width:none}
}


/* ─── L'assistant flotte au-dessus de tout ──────────────────────────────────
   Consequence : rien ne doit se retrouver SOUS lui. Sur telephone, le pied des
   pop-up est justement la ou il se pose — on lui reserve la place plutot que de
   faire redescendre le bouton. */
@media (max-width: 640px) {
  body.app-modal-ouverte .app-modal-footer { padding-bottom: calc(20px + 56px + env(safe-area-inset-bottom)); }
}


/* ─── Le lecteur au quotidien ────────────────────────────────────────────────
   La barre vit dans le pied de page : descendre dans un planning la faisait
   perdre. Elle se colle en bas PENDANT l'ecoute seulement — fixe en permanence,
   elle mangerait de la place pour rien. */
.rmb-collee{
  position:fixed;
  left:calc(var(--nav-w, 252px) + 1rem); right:1rem; bottom:.75rem;
  width:auto; margin:0;
  z-index:900;
  background:var(--bg-elevated,#fff);
  box-shadow:0 10px 34px rgba(15,37,68,.16);
}
/* Le contenu laisse la place a la barre, sinon le pied de page passe dessous. */
body.rmb-barre-collee{padding-bottom:96px}
/* L'assistant flotte au-dessus de tout : on le REMONTE plutot que de le faire
   passer derriere. */
body.rmb-barre-collee .ai-launcher{bottom:calc(96px + env(safe-area-inset-bottom))}

@media (max-width:900px){
  .rmb-collee{left:.5rem;right:.5rem;bottom:.5rem}
}

/* Le silence d'urgence : plus large qu'une icone, parce qu'on le cherche vite. */
.rmb-silence{
  flex:0 0 auto;padding:.4rem .8rem;border:1px solid var(--separator);border-radius:999px;
  background:transparent;color:var(--label-secondary);font:inherit;font-size:.8rem;
  font-weight:650;cursor:pointer;white-space:nowrap;
  transition:background-color .15s ease,color .15s ease,border-color .15s ease;
}
.rmb-silence:hover{background:var(--fill-quaternary,rgba(128,128,128,.09))}
.rmb-silence:focus-visible{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-silence.on{background:var(--rmb-accent);border-color:transparent;color:#fff}
.rmb-replie .rmb-silence{display:none}

/* Le coeur du titre en cours — distinct de l'etoile, qui vise la STATION. */
.rmb-aime.on{color:#e0245e}
.rmb-aime.on svg{fill:currentColor}

/* Les trois vues du panneau : stations, historique, programmation. */
.rmb-vues{display:flex;gap:.25rem;margin:.5rem 0 0}
.rmb-vue{
  appearance:none;border:0;background:transparent;color:var(--label-secondary);
  font:inherit;font-size:.78rem;font-weight:650;padding:.3rem .6rem;border-radius:8px;cursor:pointer;
}
.rmb-vue:hover{background:var(--fill-quaternary,rgba(128,128,128,.09))}
.rmb-vue:focus-visible{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-vue.is-actif{color:var(--label-primary);background:var(--fill-tertiary,rgba(128,128,128,.14))}

/* L'historique : une ligne = un titre, son coeur, sa station et son heure. */
.rmb-histo{margin-top:.5rem;max-height:236px;overflow-y:auto}
.rmb-histo-l{display:flex;align-items:center;gap:.4rem;padding:.3rem .1rem;border-bottom:1px solid var(--separator)}
.rmb-histo-l:last-child{border-bottom:0}
.rmb-histo-t{min-width:0}
.rmb-histo-t b{display:block;font-size:.84rem;font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-histo-t small{display:block;color:var(--label-tertiary,#9aa8bd);font-size:.74rem}

/* La programmation de la journee. */
.rmb-prog{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.5rem .8rem;margin-top:.6rem}
/* Un display explicite l emporte sur l attribut hidden : sans cette ligne, la
   programmation reste affichee sous la liste des stations. */
.rmb-prog[hidden]{display:none}
.rmb-prog-l{display:flex;align-items:center;gap:.4rem;font-size:.8rem;color:var(--label-secondary)}
.rmb-prog-l span{flex:0 0 auto}
.rmb-prog-h,.rmb-prog-s{
  flex:1 1 auto;min-width:0;padding:.32rem .5rem;border:1px solid var(--separator);
  border-radius:8px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.8rem;
}
.rmb-prog-note{grid-column:1/-1;margin:.1rem 0 0;color:var(--label-tertiary,#9aa8bd);font-size:.74rem;line-height:1.5}

/* La recherche qui continue ailleurs, quand aucune station ne correspond. */
.rmb-ailleurs{margin:.5rem 0 0}
.rmb-ailleurs-b{
  width:100%;padding:.5rem .7rem;border:1px dashed var(--separator);border-radius:10px;
  background:transparent;color:var(--rmb-accent);font:inherit;font-size:.82rem;font-weight:650;cursor:pointer;
}
.rmb-ailleurs-b:hover{background:rgba(37,99,235,.07)}

/* Le depot d'une station sur les favoris. */
.rmb-favrow.rmb-depot{outline:2px dashed var(--rmb-accent);outline-offset:3px;border-radius:8px}

@media (prefers-reduced-motion:reduce){.rmb-silence{transition:none}}

/* ─── Le lecteur ecoute l'etablissement ──────────────────────────────────────
   Ce que l'equipe met, et les annonces qui passent par-dessus la musique. */
.rmb-equipe{display:flex;flex-wrap:wrap;align-items:center;gap:.3rem;margin:.5rem 0 0}
.rmb-equipe[hidden]{display:none}
.rmb-equipe-t{color:var(--label-tertiary,#9aa8bd);font-size:.74rem;font-weight:650;margin-right:.2rem}
.rmb-equipe-b{
  padding:.25rem .6rem;border:1px solid var(--separator);border-radius:999px;
  background:transparent;color:var(--label-secondary);font:inherit;font-size:.76rem;
  font-weight:600;cursor:pointer;
}
.rmb-equipe-b:hover{background:var(--fill-quaternary,rgba(128,128,128,.09));color:var(--rmb-accent)}

.rmb-annonce-f{display:flex;gap:.4rem;margin:.6rem 0 0}
.rmb-annonce-f[hidden]{display:none}
.rmb-annonce-t{
  flex:1 1 auto;min-width:0;padding:.4rem .7rem;border:1px solid var(--separator);
  border-radius:999px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.8rem;
}
.rmb-annonce-b{
  flex:0 0 auto;padding:.4rem .9rem;border:0;border-radius:999px;
  background:var(--rmb-accent);color:#fff;font:inherit;font-size:.8rem;font-weight:650;cursor:pointer;
}

/* Pendant une annonce, la barre le montre : on doit comprendre pourquoi le son a baisse. */
.rmb-annonce{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-annonce .rmb-now small{color:var(--rmb-accent);font-weight:650}
