@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800&family=Merriweather:wght@300;400;700;900&display=swap");

:root {
  --card: #ffffff;
  --ring: #ff7e5f;
  --input: #ffe0d6;
  --muted: #fff0eb;
  --accent: #feb47b;
  --border: #ffe0d6;
  --radius: 0.625rem;
  --chart-1: #ff7e5f;
  --chart-2: #feb47b;
  --chart-3: #ffcaa7;
  --chart-4: #ffad8f;
  --chart-5: #ce6a57;
  --popover: #ffffff;
  --primary: #ff7e5f;
  /* Variante « encre » : la même teinte, assombrie juste assez pour atteindre
     4.5:1 sur les fonds clairs. La couleur vive reste réservée aux aplats —
     en texte elle ne dépassait pas 2.5:1, donc illisible pour beaucoup. */
  --primary-ink: #ab5440;
  --sidebar: #fff0eb;
  --font-mono: "Ubuntu Mono", monospace;
  --font-sans: "Montserrat", sans-serif;
  --secondary: #ffedea;
  --background: #fff9f5;
  --font-serif: "Merriweather", serif;
  --foreground: #3d3436;
  --destructive: #e63946;
  --destructive-ink: #ca323e;
  --shadow-blur: 12px;
  --shadow-color: hsl(0 0% 0%);
  --sidebar-ring: #ff7e5f;
  --shadow-spread: -3px;
  --shadow-opacity: 0.09;
  --sidebar-accent: #feb47b;
  --sidebar-border: #ffe0d6;
  --card-foreground: #3d3436;
  --shadow-offset-x: 0px;
  --shadow-offset-y: 6px;
  --sidebar-primary: #ff7e5f;
  --muted-foreground: #746E69;
  --accent-foreground: #3d3436;
  --popover-foreground: #3d3436;
  --primary-foreground: #ffffff;
  --sidebar-foreground: #3d3436;
  --secondary-foreground: #9A4A33;
  --destructive-foreground: #ffffff;
  --sidebar-accent-foreground: #3d3436;
  --sidebar-primary-foreground: #ffffff;

  --success: #2f9e64;
  --success-ink: #257d4f;
  --success-foreground: #ffffff;
  --warning: #f2a541;

  /* concentric radius scale: card = 20, button/input = 12, chip = 8 */
  --r-xl: 1.75rem;
  --r-lg: 1.125rem;
  --r-md: 0.75rem;
  --r-sm: 0.5rem;

  --shadow-sm: 0 1px 2px rgba(61, 52, 54, 0.06);
  --shadow-md: 0 6px 16px -6px rgba(61, 52, 54, 0.14), 0 2px 6px -2px rgba(61, 52, 54, 0.08);
  --shadow-lg: 0 20px 45px -15px rgba(206, 106, 87, 0.35), 0 6px 16px -6px rgba(61, 52, 54, 0.1);
  --shadow-glow: 0 8px 30px -6px rgba(255, 126, 95, 0.45);

  --ease-out: cubic-bezier(0.2, 0, 0, 1);
  --ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
}

.dark {
  --card: #392f35;
  --ring: #ff7e5f;
  --input: #463a41;
  --muted: #30272c;
  --accent: #feb47b;
  --border: #463a41;
  --popover: #392f35;
  --primary: #ff7e5f;
  --primary-ink: #ff8467;
  --success-ink: #67b88e;
  --sidebar: #2a2024;
  --secondary: #463a41;
  --background: #2a2024;
  --foreground: #f2e9e4;
  --destructive: #e63946;
  --destructive-ink: #f08a92;
  --sidebar-ring: #ff7e5f;
  --sidebar-accent: #feb47b;
  --sidebar-border: #463a41;
  --card-foreground: #f2e9e4;
  --sidebar-primary: #ff7e5f;
  --muted-foreground: #d7c6bc;
  --accent-foreground: #2a2024;
  --popover-foreground: #f2e9e4;
  --primary-foreground: #ffffff;
  --sidebar-foreground: #f2e9e4;
  --secondary-foreground: #f2e9e4;
  --destructive-foreground: #ffffff;
  --sidebar-accent-foreground: #2a2024;
  --sidebar-primary-foreground: #ffffff;
  --shadow-lg: 0 20px 45px -15px rgba(0, 0, 0, 0.55), 0 6px 16px -6px rgba(0, 0, 0, 0.4);
}

* { box-sizing: border-box; }
/* overflow-x: clip guards against accidental horizontal scroll on mobile
   without creating a scroll container (so position: sticky keeps working). */
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; overflow-x: clip; }
body { overflow-x: clip; }

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--background);
  color: var(--foreground);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 1.5;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  text-wrap: balance;
  margin: 0;
  color: var(--foreground);
}
p { text-wrap: pretty; }

.tabular { font-variant-numeric: tabular-nums; }

::selection { background: var(--accent); color: var(--accent-foreground); }

:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ---------- Layout helpers ---------- */
.container-xl { max-width: 1240px; margin-inline: auto; padding-inline: 1.25rem; }
.section { padding-block: clamp(3rem, 6vw, 6rem); }
.section-head { max-width: 640px; }
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--secondary-foreground);
  background: var(--secondary);
  padding: .35rem .8rem;
  border-radius: 999px;
}
.eyebrow::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  height: 3rem;
  padding: 0 1.5rem;
  border-radius: var(--r-md);
  font-weight: 600;
  font-size: .95rem;
  border: none;
  cursor: pointer;
  transition: transform .15s var(--ease-out), box-shadow .2s var(--ease-out), background-color .2s var(--ease-out);
  white-space: nowrap;
  min-height: 44px;
}
.btn:active { transform: scale(.96); }
.btn-primary {
  background: linear-gradient(135deg, var(--primary), var(--accent));
  color: var(--primary-foreground);
  box-shadow: var(--shadow-glow);
}
.btn-primary:hover { box-shadow: 0 12px 34px -8px rgba(255,126,95,.55); }
.btn-secondary {
  background: var(--card);
  color: var(--foreground);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}
.btn-secondary:hover { border-color: var(--primary); color: var(--primary-ink); }
.btn-dark {
  background: var(--foreground);
  color: var(--background);
}
.btn-ghost {
  background: transparent;
  color: var(--foreground);
}
.btn-ghost:hover { background: var(--muted); }
.btn-sm { height: 2.5rem; padding: 0 1.1rem; font-size: .85rem; border-radius: var(--r-sm); }
.btn-block { width: 100%; }
.btn-icon { width: 44px; height: 44px; padding: 0; border-radius: var(--r-md); }

/* ---------- Cards ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
}
.card-pad { padding: 1.5rem; }

/* ---------- Chips / badges ---------- */
.chip {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .8rem;
  font-weight: 600;
  padding: .4rem .75rem;
  border-radius: var(--r-sm);
  background: var(--muted);
  color: var(--foreground);
  border: 1px solid var(--border);
}
.chip-solid {
  background: var(--secondary);
  color: var(--secondary-foreground);
  border: none;
}

/* ---------- Inputs ---------- */
.field { display: flex; flex-direction: column; gap: .4rem; text-align: left; }
.field label {
  font-size: .82rem;
  font-weight: 600;
  color: var(--foreground);
}
.hint { font-size: .78rem; color: var(--muted-foreground); }
.input, select.input, textarea.input {
  width: 100%;
  height: 2.9rem;
  padding: 0 1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: .95rem;
  transition: border-color .15s var(--ease-out), box-shadow .15s var(--ease-out);
  min-height: 44px;
}
textarea.input { height: auto; padding-block: .8rem; resize: vertical; min-height: 100px; }
.input::placeholder { color: #b9aca6; }
.input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 4px rgba(255,126,95,.15);
}
.input-icon-wrap { position: relative; }
.input-icon-wrap .input { padding-left: 2.75rem; }
.input-icon-wrap .icon {
  position: absolute;
  left: .9rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--muted-foreground);
  display: flex;
}
.check-row { display: flex; align-items: center; gap: .55rem; font-size: .85rem; color: var(--muted-foreground); }
.check-row input { width: 18px; height: 18px; accent-color: var(--primary); }

/* ---------- Header / Nav ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 249, 245, .85);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.dark .site-header { background: rgba(42, 32, 36, .85); }
.nav-row { display: flex; align-items: center; justify-content: space-between; gap: 2rem; height: 4.5rem; }
.brand { display: flex; align-items: center; gap: .6rem; font-family: var(--font-serif); font-weight: 900; font-size: 1.2rem; }
/* La marque était un carré peint en CSS avec la lettre « E » posée dessus.
   C'est maintenant le vrai logo : plus rien à peindre derrière, l'image porte
   son fond, son dégradé et ses coins arrondis.

   L'ombre passe de `box-shadow` à `drop-shadow` : la première suit la boîte
   rectangulaire et déborderait des coins arrondis transparents du logo, la
   seconde épouse la forme réelle du dessin. */
.brand-mark {
  width: 38px; height: 38px; flex: none;
  object-fit: contain;
  filter: drop-shadow(0 6px 16px rgba(248, 54, 0, .34));
}
.nav-links { display: flex; align-items: center; gap: 2rem; }
.nav-links a {
  font-size: .92rem; font-weight: 600; color: var(--foreground); opacity: .75;
  position: relative; padding-block: .3rem;
  transition: opacity .15s var(--ease-out);
}
.nav-links a:hover { opacity: 1; }
.nav-links a.active { opacity: 1; }
.nav-links a.active::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: var(--primary); border-radius: 2px;
}
.nav-actions { display: flex; align-items: center; gap: .75rem; }
.burger { display: none; }

/* ---------- Theme toggle ---------- */
.theme-toggle {
  position: relative;
  flex: none;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--foreground);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color .2s var(--ease-out), color .2s var(--ease-out),
              background-color .2s var(--ease-out), transform .15s var(--ease-out);
}
.theme-toggle:hover { border-color: var(--primary); color: var(--primary-ink); }
.theme-toggle:active { transform: scale(.96); }
.theme-toggle svg {
  position: absolute;
  width: 20px; height: 20px;
  transition: opacity .28s var(--ease-out), transform .3s var(--ease-out), filter .28s var(--ease-out);
}
.theme-toggle .ic-moon { opacity: 0; transform: scale(.25) rotate(-90deg); filter: blur(4px); }
.theme-toggle .ic-sun { opacity: 1; transform: none; filter: blur(0); }
.theme-toggle.is-dark .ic-sun { opacity: 0; transform: scale(.25) rotate(90deg); filter: blur(4px); }
.theme-toggle.is-dark .ic-moon { opacity: 1; transform: none; filter: blur(0); }
.theme-toggle-fixed { position: fixed; top: 1rem; right: 1rem; z-index: 60; box-shadow: var(--shadow-md); }
.bar-actions { display: flex; align-items: center; gap: .75rem; margin-left: auto; }
/* Keep top bars uncrowded on small screens: hand the toggle to the mobile surfaces */
@media (max-width: 920px) { .nav-actions .theme-toggle { display: none; } }
@media (max-width: 900px) { .dash-topbar .theme-toggle { display: none; } }
.mm-theme-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: .35rem; padding: .35rem .65rem;
  font-weight: 600; font-size: .95rem; color: var(--foreground);
}
@media (prefers-reduced-motion: reduce) {
  .theme-toggle svg { transition: opacity .2s linear; transform: none !important; filter: none !important; }
}

@media (max-width: 920px) {
  .nav-links { display: none; }
  .nav-actions .btn-secondary.hide-mobile { display: none; }
  .burger {
    display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; border-radius: var(--r-sm);
    border: 1px solid var(--border); background: var(--card);
  }
}

/* The burger is the only way into the menu on mobile: it must never be
   squeezed or pushed out of the (overflow-clipped) header. */
.burger { flex: 0 0 auto; }
.nav-actions { flex: 0 0 auto; }
.brand { min-width: 0; }

/* On phones the header CTA and the brand together overflow the bar
   (≈417px needed for 388px available on a 428px-wide iPhone Pro Max),
   which clipped the burger. The CTA lives in the mobile menu and the hero,
   so we drop it here and tighten the row instead. */
@media (max-width: 700px) {
  .nav-row { gap: .75rem; }
  .nav-actions .btn-primary { display: none; }
}
@media (max-width: 400px) {
  .brand { font-size: 1.05rem; }
  .brand-mark { width: 30px; height: 30px; }
}

.mobile-menu {
  display: none;
  position: relative;
  flex-direction: column;
  gap: .25rem;
  padding: 1rem 1.25rem 1.5rem;
  /* respect notched phones (home indicator / rounded corners) */
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border);
  background: var(--background);
  /* The menu lives inside the sticky header: cap it to the space left under
     the bar and let it scroll, otherwise the last entries are cut off and
     unreachable on short screens (small phones, landscape). */
  max-height: calc(100vh - 4.5rem);
  max-height: calc(100dvh - 4.5rem);
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.mobile-menu.open { display: flex; }
.mobile-menu a {
  position: relative;
  z-index: 1;
  padding: .8rem .65rem;
  font-weight: 600;
  border-radius: var(--r-md);
  transition: background .18s var(--ease-out), padding-left .18s var(--ease-out);
}
.mobile-menu a:hover { background: var(--muted); padding-left: 1rem; }
.mobile-menu.open a { animation: menuItemIn .45s var(--ease-out) both; }
.mobile-menu.open a:nth-of-type(1) { animation-delay: .05s; }
.mobile-menu.open a:nth-of-type(2) { animation-delay: .10s; }
.mobile-menu.open a:nth-of-type(3) { animation-delay: .15s; }
.mobile-menu.open a:nth-of-type(4) { animation-delay: .20s; }
.mobile-menu.open a:nth-of-type(5) { animation-delay: .25s; }
.mobile-menu.open a:nth-of-type(6) { animation-delay: .30s; }
.mobile-menu.open a:nth-of-type(7) { animation-delay: .35s; }

/* animated background layer (moving gradient + drifting education icons) */
.mobile-menu-fx { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.mobile-menu-fx .fx-blob {
  position: absolute; inset: -45%;
  background:
    radial-gradient(circle at 26% 22%, rgba(255,126,95,.18), transparent 44%),
    radial-gradient(circle at 80% 74%, rgba(254,180,123,.20), transparent 46%);
  animation: fxDrift 14s ease-in-out infinite alternate;
}
.mobile-menu-fx .fx-ic {
  position: absolute; bottom: -28px;
  color: var(--primary-ink); opacity: 0;
  animation: fxFloat linear infinite;
}
.dark .mobile-menu-fx .fx-ic { color: var(--accent); }

@keyframes menuItemIn { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }
@keyframes fxDrift { from { transform: translate(0, 0) scale(1); } to { transform: translate(7%, -6%) scale(1.08); } }
@keyframes fxFloat {
  0% { transform: translateY(0) rotate(0deg); opacity: 0; }
  12% { opacity: .18; }
  85% { opacity: .18; }
  100% { transform: translateY(-320px) rotate(48deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .mobile-menu-fx { display: none; }
  .mobile-menu.open a { animation: none; }
}

/* ---------- Footer ---------- */
.site-footer { background: var(--foreground); color: #f2e9e4; }
/* --foreground flips light in dark mode; keep the footer dark so its light text stays legible */
.dark .site-footer { background: #1d1519; }
.site-footer a { opacity: .75; transition: opacity .15s; }
.site-footer a:hover { opacity: 1; }

/* Social icons — small, placed in the footer (brand column or bottom bar) */
.footer-social { display: flex; flex-wrap: wrap; gap: .5rem; }
.footer-marque .footer-social { margin-top: 1.25rem; }
.site-footer .footer-social a {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.08); color: #f2e9e4; opacity: 1;
  transition: transform .18s var(--ease-out), background-color .2s var(--ease-out);
}
.site-footer .footer-social a:hover { background: rgba(255,255,255,.18); opacity: 1; transform: translateY(-2px); }
.site-footer .footer-social a:active { transform: scale(.94); }
.footer-social svg { width: 18px; height: 18px; }
@media (prefers-reduced-motion: reduce) {
  .site-footer .footer-social a { transition: background-color .2s; }
  .site-footer .footer-social a:hover, .site-footer .footer-social a:active { transform: none; }
}
/* Pied de page réduit à l'essentiel : la marque à gauche, cinq liens à droite.
   Les quatre colonnes précédentes s'empilaient sur téléphone et faisaient un
   écran entier à faire défiler — pour seize liens dont deux ne menaient nulle
   part. */
.footer-min {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  justify-content: space-between; gap: 2rem 3rem;
}
.footer-marque { min-width: 0; max-width: 34ch; }
.footer-accroche { font-size: .88rem; opacity: .7; margin-top: 1rem; }
.footer-liens {
  display: flex; flex-wrap: wrap; gap: .35rem 1.75rem;
  font-size: .92rem; padding-top: .35rem;
}
/* La zone de frappe fait 44 px de haut sans que le texte s'espace d'autant :
   le lien reste sur sa ligne, seul le rembourrage grandit. */
.footer-liens a { display: inline-flex; align-items: center; min-height: 44px; }

@media (max-width: 640px) {
  /* En colonne, les liens gagnent une ligne chacun : au doigt, deux liens
     côte à côte à moins de 44 px d'écart se visent mal. */
  .footer-min { flex-direction: column; gap: 1.5rem; }
  .footer-liens { flex-direction: column; gap: 0; }
}
.footer-bottom {
  border-top: 1px solid rgba(255,255,255,.12);
  margin-top: 2.5rem; padding-top: 1.5rem;
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1rem;
  font-size: .82rem; opacity: .6;
}
/* La barre entière est à 60 % d'opacité : un lien qui hérite de cette valeur
   se lit moins bien qu'un texte ordinaire, alors qu'on doit pouvoir le
   trouver. Il reprend donc son plein contraste, et se souligne au survol. */
.footer-legal {
  color: inherit; opacity: 1; font-weight: 600;
  text-decoration: none; text-underline-offset: 3px;
}
.footer-legal:hover, .footer-legal:focus-visible { text-decoration: underline; }
@media (max-width: 760px) {
}
/* Sous 560 px, deux colonnes tombent à 155 px chacune : les intitulés et les
   liens s'y écrasent. Une seule colonne rend chaque rubrique lisible, et la
   rangée du bas s'empile au lieu de s'éparpiller en `space-between`. */
@media (max-width: 560px) {
  .footer-bottom {
    flex-direction: column; align-items: center; text-align: center;
    gap: 1.25rem;
  }
  .footer-bottom .footer-social { justify-content: center; }
}

/* ---------- Reveal on scroll ---------- */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s var(--ease-out), transform .6s var(--ease-out); }
.reveal.in { opacity: 1; transform: translateY(0); }
.stagger > * { transition-delay: calc(var(--i, 0) * 80ms); }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
}

/* ---------- Tutor card ---------- */
.tutor-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out), border-color .25s;
  display: flex;
  flex-direction: column;
}
.tutor-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: var(--accent);
}
.tutor-card .avatar-wrap {
  position: relative;
  padding: 1.25rem 1.25rem 0;
}
.tutor-card img.avatar {
  width: 100%; aspect-ratio: 4/3; object-fit: cover;
  border-radius: var(--r-lg);
  outline: 1px solid rgba(0,0,0,.1);
}
.dark .tutor-card img.avatar { outline-color: rgba(255,255,255,.1); }
.tutor-card .rate-badge {
  position: absolute; top: 1.75rem; right: 1.75rem;
  background: rgba(61,52,54,.75);
  color: #fff; font-size: .75rem; font-weight: 700;
  padding: .3rem .6rem; border-radius: var(--r-sm);
  backdrop-filter: blur(4px);
}
.tutor-card .body { padding: 1.1rem 1.25rem 1.4rem; display: flex; flex-direction: column; gap: .6rem; flex: 1; }
.tutor-card .name-row { display: flex; align-items: center; justify-content: space-between; }
.tutor-card .name-row h3 { font-family: var(--font-sans); font-weight: 700; font-size: 1.05rem; }
.rating { display: flex; align-items: center; gap: .3rem; font-size: .85rem; font-weight: 700; color: #c98a2e; }
.tutor-card .meta { font-size: .85rem; color: var(--muted-foreground); display: flex; align-items: center; gap: .4rem; }
.tutor-card .subjects { display: flex; flex-wrap: wrap; gap: .4rem; }
.tutor-card .footer-row { margin-top: auto; display: flex; align-items: center; justify-content: space-between; padding-top: .75rem; border-top: 1px dashed var(--border); }
.price { font-family: var(--font-serif); font-weight: 700; color: var(--primary-ink); }
.price small { font-family: var(--font-sans); font-weight: 500; color: var(--muted-foreground); font-size: .72rem; }

/* Le montant se lit de haut en bas : ce qu'il mesure, le chiffre, la période.
   Posée après le chiffre, l'unité arrivait trop tard — on avait déjà lu
   « 22 000 F » comme un tarif horaire. */
.price:has(.price-unit) {
  display: flex; flex-direction: column; align-items: flex-end;
  line-height: 1.15; text-align: right;
}
.price .price-unit {
  font-size: .66rem; text-transform: uppercase; letter-spacing: .04em;
  font-weight: 700; color: var(--muted-foreground);
}
.price .price-per { font-size: .68rem; color: var(--muted-foreground); }
.price .tabular { font-size: 1.05rem; font-variant-numeric: tabular-nums; }

/* ---------- Favoris ---------- */
/* Le cœur vit à l'intérieur d'une carte qui est elle-même un lien : la zone de
   frappe est portée à 44 px par un pseudo-élément, sans agrandir le dessin. */
.btn-coeur {
  position: relative;
  width: 32px; height: 32px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--card); color: var(--muted-foreground);
  font-size: .95rem; line-height: 1; cursor: pointer;
  transition: color .18s ease, border-color .18s ease, background-color .18s ease, scale .12s var(--ease-out);
}
.btn-coeur::after { content: ""; position: absolute; inset: -6px; }
.btn-coeur:hover { color: var(--primary); border-color: var(--primary); }
.btn-coeur:active { scale: .96; }
.btn-coeur.est-favori { color: #fff; background: var(--primary); border-color: var(--primary); }
.btn-coeur:disabled { opacity: .55; cursor: progress; }

/* Le même état sur le bouton texte de la fiche publique. */
.btn.est-favori { color: #fff; background: var(--primary); border-color: var(--primary); }
.btn.est-favori svg { fill: currentColor; }

.fav-card { display: flex; flex-direction: column; }
.fav-card .fav-lien { display: flex; flex-direction: column; flex: 1; color: inherit; }
.fav-card .footer-row {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .75rem 1.25rem 1.1rem;
  border-top: 1px dashed var(--border);
}
.fav-card .avatar-vide {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-size: 2rem; font-weight: 900;
  color: #fff; background: linear-gradient(135deg, var(--primary), var(--accent));
}

@media (prefers-reduced-motion: reduce) {
  .btn-coeur { transition: none; }
  .btn-coeur:active { scale: 1; }
}

/* ---------- Dépôt d'un avis ---------- */
.avis-ligne { padding-block: 1.25rem; border-bottom: 1px solid var(--border); }
.avis-ligne:last-child { border-bottom: none; }
.avis-qui { display: flex; align-items: center; gap: .75rem; }
.avis-qui strong { display: block; font-size: .95rem; }
.avis-photo { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: none; align-self: center; }
.avis-etat { font-size: .78rem; color: var(--muted-foreground); }

.etoile-choix { display: flex; gap: .15rem; margin: .6rem 0; }
.etoile-choix .etoile {
  width: 40px; height: 40px;              /* zone de frappe confortable */
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer;
  font-size: 1.5rem; line-height: 1;
  color: var(--border);
  transition: color .15s ease, scale .1s var(--ease-out);
}
.etoile-choix .etoile.on { color: #e8a13a; }
.etoile-choix .etoile:hover { color: #e8a13a; }
.etoile-choix .etoile:active { scale: .96; }

.avis-mot {
  width: 100%; padding: .6rem .75rem; font: inherit; font-size: .88rem;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--background); color: var(--foreground); resize: vertical;
}
.avis-actions { display: flex; align-items: center; gap: .5rem; margin-top: .6rem; flex-wrap: wrap; }
.avis-retour { font-size: .82rem; color: var(--muted-foreground); }
.avis-retour.ok { color: var(--success-ink); }
.avis-retour.ko { color: var(--destructive-ink); }

/* Un avis masqué reste lisible en modération, mais se voit au premier coup d'œil. */
tr.avis-masque { opacity: .55; }
tr.avis-masque .avis-texte { text-decoration: line-through; }

@media (prefers-reduced-motion: reduce) {
  .etoile-choix .etoile { transition: none; }
  .etoile-choix .etoile:active { scale: 1; }
}

/* ---------- Steps ---------- */
.step {
  display: flex; gap: 1rem; align-items: flex-start;
}
.step-num {
  flex: none;
  width: 3rem; height: 3rem;
  border-radius: var(--r-md);
  background: var(--card);
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-weight: 900; font-size: 1.15rem; color: var(--primary-ink);
  box-shadow: var(--shadow-sm);
}

/* ---------- FAQ ---------- */
.faq-item { border-bottom: 1px solid var(--border); }
.faq-q {
  width: 100%; text-align: left; background: none; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.25rem 0; font-weight: 700; font-size: 1rem; color: var(--foreground);
  min-height: 44px;
}
.faq-q .plus { transition: transform .3s var(--ease-out); flex: none; color: var(--primary-ink); }
.faq-item.open .faq-q .plus { transform: rotate(135deg); }
.faq-a {
  max-height: 0; overflow: hidden; transition: max-height .35s var(--ease-out), opacity .25s;
  color: var(--muted-foreground); font-size: .92rem; opacity: 0;
}
.faq-item.open .faq-a { opacity: 1; padding-bottom: 1.25rem; }

/* ---------- Page banner (photo header) ---------- */
.page-banner {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  padding: clamp(2.25rem, 5vw, 3.5rem) clamp(1.5rem, 4vw, 3rem);
  min-height: 200px;
  display: flex;
  align-items: flex-end;
}
.page-banner img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.page-banner .scrim {
  position: absolute; inset: 0;
  background: linear-gradient(100deg, rgba(61,52,54,.82) 0%, rgba(61,52,54,.55) 55%, rgba(61,52,54,.25) 100%);
}
.page-banner .banner-content { position: relative; z-index: 1; max-width: 60ch; }
.page-banner .eyebrow { background: rgba(255,255,255,.16); color: #fff; }
.page-banner .eyebrow::before { background: var(--accent); }
.page-banner h1 { color: #fff; font-size: clamp(1.6rem, 3vw, 2.2rem); margin-top: .75rem; }
.page-banner p { color: rgba(255,255,255,.85); margin-top: .6rem; }

/* ---------- Auth pages ---------- */
.auth-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr 1fr;
}
@media (max-width: 940px) {
  .auth-shell { grid-template-columns: 1fr; }
  .auth-visual { display: none; }
}
.auth-visual {
  position: relative;
  background: linear-gradient(155deg, #ffb37a 0%, var(--primary) 55%, #d95d3f 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.auth-visual::before, .auth-visual::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
}
.auth-visual::before { width: 320px; height: 320px; top: -80px; left: -100px; }
.auth-visual::after { width: 220px; height: 220px; bottom: -60px; right: -60px; background: rgba(61,52,54,.12); }
.auth-form-side {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.5rem;
}
.auth-card { width: 100%; max-width: 400px; }
.auth-tabs {
  display: flex;
  padding: .3rem;
  background: var(--muted);
  border-radius: var(--r-lg);
  margin-bottom: 2rem;
  position: relative;
}
.auth-tabs button {
  flex: 1; position: relative; z-index: 1;
  padding: .7rem 0; background: none; border: none; cursor: pointer;
  font-weight: 700; font-size: .9rem; color: var(--muted-foreground);
  border-radius: var(--r-md);
  transition: color .25s var(--ease-out);
  min-height: 44px;
}
.auth-tabs button.active { color: var(--primary-foreground); }
.auth-tabs .slider {
  position: absolute; top: .3rem; left: .3rem;
  width: calc(50% - .3rem); height: calc(100% - .6rem);
  background: linear-gradient(135deg, var(--primary), var(--accent));
  border-radius: var(--r-md);
  box-shadow: var(--shadow-glow);
  transition: transform .35s var(--ease-out);
}
.auth-tabs button:nth-child(2).active ~ .slider,
.auth-tabs.tab-2 .slider { transform: translateX(100%); }

.auth-panel { display: none; }
.auth-panel.active { display: block; animation: fadeUp .4s var(--ease-out); }
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px);} to { opacity: 1; transform: translateY(0);} }

.social-row { display: flex; gap: .75rem; margin-top: 1.25rem; }
.social-btn {
  flex: 1; height: 2.9rem; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--card);
  display: flex; align-items: center; justify-content: center; gap: .5rem;
  font-weight: 600; font-size: .85rem; cursor: pointer;
  transition: border-color .2s, transform .15s;
}
.social-btn:hover { border-color: var(--primary); }
.social-btn:active { transform: scale(.96); }
.divider-row { display: flex; align-items: center; gap: .75rem; margin: 1.5rem 0; color: var(--muted-foreground); font-size: .8rem; }
.divider-row::before, .divider-row::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* Mascot — colourful student (afro, orange sweater, pencil behind ear) */
.mascot-wrap {
  /* 214 px : la mascotte était plus haute que le formulaire qu'elle
     surplombe, et repoussait le bouton de connexion hors de l'écran sur
     mobile. `clamp` la fait décroître avec la largeur, sans palier brutal. */
  width: clamp(96px, 26vw, 132px);
  aspect-ratio: 1;
  height: auto;
  margin: 0 auto .75rem;
  animation: mascotFloat 5s ease-in-out infinite;
}
.mascot-svg { width: 100%; height: 100%; overflow: visible; }

/* palette (shared by login + signup mascots) */
.m-sweater { fill: url(#sweaterGrad); }
.m-collar { fill: #fff3ea; }
.m-skin { fill: #8a5a3c; }
.m-skin-d { fill: #6b4530; }
.m-hair { fill: #241812; }
.m-brow { stroke: #241812; stroke-width: 4; fill: none; stroke-linecap: round; }
.m-white { fill: #fff; }
.m-pupil { fill: #2a1a12; }
.m-spark { fill: #fff; }
.m-nose { stroke: #6b4530; stroke-width: 3; fill: none; stroke-linecap: round; }
.m-cheek { fill: #ff7e5f; opacity: .32; }
.m-mouth { stroke: #3a2418; stroke-width: 4; fill: none; stroke-linecap: round; }
.m-pencil-body { fill: #f2b134; }
.m-pencil-band { fill: #e88a3c; }
.m-pencil-wood { fill: #d7a86e; }
.m-pencil-lead { fill: #3a2418; }
.m-sleeve { stroke: #e8623f; stroke-width: 19; fill: none; stroke-linecap: round; }
.m-forearm { stroke: #8a5a3c; stroke-width: 15; fill: none; stroke-linecap: round; }

/* head tilt while typing username */
.mascot-head-group {
  transform: rotate(var(--mascot-tilt, 0deg));
  transform-box: view-box;
  transform-origin: 110px 132px;
  transition: transform .3s var(--ease-out);
}

/* blink */
.mascot-eyes {
  transform-box: fill-box;
  transform-origin: center;
  animation: mascotBlink 5s ease-in-out infinite;
  transition: opacity .18s var(--ease-out);
}

/* arms crossfade: rest (folded) <-> cover (over eyes) */
.arms-rest, .arms-cover { transition: opacity .28s var(--ease-out), transform .3s var(--ease-out); }
.arms-cover { opacity: 0; transform: translateY(8px); }
.arms-rest { animation: handTap 1.8s ease-in-out infinite; transform-box: view-box; transform-origin: 110px 175px; }
.mascot-wrap.covering .arms-rest { opacity: 0; transform: translateY(8px); animation: none; }
.mascot-wrap.covering .arms-cover { opacity: 1; transform: translateY(0); }
.mascot-wrap.covering .mascot-eyes { opacity: 0; }

@keyframes mascotFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes mascotBlink { 0%, 90%, 100% { transform: scaleY(1); } 94% { transform: scaleY(.1); } }
@keyframes handTap { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }

@media (prefers-reduced-motion: reduce) {
  .mascot-wrap, .mascot-eyes, .arms-rest { animation: none !important; }
}

/* Signup mascot — the same student waving hello */
.signup-mascot {
  width: 150px; height: 150px;
  margin: 0 auto 1rem;
  animation: mascotFloat 5s ease-in-out infinite;
}
.signup-mascot svg { width: 100%; height: 100%; overflow: visible; }
.signup-mascot .sleeve-sm { stroke: #e8623f; stroke-width: 15; fill: none; stroke-linecap: round; }
.signup-mascot .forearm-sm { stroke: #8a5a3c; stroke-width: 12; fill: none; stroke-linecap: round; }
.signup-mascot .wave-fingers { stroke: #8a5a3c; stroke-width: 3.5; fill: none; stroke-linecap: round; }
.signup-mascot .wave-arm {
  transform-box: view-box;
  transform-origin: 96px 104px;
  animation: mascotWave 2.4s ease-in-out infinite;
}
@keyframes mascotWave {
  0%, 100% { transform: rotate(2deg); }
  25% { transform: rotate(-16deg); }
  50% { transform: rotate(8deg); }
  75% { transform: rotate(-12deg); }
}
@media (prefers-reduced-motion: reduce) {
  .signup-mascot, .signup-mascot .wave-arm { animation: none !important; }
}

.password-toggle {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  height: 34px; padding: 0 .8rem; border-radius: var(--r-sm);
  background: var(--foreground); color: var(--background);
  border: none; font-size: .75rem; font-weight: 700; cursor: pointer;
  min-width: 44px;
}
.password-toggle:active { transform: translateY(-50%) scale(.96); }

/* OTP inputs */
.otp-row { display: flex; gap: .8rem; justify-content: center; margin: 2rem 0; }
.otp-box {
  width: 3.4rem; height: 3.6rem;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--card);
  text-align: center;
  font-family: var(--font-serif);
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--primary-ink);
  transition: border-color .2s, box-shadow .2s, transform .15s;
}
.otp-box:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 4px rgba(255,126,95,.18);
  transform: translateY(-2px);
}

/* Icon avatar circle */
.icon-circle {
  width: 76px; height: 76px; border-radius: 50%;
  background: var(--secondary);
  display: flex; align-items: center; justify-content: center;
  color: var(--primary-ink);
  margin: 0 auto 1.25rem;
}

/* ---------- Dashboard shell ---------- */
.dash-shell { display: grid; grid-template-columns: 260px 1fr; min-height: 100vh; }
.dash-sidebar {
  background: var(--sidebar);
  border-right: 1px solid var(--sidebar-border);
  padding: 1.5rem 1.1rem;
  display: flex; flex-direction: column; gap: .3rem;
  position: sticky; top: 0; height: 100vh;
}
.dash-sidebar .brand { margin-bottom: 1.5rem; padding-inline: .5rem; }
.dash-link {
  display: flex; align-items: center; gap: .75rem;
  padding: .75rem .9rem; border-radius: var(--r-md);
  font-weight: 600; font-size: .9rem; color: var(--sidebar-foreground); opacity: .7;
  transition: background .2s, opacity .2s;
  min-height: 44px;
}
.dash-link svg { flex: none; }
.dash-link:hover { background: rgba(255,126,95,.08); opacity: 1; }
.dash-link.active { background: var(--sidebar-primary); color: var(--sidebar-primary-foreground); opacity: 1; box-shadow: var(--shadow-glow); }
.dash-link.active svg { color: var(--sidebar-primary-foreground); }
.dash-sidebar hr { border: none; border-top: 1px solid var(--sidebar-border); margin: .75rem 0; }
.dash-main { padding: 1.75rem clamp(1.25rem, 3vw, 2.5rem); }
.dash-topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.75rem; gap: 1rem; flex-wrap: wrap; }
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; margin-bottom: 1.75rem; }
@media (max-width: 1080px) { .stat-grid { grid-template-columns: repeat(2, 1fr); } }
.stat-card { padding: 1.35rem; }
.stat-card .stat-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: .75rem; }
.stat-card .stat-icon { width: 40px; height: 40px; border-radius: var(--r-sm); background: var(--secondary); color: var(--primary-ink); display: flex; align-items: center; justify-content: center; }
.stat-card .stat-value { font-family: var(--font-serif); font-size: 1.8rem; font-weight: 900; }
.stat-card .stat-label { font-size: .82rem; color: var(--muted-foreground); }
.stat-card .stat-delta { font-size: .78rem; font-weight: 700; }
.stat-delta.up { color: var(--success-ink); }
.stat-delta.down { color: var(--destructive-ink); }

.dash-mobile-bar { display: none; }

@media (max-width: 900px) {
  .dash-shell { grid-template-columns: 1fr; }

  .dash-mobile-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
    background: var(--background);
    position: sticky;
    top: 0;
    z-index: 40;
  }
  .dash-mobile-bar .brand { font-size: 1rem; }
  .dash-mobile-bar .dash-burger {
    width: 44px; height: 44px; border-radius: var(--r-sm);
    border: 1px solid var(--border); background: var(--card);
    display: flex; align-items: center; justify-content: center; flex: none;
  }

  .dash-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    width: 270px;
    z-index: 70;
    transform: translateX(-100%);
    transition: transform .3s var(--ease-out);
    display: flex;
    box-shadow: var(--shadow-lg);
    /* Long menus (admin) must stay reachable inside the drawer */
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  }
  .dash-sidebar.open { transform: translateX(0); }

  .dash-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,.4);
    z-index: 65;
  }
  .dash-overlay.open { display: block; }
}

table.data-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.data-table th {
  text-align: left; font-size: .74rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted-foreground); padding: .7rem 1rem; border-bottom: 1px solid var(--border);
}
table.data-table td { padding: .85rem 1rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
table.data-table tr:last-child td { border-bottom: none; }
table.data-table tr { transition: background .15s; }
table.data-table tbody tr:hover { background: var(--muted); }
.status-pill { display: inline-flex; align-items: center; gap: .35rem; font-size: .75rem; font-weight: 700; padding: .3rem .65rem; border-radius: 999px; }
.status-pill.ok { background: rgba(47,158,100,.12); color: var(--success-ink); }
.status-pill.pending { background: rgba(242,165,65,.15); color: #b9740b; }
.status-pill.warn { background: rgba(230,57,70,.1); color: var(--destructive-ink); }
/* Inscription sociale jamais finalisée : ni un succès, ni une alerte, ni une
   file d'attente. Le gris dit « rien à faire ici pour l'instant » sans attirer
   l'œil dans un tableau que l'administration parcourt à la recherche d'actions. */
.status-pill.muted { background: var(--muted); color: var(--muted-foreground); }
/* Remplace un bouton là où aucune action n'a de sens, en gardant l'alignement
   de la colonne : une cellule vide se lit comme un défaut d'affichage. */
.hint-inline { font-size: .78rem; color: var(--muted-foreground); font-style: italic; white-space: nowrap; }

/* ---------- Responsive tables → stacked cards on mobile ---------- */
@media (max-width: 640px) {
  /* hide the header row visually (labels move onto each cell) */
  table.data-table thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  table.data-table, table.data-table tbody { display: block; width: 100%; }
  table.data-table tr {
    display: block; background: var(--card);
    border: 1px solid var(--border); border-radius: var(--r-md);
    margin-bottom: .85rem; padding: .2rem .15rem; box-shadow: var(--shadow-sm);
  }
  table.data-table td {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .6rem .85rem; border: none; border-bottom: 1px solid var(--border); text-align: right;
  }
  table.data-table tr td:last-child { border-bottom: none; }
  table.data-table td::before {
    content: attr(data-label);
    flex: 0 0 auto; text-align: left;
    font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
    color: var(--muted-foreground);
  }
  /* actions: full-width buttons, no label */
  table.data-table td.action-cell { justify-content: flex-end; flex-wrap: wrap; gap: .45rem; }
  table.data-table td.action-cell::before { display: none; }
  table.data-table td.action-cell .btn { flex: 1 1 auto; min-width: 7rem; }
  /* an empty cell (e.g. spacer column) collapses */
  table.data-table td:not([data-label]):empty { display: none; }
  /* no per-row hover shift on mobile cards (avoids flicker on tap) */
  table.data-table tbody tr:hover { background: var(--card); }
  /* smooth card press feedback on touch */
  table.data-table tr { transition: box-shadow .18s var(--ease-out), transform .12s var(--ease-out); }
}

.avatar-sm { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; outline: 1px solid rgba(0,0,0,.1); }
.dark .avatar-sm { outline-color: rgba(255,255,255,.1); }

/* ---------- Scroll progress bar (public pages) ---------- */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0;
  z-index: 100; pointer-events: none;
  background: linear-gradient(90deg, var(--primary), var(--accent));
  box-shadow: var(--shadow-glow);
  transition: width .1s linear;
}

/* ---------- Sticky scroll arrow (down / back to top) ---------- */

/* ---------- Extra micro-interactions (shared across all pages) ---------- */
/* Card lift on hover — mirrors the tutor-card behaviour for the rest of the surfaces */
.feature-card, .testi-card, .level-col {
  transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out), border-color .25s var(--ease-out);
}
.feature-card:hover, .testi-card:hover, .level-col:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: var(--accent);
}
.stat-card { transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out); }
.stat-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }

/* Icon pop when its card is hovered */
.feature-card .f-icon, .stat-card .stat-icon, .contact-info-item .f-icon {
  transition: transform .25s var(--ease-out);
}
.feature-card:hover .f-icon, .stat-card:hover .stat-icon { transform: scale(1.08) rotate(-4deg); }

/* Chip hover */
.subject-chips .chip { transition: transform .18s var(--ease-out), border-color .18s var(--ease-out), color .18s var(--ease-out); }
.subject-chips .chip:hover { transform: translateY(-2px); border-color: var(--primary); color: var(--primary-ink); }

/* Brand mark spins slightly on hover */
.brand-mark { transition: transform .3s var(--ease-out); }
.brand:hover .brand-mark { transform: rotate(-8deg) scale(1.05); }

/* Primary-button icons nudge forward on hover */
.btn svg { transition: transform .2s var(--ease-out); flex: none; }
/* Safety net: an inline SVG without width/height would otherwise render at its
   default 300×150 and blow the button up. */
.btn svg:not([width]) { width: 16px; height: 16px; }
.btn-primary:hover svg, .btn-success:hover svg { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .scroll-progress { display: none; }
  .feature-card, .testi-card, .level-col, .stat-card,
  .feature-card .f-icon, .stat-card .stat-icon,
  .subject-chips .chip, .brand-mark, .btn svg {
    transition: none;
  }
  .feature-card:hover, .testi-card:hover, .level-col:hover, .stat-card:hover,
  .feature-card:hover .f-icon, .stat-card:hover .stat-icon,
  .subject-chips .chip:hover, .brand:hover .brand-mark,
  .btn-primary:hover svg, .btn-success:hover svg {
    transform: none;
  }
}

/* ===================================================================
   Mobile nav — keep the "trait" on the selected (current-page) link
   The desktop nav shows a primary underline on .active; in the vertical
   drawer the idiomatic equivalent is a persistent left accent bar.
   .active is applied by main.js based on the current page.
   =================================================================== */
.mobile-menu a.active {
  color: var(--primary-ink);
  background: var(--secondary);
}
.mobile-menu a.active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 62%;
  border-radius: 3px;
  background: var(--primary);
}
/* Hover shifts text right by padding; keep the active bar pinned to the edge */
.mobile-menu a.active:hover { padding-left: 1rem; }

/* ===================================================================
   Forms — refined field interactions (applies to every form site-wide)
   Focus lift, label + icon highlight, custom select caret, live
   validation colour, tactile checkboxes, staged section entrance.
   =================================================================== */

/* Smooth every state change on the field surface */
.input, select.input, textarea.input {
  transition: border-color .18s var(--ease-out),
              box-shadow .18s var(--ease-out),
              background-color .18s var(--ease-out);
}

/* Hover invites interaction before focus */
.input:hover:not(:focus):not(:disabled) { border-color: var(--accent); }

/* Focus: brand ring + gentle depth (overrides the earlier .input:focus) */
.input:focus {
  outline: none;
  border-color: var(--primary);
  /* `background-color` et non le raccourci `background` : celui-ci remettrait
     `background-image` à none et effacerait le chevron des <select> au focus. */
  background-color: var(--card);
  box-shadow: 0 0 0 4px rgba(255,126,95,.16), var(--shadow-sm);
}

/* The label and leading icon light up while the field is active */
.field:focus-within label { color: var(--primary-ink); }
.input-icon-wrap { transition: color .18s var(--ease-out); }
.input-icon-wrap:focus-within .icon { color: var(--primary-ink); }
.field label { transition: color .18s var(--ease-out); }

/* Custom caret for selects (native arrow removed) */
select.input {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 16px;
  cursor: pointer;
}
.dark select.input {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
select.input::-ms-expand { display: none; }
/* Un `select` doit montrer le focus clavier aussi nettement qu'un champ texte :
   l'ombre portée seule ne suffit pas sur tous les rendus natifs. */
select.input:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Live validation — only after the user has interacted (native :user-invalid) */
.input:user-invalid { border-color: var(--destructive); }
.input:user-invalid:focus {
  box-shadow: 0 0 0 4px rgba(230,57,70,.16), var(--shadow-sm);
}

/* Tactile checkboxes */
.check-row, .consent-row { cursor: pointer; }
.check-row input, .consent-row input {
  cursor: pointer;
  transition: transform .12s var(--ease-out);
}
.check-row input:active, .consent-row input:active { transform: scale(.9); }

/* Multi-step form cards: the one you're filling in lifts to the front */
.form-section {
  transition: border-color .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.form-section:focus-within {
  border-color: var(--accent);
  box-shadow: var(--shadow-md);
}

/* Staged entrance for form sections (never hides content for reduced-motion) */
@media (prefers-reduced-motion: no-preference) {
  .form-section { animation: formSectionIn .55s var(--ease-out) both; }
  .form-section:nth-of-type(1) { animation-delay: .04s; }
  .form-section:nth-of-type(2) { animation-delay: .12s; }
  .form-section:nth-of-type(3) { animation-delay: .20s; }
  .form-section:nth-of-type(4) { animation-delay: .28s; }
  @keyframes formSectionIn {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ===================================================================
   Type-driven field icons — a leading icon derived from the input type,
   with zero markup changes. Scoped to `.field > .input` so fields already
   wrapped in `.input-icon-wrap` (which bring their own icon) never double
   up. The icon tints to the brand colour while the field is focused.
   =================================================================== */
.field > .input[type="email"],
.field > .input[type="tel"],
.field > .input[type="date"],
.field > .input[type="time"],
.field > .input[type="number"] {
  padding-left: 2.75rem;
  background-repeat: no-repeat;
  background-position: left .9rem center;
  background-size: 18px 18px;
}
/* light theme (neutral) */
.field > .input[type="email"]  { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 6l-10 7L2 6'/%3E%3Crect x='2' y='4' width='20' height='16' rx='2'/%3E%3C/svg%3E"); }
.field > .input[type="tel"]    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.68 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.32 1.85.55 2.81.68A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E"); }
.field > .input[type="date"]   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4M8 2v4M3 10h18'/%3E%3C/svg%3E"); }
.field > .input[type="time"]   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpolyline points='12 7 12 12 15 14'/%3E%3C/svg%3E"); }
.field > .input[type="number"] { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23a89a92' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='9' x2='20' y2='9'/%3E%3Cline x1='4' y1='15' x2='20' y2='15'/%3E%3Cline x1='10' y1='3' x2='8' y2='21'/%3E%3Cline x1='16' y1='3' x2='14' y2='21'/%3E%3C/svg%3E"); }
/* dark theme (neutral) */
.dark .field > .input[type="email"]  { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 6l-10 7L2 6'/%3E%3Crect x='2' y='4' width='20' height='16' rx='2'/%3E%3C/svg%3E"); }
.dark .field > .input[type="tel"]    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.68 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.32 1.85.55 2.81.68A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E"); }
.dark .field > .input[type="date"]   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4M8 2v4M3 10h18'/%3E%3C/svg%3E"); }
.dark .field > .input[type="time"]   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpolyline points='12 7 12 12 15 14'/%3E%3C/svg%3E"); }
.dark .field > .input[type="number"] { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23d7c6bc' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='9' x2='20' y2='9'/%3E%3Cline x1='4' y1='15' x2='20' y2='15'/%3E%3Cline x1='10' y1='3' x2='8' y2='21'/%3E%3Cline x1='16' y1='3' x2='14' y2='21'/%3E%3C/svg%3E"); }
/* focus tint (brand colour, same in both themes) */
.field > .input[type="email"]:focus  { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ff7e5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 6l-10 7L2 6'/%3E%3Crect x='2' y='4' width='20' height='16' rx='2'/%3E%3C/svg%3E"); }
.field > .input[type="tel"]:focus    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ff7e5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.68 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.32 1.85.55 2.81.68A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E"); }
.field > .input[type="date"]:focus   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ff7e5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4M8 2v4M3 10h18'/%3E%3C/svg%3E"); }
.field > .input[type="time"]:focus   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ff7e5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpolyline points='12 7 12 12 15 14'/%3E%3C/svg%3E"); }
.field > .input[type="number"]:focus { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23ff7e5f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='9' x2='20' y2='9'/%3E%3Cline x1='4' y1='15' x2='20' y2='15'/%3E%3Cline x1='10' y1='3' x2='8' y2='21'/%3E%3Cline x1='16' y1='3' x2='14' y2='21'/%3E%3C/svg%3E"); }

/* ===================================================================
   Chip toggles — promoted to a shared, polished component (previously
   only styled on the search page). Used for subjects, class levels, etc.
   =================================================================== */
.chip-select { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip-toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-sans);
  font-size: .82rem; font-weight: 600;
  padding: .5rem .85rem; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--card); color: var(--foreground);
  cursor: pointer; min-height: 40px;
  transition: background-color .18s var(--ease-out), border-color .18s var(--ease-out),
              color .18s var(--ease-out), transform .12s var(--ease-out), box-shadow .18s var(--ease-out);
}
.chip-toggle:hover { border-color: var(--primary); color: var(--primary-ink); }
.chip-toggle:active { transform: scale(.96); }
.chip-toggle.active {
  background: linear-gradient(135deg, var(--primary), var(--accent));
  border-color: transparent;
  color: var(--primary-foreground);
  box-shadow: var(--shadow-glow);
}
.chip-toggle.active:hover { color: var(--primary-foreground); }
.chip-toggle svg { width: 15px; height: 15px; flex: none; }

/* Cycle d'une matière qui n'est pas transversale (Philosophie, Éveil au
   milieu…). Discret par construction : c'est une précision, pas une étiquette
   de plus à lire. Rien n'apparaît sur les matières des trois cycles. */
.chip-cycle {
  font-size: .66rem; font-weight: 700; letter-spacing: .03em;
  padding: .1rem .34rem; border-radius: .3rem;
  background: var(--secondary); color: var(--muted-foreground);
}
.chip-toggle.active .chip-cycle {
  background: rgba(255, 255, 255, .22); color: var(--primary-foreground);
}
/* Attente du référentiel : une ligne calme, pas un vide inexpliqué. */
.chip-vide { font-size: .82rem; color: var(--muted-foreground); font-style: italic; }

/* Section subtitle (sits under an .fs-head) */
.fs-sub { margin: -.9rem 0 1.35rem; color: var(--muted-foreground); font-size: .9rem; }

/* Classes grouped by cycle (répétiteur — compétences) */
.class-groups { display: flex; flex-direction: column; gap: 1.1rem; }
.class-group .cg-label {
  display: block;
  font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
  font-weight: 700; color: var(--muted-foreground);
  margin-bottom: .55rem;
}

/* Bloc budget du parent — mensuel uniquement (l'horaire a été retiré du site) */
.budget-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; align-items: end; }
@media (max-width: 520px) { .budget-grid { grid-template-columns: 1fr; } }
.budget-cell { display: flex; flex-direction: column; gap: .4rem; }
.budget-cap { font-size: .82rem; font-weight: 600; color: var(--foreground); }
.budget-cell--lead {
  padding: .9rem;
  border-radius: var(--r-md);
  background: var(--secondary);
}
.budget-cell--lead .budget-cap { color: var(--primary-ink); display: flex; align-items: center; gap: .4rem; }
.budget-tag {
  font-size: .64rem; text-transform: uppercase; letter-spacing: .04em;
  font-weight: 800; padding: .12rem .4rem; border-radius: 999px;
  background: var(--primary); color: var(--primary-foreground);
}
/* Badge « facultatif » neutre (encore utilisé par le tableau de bord admin) */
.opt-tag {
  font-size: .64rem; text-transform: uppercase; letter-spacing: .04em;
  font-weight: 800; padding: .12rem .4rem; border-radius: 999px;
  background: var(--muted); color: var(--muted-foreground);
  border: 1px solid var(--border);
}
.input-affix { position: relative; }
.input-affix .input { padding-right: 3.4rem; }
.input-affix .affix {
  position: absolute; right: .9rem; top: 50%; transform: translateY(-50%);
  font-size: .78rem; font-weight: 700; color: var(--muted-foreground);
  pointer-events: none;
}
/* Hide number spinners so they don't collide with the FCFA suffix */
.input-affix input[type="number"]::-webkit-outer-spin-button,
.input-affix input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.input-affix input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* ===================================================================
   Field focus motion — "spotlight" style.
   The label stays above the field. On focus: a vertical accent bar wipes
   down the left edge, the icon springs in, the field lifts slightly and a
   soft ring blooms. The label shifts right and picks up the brand colour.
   Transform/opacity + colour only, ease-out, ≤240ms, reduced-motion safe.
   =================================================================== */
.input-icon-wrap { display: block; }

/* Label above the field: nudges right and colours up while focused */
.field > label {
  display: inline-block;
  transform-origin: left center;
  transition: transform .2s var(--ease-out-quart), color .18s ease, letter-spacing .2s var(--ease-out);
}
.field:focus-within > label {
  color: var(--primary-ink);
  transform: translateX(3px);
  letter-spacing: .012em;
}
/* Once filled (and unfocused), a small brand dot confirms the value */
.field.is-filled > label::after {
  content: "";
  display: inline-block; width: 5px; height: 5px; margin-left: .4rem;
  border-radius: 50%; background: var(--primary);
  vertical-align: middle; opacity: .55;
  animation: dotPop .25s var(--ease-out) both;
}
.field.is-filled:focus-within > label::after { opacity: 1; }

/* Icon springs in from the left */
.input-icon-wrap .icon {
  z-index: 2;
  transition: color .18s ease, transform .24s var(--ease-out-quart), opacity .18s ease;
}
.input-icon-wrap:focus-within .icon { color: var(--primary-ink); }
.input-icon-wrap.is-textarea .icon { top: 1.35rem; transform: none; }

/* Vertical accent bar wiping down the left edge on focus */
.input-icon-wrap::before {
  content: "";
  position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  border-radius: 3px; background: var(--primary);
  transform: scaleY(0); transform-origin: top center;
  transition: transform .24s var(--ease-out-quart);
  pointer-events: none; z-index: 2;
}
.input-icon-wrap:focus-within::before { transform: scaleY(1); }

/* The field itself lifts a touch while focused */
.input-icon-wrap .input { transition: border-color .18s var(--ease-out), box-shadow .22s var(--ease-out), transform .22s var(--ease-out); }
.input-icon-wrap:focus-within .input { transform: translateY(-1px); }

@keyframes dotPop { from { transform: scale(0); } to { transform: scale(1); } }

@media (prefers-reduced-motion: reduce) {
  .field > label,
  .input-icon-wrap .icon,
  .input-icon-wrap::before,
  .input-icon-wrap .input { transition: color .15s ease; }
  .field:focus-within > label { transform: none; letter-spacing: normal; }
  .input-icon-wrap::before { transform: scaleY(1); opacity: 0; }
  .input-icon-wrap:focus-within::before { opacity: 1; }
  .input-icon-wrap:focus-within .input { transform: none; }
  .field.is-filled > label::after { animation: none; }
}

/* ===================================================================
   Dashboard stat tiles (shared by all dashboards)
   Accent-coloured tiles with a drifting glow, an animated SVG logo and
   a rule that draws itself in. Staggered entrance, reduced-motion safe.
   =================================================================== */
.tile-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.1rem; margin-bottom: 1.75rem; }
@media (max-width: 1080px) { .tile-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 460px)  { .tile-grid { grid-template-columns: 1fr; } }

.tile {
  --tile: var(--primary);
  position: relative; overflow: hidden; isolation: isolate;
  padding: 1.35rem 1.25rem 1.5rem;
  border-radius: var(--r-lg);
  background: var(--card);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out), border-color .25s var(--ease-out);
}
.tile--parents  { --tile: #ff7e5f; }
.tile--tutors   { --tile: #2f9e64; }
.tile--requests { --tile: #f2a541; }
.tile--pending  { --tile: #ce6a57; }
.tile--info     { --tile: #4f8ef7; }
.tile:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: color-mix(in srgb, var(--tile) 45%, var(--border)); }

.tile-glow {
  position: absolute; z-index: -1; top: -55px; right: -55px;
  width: 150px; height: 150px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--tile) 38%, transparent), transparent 70%);
  opacity: .75;
}

.tile-icon {
  width: 44px; height: 44px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  color: var(--tile);
  background: color-mix(in srgb, var(--tile) 14%, transparent);
  transition: transform .28s var(--ease-out), background-color .25s var(--ease-out);
}
.tile-icon .tile-logo { width: 24px; height: 24px; overflow: visible; }
.tile:hover .tile-icon { transform: scale(1.07) rotate(-5deg); background: color-mix(in srgb, var(--tile) 22%, transparent); }

.tile-value {
  margin-top: .9rem;
  font-family: var(--font-serif); font-weight: 900;
  font-size: clamp(1.7rem, 3.2vw, 2.1rem); line-height: 1;
  color: var(--foreground);
}
.tile-label { margin-top: .35rem; font-size: .84rem; color: var(--muted-foreground); }
.tile-rule {
  display: block; margin-top: 1rem; height: 3px; border-radius: 3px;
  background: linear-gradient(90deg, var(--tile), color-mix(in srgb, var(--tile) 25%, transparent));
  transform-origin: left center;
}

@media (prefers-reduced-motion: no-preference) {
  .tile { animation: tileIn .5s var(--ease-out) both; }
  .tile:nth-child(1) { animation-delay: .04s; }
  .tile:nth-child(2) { animation-delay: .12s; }
  .tile:nth-child(3) { animation-delay: .20s; }
  .tile:nth-child(4) { animation-delay: .28s; }
  .tile-rule { animation: ruleIn .7s var(--ease-out) .35s both; }
  .tile-glow { animation: glowDrift 9s ease-in-out infinite alternate; }
  @keyframes tileIn    { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
  @keyframes ruleIn    { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  @keyframes glowDrift { from { transform: translate(0, 0) scale(1); } to { transform: translate(-14px, 12px) scale(1.14); } }

  /* ---- Animated SVG logo parts ---- */
  .tile-logo .lg-draw, .tile-logo .lg-lines, .tile-logo .lg-check,
  .tile-logo .lg-ring, .tile-logo .lg-flap {
    stroke-dasharray: 90; stroke-dashoffset: 90;
    animation: lgDraw 1.1s var(--ease-out) .25s forwards;
  }
  .tile-logo .lg-lines { animation-duration: .9s; animation-delay: .55s; }
  .tile-logo .lg-check { animation-duration: .5s;  animation-delay: .85s; stroke-dasharray: 20; stroke-dashoffset: 20; }
  .tile-logo .lg-beat  { animation: lgBeat 2.6s ease-in-out 1.2s infinite; transform-origin: center; }
  .tile-logo .lg-bob   { animation: lgBob 2.4s ease-in-out 1.1s infinite; }
  .tile-logo .lg-coin  { animation: lgCoin 3.2s var(--ease-out) 1s infinite; }
  .tile-logo .lg-spin  { animation: lgSpin 6s linear 1.2s infinite; }
  .tile-logo .lg-sheen { animation: lgSheen 3.4s ease-in-out 1.3s infinite; }
  .tile-logo .lg-star  { transform-origin: center; animation: lgStar .6s var(--ease-out) .9s both; }
  .tile-logo .lg-slot  { transform-origin: center; animation: lgStar .5s var(--ease-out) .9s both; }
  .tile-logo .lg-flap  { transform-origin: 12px 8px; }

  @keyframes lgDraw  { to { stroke-dashoffset: 0; } }
  @keyframes lgBeat  { 0%, 70%, 100% { transform: scale(1); } 80% { transform: scale(1.18); } 90% { transform: scale(1.05); } }
  @keyframes lgBob   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2.2px); } }
  @keyframes lgCoin  { 0% { transform: translateY(0); opacity: 1; } 45% { transform: translateY(7px); opacity: .25; } 46%, 100% { transform: translateY(0); opacity: 1; } }
  @keyframes lgSpin  { to { transform: rotate(360deg); } }
  @keyframes lgSheen { 0%, 100% { opacity: .18; } 50% { opacity: .6; } }
  @keyframes lgStar  { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: .9; } }

  /* replay the logo motion on hover for a tactile feel */
  .tile:hover .tile-logo .lg-draw { animation: lgDraw .8s var(--ease-out) forwards; }
}

/* ===================================================================
   Quartier combobox — suggestions of already-located quartiers.
   Shared by the registration forms and the admin popups.
   =================================================================== */
.suggest-field { position: relative; z-index: 1; }

/* While a list is open, lift the field AND its containing card/section above
   the following ones — otherwise later siblings (which create their own
   stacking contexts) paint over the dropdown and it looks cut off. */
.suggest-field.suggest-open { z-index: 900; }
.suggest-open-host { position: relative; z-index: 800; }

.suggest-list {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 901;
  margin-top: .3rem; max-height: 210px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-md);
  animation: fadeUp .18s var(--ease-out);
}
.suggest-item {
  display: block; width: 100%; text-align: left; padding: .6rem .8rem;
  background: none; border: none; cursor: pointer; font: inherit;
  color: var(--foreground); font-size: .88rem;
  transition: background-color .14s var(--ease-out), padding-left .14s var(--ease-out), color .14s var(--ease-out);
}
.suggest-item:hover { background: var(--muted); padding-left: 1rem; color: var(--primary-ink); }
@media (prefers-reduced-motion: reduce) { .suggest-list { animation: none; } }

/* ===================================================================
   Éditeur d'annonces (admin) — rédaction, galerie d'images, vidéo.
   =================================================================== */
.ann-editor { animation: fadeUp .35s var(--ease-out); }
.ann-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.25rem; }
.ann-editor-grid { display: grid; grid-template-columns: 1.6fr .9fr; gap: 1.75rem; align-items: start; }
@media (max-width: 900px) { .ann-editor-grid { grid-template-columns: 1fr; } }
.ann-fields { display: flex; flex-direction: column; gap: 1rem; }
.ann-media { display: flex; flex-direction: column; gap: .7rem; }
.ann-drop {
  position: relative; aspect-ratio: 16 / 10; width: 100%;
  border: 1.5px dashed var(--border); border-radius: var(--r-md);
  background: var(--muted); overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: border-color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.ann-drop:hover { border-color: var(--primary); background: var(--secondary); }
.ann-drop img { width: 100%; height: 100%; object-fit: cover; }
.ann-drop.is-video video { width: 100%; height: 100%; object-fit: cover; background: #000; }
.ann-drop-empty { display: flex; flex-direction: column; align-items: center; gap: .5rem; color: var(--muted-foreground); font-size: .82rem; text-align: center; padding: 1rem; }
.ann-drop-empty svg { width: 32px; height: 32px; }
.ann-media-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
.ann-editor-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border); flex-wrap: wrap;
}
.ann-thumb {
  width: 46px; height: 34px; border-radius: var(--r-sm); object-fit: cover; display: block;
  background: var(--muted); outline: 1px solid rgba(0,0,0,.1);
}
.dark .ann-thumb { outline-color: rgba(255,255,255,.1); }

/* ---- Table de bascule Images / Vidéo ---- */
.media-switch {
  position: relative; display: grid; grid-template-columns: 1fr 1fr; gap: .25rem;
  padding: .25rem; margin-bottom: 1rem;
  background: var(--muted); border-radius: var(--r-md);
}
.media-tab {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  padding: .55rem .5rem; border: none; background: none; cursor: pointer;
  font: inherit; font-size: .84rem; font-weight: 700; color: var(--muted-foreground);
  border-radius: var(--r-sm);
  transition: color .2s var(--ease-out);
}
.media-tab svg { width: 16px; height: 16px; }
.media-tab.active { color: var(--primary-ink); }
.media-count {
  min-width: 18px; padding: 0 .3rem; border-radius: 999px;
  background: var(--primary); color: var(--primary-foreground);
  font-size: .68rem; line-height: 18px; font-variant-numeric: tabular-nums;
}
.media-tab:not(.active) .media-count { background: var(--border); color: var(--muted-foreground); }
.media-ink {
  position: absolute; z-index: 0; top: .25rem; bottom: .25rem; left: .25rem;
  width: calc(50% - .375rem); border-radius: var(--r-sm);
  background: var(--card); box-shadow: var(--shadow-sm);
  transition: transform .28s var(--ease-out);
}
.media-switch.on-video .media-ink { transform: translateX(calc(100% + .25rem)); }
.media-panel { display: none; }
.media-panel.active { display: block; animation: fadeUp .3s var(--ease-out); }

/* ---- Galerie d'images ---- */
.gallery-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; margin-bottom: .6rem; }
.gallery-item {
  position: relative; aspect-ratio: 1; border-radius: var(--r-sm); overflow: hidden;
  background: var(--muted); outline: 1px solid var(--border);
  animation: galIn .3s var(--ease-out) both;
}
.gallery-item img { width: 100%; height: 100%; object-fit: cover; }
.gallery-item .gi-del {
  position: absolute; top: 3px; right: 3px; width: 22px; height: 22px;
  border: none; border-radius: 50%; cursor: pointer;
  background: rgba(20,14,16,.65); color: #fff; font-size: .8rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity .18s var(--ease-out), transform .12s var(--ease-out);
}
.gallery-item:hover .gi-del, .gallery-item:focus-within .gi-del { opacity: 1; }
.gallery-item .gi-del:active { transform: scale(.9); }
.gallery-empty { grid-column: 1/-1; font-size: .82rem; color: var(--muted-foreground); font-style: italic; }
@keyframes galIn { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .ann-editor, .media-panel.active { animation: none; }
  .media-ink { transition: none; }
  .gallery-item { animation: none; }
}

/* ===================================================================
   Espace « Mes paiements » / « Mes revenus » (parent & répétiteur)
   =================================================================== */
.pay-title { font-family: var(--font-sans); font-size: 1rem; font-weight: 700; margin-bottom: 1rem; }
.two-col-pay { display: grid; grid-template-columns: 1fr 1.3fr; gap: 1.5rem; align-items: start; }
@media (max-width: 900px) { .two-col-pay { grid-template-columns: 1fr; } }

.partner-row { display: flex; align-items: center; gap: .75rem; padding: .65rem 0; border-bottom: 1px solid var(--border); }
.partner-row:last-child { border-bottom: none; }
.partner-avatar {
  width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: .74rem; font-weight: 800; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
  background-size: cover; background-position: center;
}
.partner-name { flex: 1; font-size: .9rem; font-weight: 600; }
.partner-total { font-weight: 700; color: var(--primary-ink); font-size: .9rem; }

/* Bandeau revenus (répétiteur) */
.rev-head { display: flex; align-items: center; justify-content: space-between; gap: 2rem; flex-wrap: wrap; }
.rev-total { font-family: var(--font-serif); font-weight: 900; font-size: clamp(2rem, 5vw, 2.8rem); line-height: 1; margin-top: .6rem; }
.rev-sub { font-size: .85rem; color: var(--muted-foreground); margin-top: .35rem; }
.rev-split { display: grid; grid-template-columns: repeat(4, auto); gap: 1.75rem; }
@media (max-width: 640px) { .rev-split { grid-template-columns: repeat(2, 1fr); gap: 1rem; width: 100%; } }
.rev-split .rev-k { display: block; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-foreground); }
.rev-split strong { font-size: 1.1rem; font-weight: 800; }

/* ---- Reçu imprimable ---- */
.receipt-overlay {
  position: fixed; inset: 0; z-index: 120; display: flex; align-items: flex-start; justify-content: center;
  padding: clamp(1rem, 4vw, 3rem) 1rem; overflow-y: auto;
  background: rgba(20,14,16,.6); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity .2s var(--ease-out);
}
.receipt-overlay.open { opacity: 1; }
.receipt-card {
  width: 100%; max-width: 460px; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  transform: translateY(12px) scale(.985); opacity: 0;
  transition: transform .24s var(--ease-out), opacity .24s var(--ease-out);
}
.receipt-overlay.open .receipt-card { transform: none; opacity: 1; }
.receipt-head { display: flex; align-items: center; justify-content: space-between; padding: 1.1rem 1.35rem; border-bottom: 1px dashed var(--border); }
.receipt-brand { display: flex; align-items: center; gap: .5rem; font-family: var(--font-serif); font-weight: 900; }
.receipt-body { padding: 1.5rem 1.35rem; text-align: center; }
.receipt-amount { font-family: var(--font-serif); font-weight: 900; font-size: 2.2rem; margin-top: .7rem; }
.receipt-amount small { font-size: .95rem; color: var(--muted-foreground); }
.receipt-status { margin-top: .6rem; }
.receipt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .9rem 1rem; margin: 1.5rem 0 0; text-align: left; }
@media (max-width: 420px) { .receipt-grid { grid-template-columns: 1fr; } }
.receipt-grid dt { font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-foreground); }
.receipt-grid dd { margin: .15rem 0 0; font-size: .92rem; font-weight: 600; }
.receipt-note { margin-top: 1.5rem; font-size: .76rem; color: var(--muted-foreground); }
.receipt-foot { display: flex; justify-content: flex-end; gap: .75rem; padding: 0 1.35rem 1.35rem; }

@media print {
  body > *:not(.receipt-overlay) { display: none !important; }
  .receipt-overlay { position: static; background: none; padding: 0; backdrop-filter: none; opacity: 1; }
  .receipt-card { box-shadow: none; border: none; max-width: none; transform: none; opacity: 1; }
  .receipt-foot, .modal-close { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .receipt-overlay, .receipt-card { transition: opacity .12s linear; }
  .receipt-card { transform: none; }
}

/* ===================================================================
   Colonne d'actions des tableaux (CRUD) — grands écrans.
   Les boutons restent sur une seule ligne, alignés à droite, sans
   comprimer les colonnes de données.
   =================================================================== */
@media (min-width: 641px) {
  /* La cellule doit rester une vraie `table-cell` : lui donner `display:flex`
     la sort de l'algorithme de tableau et son contenu déborde sur les colonnes
     voisines. On garde donc le flux en ligne et on espace les boutons. */
  table.data-table th:last-child,
  table.data-table td.action-cell {
    width: 1%;
    white-space: nowrap;
    text-align: right;
    vertical-align: middle;
  }
  table.data-table td.action-cell .btn { vertical-align: middle; }
  table.data-table td.action-cell .btn + .btn { margin-left: .35rem; }
  /* boutons icône : carrés et compacts */
  table.data-table td.action-cell .btn-sm:has(> svg:only-child) {
    width: 34px; padding: 0; justify-content: center;
  }
}

/* ===================================================================
   Barre d'outils de panneau + champ de recherche (tous les dashboards)
   Défini ici (et non dans une page) pour que l'icône ait toujours sa
   taille : un SVG inline sans width/height s'afficherait en 300×150.
   =================================================================== */
.toolbar-actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.search-box { position: relative; display: flex; align-items: center; }
.search-box svg {
  position: absolute; left: .7rem;
  width: 16px; height: 16px; flex: none;
  color: var(--muted-foreground); pointer-events: none;
}
.search-box .input { height: 2.5rem; padding-left: 2.2rem; min-width: 16rem; }
@media (max-width: 560px) {
  .search-box, .search-box .input { min-width: 0; width: 100%; }
}

/* ===================================================================
   Correctifs de mise en page des tableaux de bord
   Un élément de grille a `min-width: auto` par défaut : il refuse de
   descendre sous la largeur de son contenu, ce qui poussait toute la
   zone principale hors de l'écran (tables larges) sur tablette.
   =================================================================== */
.dash-shell { min-width: 0; }
.dash-main { min-width: 0; }
.dash-panel { min-width: 0; }
.dash-main > *,
.dash-panel > * { max-width: 100%; }

/* Les grilles internes doivent pouvoir se comprimer aussi */
.two-col, .two-col-pay, .tile-grid, .ann-editor-grid, .modal-grid { min-width: 0; }
.two-col > *, .two-col-pay > *, .tile-grid > * { min-width: 0; }

/* Cartes en mode mobile : le contenu doit se replier, pas déborder */
@media (max-width: 640px) {
  table.data-table tr { min-width: 0; overflow: hidden; }
  table.data-table td { min-width: 0; overflow-wrap: anywhere; }
  table.data-table td.action-cell { display: flex; flex-wrap: wrap; gap: .4rem; }
  table.data-table td.action-cell .btn { min-width: 0; flex: 1 1 6rem; }
  .rev-head { gap: 1rem; }
}

/* ===================================================================
   Pastille de compte + modale (partagées par les trois tableaux de bord)
   =================================================================== */
.dash-topbar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.topbar-actions { display: flex; align-items: center; gap: .6rem; }

.admin-chip {
  display: inline-flex; align-items: center; gap: .6rem;
  padding: .3rem .55rem .3rem .3rem;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--card); cursor: pointer;
  transition: border-color .18s var(--ease-out), box-shadow .18s var(--ease-out), transform .12s var(--ease-out);
}
.admin-chip:hover { border-color: var(--primary); box-shadow: var(--shadow-sm); }
.admin-chip:active { transform: scale(.98); }
.admin-avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: .82rem; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
  background-size: cover; background-position: center;
}
.admin-chip-text { display: flex; flex-direction: column; line-height: 1.1; text-align: left; padding-right: .3rem; }
.admin-chip-text .ac-hi { font-size: .62rem; color: var(--muted-foreground); text-transform: uppercase; letter-spacing: .05em; }
.admin-chip-text strong { font-size: .85rem; }

.modal-overlay {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center; padding: 1rem;
  background: rgba(20,14,16,.55); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .2s var(--ease-out);
}
.modal-overlay.open { opacity: 1; }
.modal-card {
  width: 100%; max-width: 460px; max-height: 90vh; overflow: auto;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  transform: scale(.96) translateY(6px); opacity: 0;
  transition: transform .22s var(--ease-out), opacity .22s var(--ease-out);
}
.modal-overlay.open .modal-card { transform: none; opacity: 1; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--border); }
.modal-head h3 { font-family: var(--font-sans); font-size: 1.05rem; font-weight: 700; }
.modal-close {
  flex: none; width: 40px; height: 40px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--card); color: var(--muted-foreground);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: color .18s ease, border-color .18s ease, transform .12s var(--ease-out);
}
.modal-close:hover { color: var(--foreground); border-color: var(--primary); }
.modal-close:active { transform: scale(.94); }
.modal-body { padding: 1.5rem; display: flex; flex-direction: column; gap: 1rem; }
.modal-foot { display: flex; justify-content: flex-end; gap: .75rem; padding: 0 1.5rem 1.5rem; }
.modal-body .form-error { color: var(--destructive-ink); font-size: .85rem; font-weight: 600; margin: 0; }

.pw-wrap { position: relative; display: flex; align-items: center; }
.pw-wrap .input { padding-right: 2.6rem; width: 100%; }
.pw-toggle {
  position: absolute; right: .5rem; width: 30px; height: 30px;
  border: none; background: none; color: var(--muted-foreground);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); transition: color .16s ease;
}
.pw-toggle:hover { color: var(--primary-ink); }

/* Sur mobile : pastille et actions en haut à droite, au-dessus du titre.
   `.topbar-actions` est le dernier enfant du DOM : en column-reverse il remonte
   donc tout seul. Surtout pas d'`order: -1` ici — l'ordre est inversé lui aussi
   et le renverrait en bas. `justify-content: flex-end` colle la pastille au
   bord droit une fois la ligne passée en pleine largeur. */
@media (max-width: 720px) {
  .dash-topbar { flex-direction: column-reverse; align-items: stretch; gap: .85rem; flex-wrap: nowrap; }
  .dash-topbar > div { width: 100%; }
  .topbar-actions { justify-content: flex-end; }
}
@media (max-width: 560px) {
  .admin-chip-text { display: none; }
  .admin-chip { padding: .25rem; }
  .modal-card { max-width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .modal-overlay, .modal-card { transition: opacity .12s linear; }
  .modal-card { transform: none; }
}

/* ---- Carte d'accueil de l'onglet Statistiques ---- */
.welcome-card {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  margin-bottom: 1.5rem;
}
.welcome-card h2 {
  font-family: var(--font-serif); font-weight: 900;
  font-size: clamp(1.4rem, 3vw, 1.9rem); margin-top: .7rem;
}
.welcome-card p { color: var(--muted-foreground); margin-top: .4rem; }
.welcome-glow {
  position: absolute; z-index: -1; top: -70px; right: -50px;
  width: 210px; height: 210px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--primary) 26%, transparent), transparent 70%);
}
@media (prefers-reduced-motion: no-preference) {
  .welcome-card { animation: tileIn .5s var(--ease-out) both; }
  .welcome-glow { animation: glowDrift 10s ease-in-out infinite alternate; }
}

/* ===================================================================
   Accueil — section « Actualités » + fenêtre de nouvelle publication
   =================================================================== */
.news-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.5rem; justify-content: center; }
/* Une ou deux annonces seulement : on centre au lieu de laisser une colonne vide. */
.news-grid:has(> :last-child:nth-child(1)) { grid-template-columns: minmax(0, 420px); }
.news-grid:has(> :last-child:nth-child(2)) { grid-template-columns: repeat(2, minmax(0, 420px)); }
@media (max-width: 940px) { .news-grid, .news-grid:has(> :last-child:nth-child(2)) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) {
  .news-grid, .news-grid:has(> :last-child:nth-child(1)), .news-grid:has(> :last-child:nth-child(2)) { grid-template-columns: minmax(0, 1fr); }
}

.news-card {
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm); color: inherit;
  transition: transform .25s var(--ease-out), box-shadow .25s var(--ease-out), border-color .25s var(--ease-out);
}
.news-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-md); border-color: var(--accent); }
.news-media { aspect-ratio: 16 / 10; background: var(--muted); overflow: hidden; }
.news-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease-out); }
.news-card:hover .news-media img { transform: scale(1.05); }
.news-body { padding: 1.25rem; display: flex; flex-direction: column; gap: .5rem; flex: 1; }
.news-cat { align-self: flex-start; font-size: .7rem; }
.news-body h3 { font-family: var(--font-sans); font-size: 1.02rem; font-weight: 700; line-height: 1.35; }
.news-body p { font-size: .88rem; color: var(--muted-foreground); }
.news-foot { margin-top: auto; padding-top: .6rem; display: flex; align-items: center; justify-content: space-between; font-size: .76rem; color: var(--muted-foreground); }
.news-more { color: var(--primary-ink); font-weight: 700; }

/* --- fenêtre d'annonce --- */
.news-pop-overlay {
  position: fixed; inset: 0; z-index: 120;
  display: flex; align-items: flex-end; justify-content: flex-end;
  /* Marge basse élargie : le bouton flottant « haut de page » occupe ce coin. */
  padding: clamp(1rem, 3vw, 2rem) clamp(1rem, 3vw, 2rem) 5.5rem;
  background: transparent; pointer-events: none;
  opacity: 0; transition: opacity .28s var(--ease-out);
}
.news-pop-overlay.open { opacity: 1; }
.news-pop {
  pointer-events: auto; position: relative;
  width: min(380px, 100%); overflow: hidden;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  transform: translateY(24px) scale(.97);
  transition: transform .4s var(--ease-out-quart);
}
.news-pop-overlay.open .news-pop { transform: none; }
.news-pop-media { aspect-ratio: 16 / 9; background: var(--muted); }
.news-pop-media img { width: 100%; height: 100%; object-fit: cover; }
.news-pop-body { padding: 1.25rem; }
.news-pop-body h3 { font-family: var(--font-sans); font-size: 1.05rem; font-weight: 700; margin-top: .6rem; line-height: 1.35; }
.news-pop-body p { font-size: .86rem; color: var(--muted-foreground); margin-top: .45rem; }
.news-pop-actions { display: flex; gap: .6rem; margin-top: 1.1rem; flex-wrap: wrap; }
.news-pop-badge {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .68rem; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
  padding: .28rem .6rem; border-radius: 999px;
  background: var(--secondary); color: var(--primary-ink);
}
.news-pop-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--primary);
}
.news-pop-close {
  position: absolute; top: .6rem; right: .6rem; z-index: 2;
  width: 32px; height: 32px; border: none; border-radius: 50%; cursor: pointer;
  background: rgba(20,14,16,.55); color: #fff;
  display: flex; align-items: center; justify-content: center;
  transition: background-color .18s var(--ease-out), transform .12s var(--ease-out);
}
.news-pop-close:hover { background: rgba(20,14,16,.8); }
.news-pop-close:active { transform: scale(.92); }

@media (prefers-reduced-motion: no-preference) {
  .news-card { animation: newsIn .5s var(--ease-out) both; }
  @keyframes newsIn { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
  .news-pop-badge::before { animation: badgePulse 2s ease-in-out infinite; }
}
@media (prefers-reduced-motion: reduce) {
  .news-pop { transition: opacity .15s linear; transform: none; }
  .news-card, .news-card:hover { animation: none; transform: none; }
  .news-card:hover .news-media img { transform: none; }
}
@media (max-width: 520px) {
  .news-pop-overlay { align-items: flex-end; justify-content: center; }
  .news-pop { width: 100%; }
}

/* ===================================================================
   Bouton d'action destructrice (partagé par les trois tableaux de bord)
   =================================================================== */
.btn-danger { color: var(--destructive-ink); }
.btn-danger:hover { background: rgba(230,57,70,.1); }

/* ===================================================================
   Emploi du temps du répétiteur (assets/js/planning.js)
   =================================================================== */
.plan-headcard { margin-bottom: 1.25rem; }
.plan-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.25rem; flex-wrap: wrap; }
.plan-head-text h2 { font-family: var(--font-sans); font-size: 1.1rem; font-weight: 700; }
.plan-head-text p { font-size: .86rem; color: var(--muted-foreground); margin-top: .25rem; }
.plan-head-actions { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-left: auto; }

/* Bascule Semaine / Liste, avec un curseur qui glisse sous l'onglet actif */
.plan-views {
  position: relative; display: inline-flex; padding: .25rem;
  background: var(--muted); border-radius: 999px;
}
.plan-view {
  position: relative; z-index: 1; border: none; background: none; cursor: pointer;
  padding: .42rem .95rem; border-radius: 999px;
  font-size: .82rem; font-weight: 700; color: var(--muted-foreground);
  transition: color .2s var(--ease-out);
}
.plan-view.active { color: var(--primary-ink); }
.plan-view-ink {
  position: absolute; z-index: 0; top: .25rem; bottom: .25rem; left: .25rem;
  width: calc(50% - .25rem); border-radius: 999px;
  background: var(--card); box-shadow: var(--shadow-sm);
  transition: transform .32s var(--ease-out-quart);
}
.plan-views:has(.plan-view:last-of-type.active) .plan-view-ink { transform: translateX(100%); }

/* Bandeau de synthèse */
.plan-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: .75rem; margin-top: 1.25rem; }
@media (max-width: 720px) { .plan-stats { grid-template-columns: repeat(2, 1fr); } }
.plan-stat {
  padding: .8rem .9rem; border-radius: var(--r-md);
  background: var(--muted); border: 1px solid transparent;
  transition: border-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.plan-stat:hover { border-color: var(--accent); transform: translateY(-2px); }
.ps-value { display: block; font-family: var(--font-serif); font-size: 1.3rem; font-weight: 900; line-height: 1; }
.ps-label { display: block; margin-top: .3rem; font-size: .74rem; color: var(--muted-foreground); }

/* --- Grille horaire --- */
.plan-board { overflow: hidden; }
.plan-week { display: flex; gap: .5rem; overflow-x: auto; padding-bottom: .35rem; }
.plan-rail { flex: none; width: 44px; display: flex; flex-direction: column; }
/* Copie invisible de l'en-tête de colonne : garantit que la première heure
   tombe pile sur la première ligne, quelle que soit la taille du texte. */
.plan-railhead { background: none !important; visibility: hidden; }
.plan-hour {
  height: var(--plan-hour-h, 58px);
  font-size: .68rem; font-weight: 700; color: var(--muted-foreground); text-align: right;
  padding-right: .4rem;
  /* `transform` centre l'étiquette sur sa ligne SANS décaler les suivantes ;
     une marge négative, elle, se cumulerait d'heure en heure. */
  transform: translateY(-.5em);
}
.plan-hour:last-child { height: 0; }
.plan-days { display: grid; grid-template-columns: repeat(7, minmax(104px, 1fr)); gap: .4rem; flex: 1; min-width: 0; }
/* Sous 1080 px, les colonnes se compriment au lieu d'imposer un défilement
   horizontal : sept jours à ~95 px restent lisibles, un scroll latéral non. */
@media (max-width: 1080px) {
  .plan-days { grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .3rem; }
  .pslot-sub, .pslot-end { display: none; }
}
.plan-col { min-width: 0; }
.plan-colhead {
  display: flex; align-items: baseline; gap: .35rem; justify-content: center;
  padding: .45rem .3rem .5rem; border-radius: var(--r-sm) var(--r-sm) 0 0;
}
.pc-day { font-size: .74rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-foreground); }
.pc-today { font-size: .6rem; font-weight: 700; color: var(--primary-ink); }
.plan-col.is-today .pc-day { color: var(--primary-ink); }
.plan-col.is-today .plan-colhead { background: var(--secondary); }

.plan-colbody {
  position: relative; border-radius: 0 0 var(--r-sm) var(--r-sm);
  /* Colonne volontairement plus sourde que les cartes : sans cet ecart de
     luminance, un cours pale se fondait dans le fond (rapport mesure 1.02). */
  background: color-mix(in srgb, var(--foreground) 14%, var(--muted)); cursor: copy;
  transition: background-color .2s var(--ease-out);
}
.plan-colbody:hover { background: color-mix(in srgb, var(--primary) 7%, var(--muted)); }
.plan-col.is-today .plan-colbody { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 35%, transparent); }
.plan-line { position: absolute; left: 0; right: 0; height: 1px; background: var(--border); opacity: .6; pointer-events: none; }
.plan-empty {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: .72rem; color: var(--muted-foreground); opacity: .5; pointer-events: none;
}

/* --- Carte d'un cours --- */
.plan-slot {
  --tint: var(--primary);
  position: absolute; z-index: 2; overflow: hidden; text-align: left;
  display: flex; flex-direction: column; gap: .1rem;
  padding: .38rem .45rem; margin: 0 2px;
  border: 1px solid color-mix(in srgb, var(--tint) 32%, transparent);
  border-left: 3px solid var(--tint);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--tint) 10%, var(--card));
  box-shadow: var(--shadow-sm); cursor: pointer; color: var(--foreground);
  transition: transform .18s var(--ease-out), box-shadow .18s var(--ease-out), border-color .18s var(--ease-out);
}
.plan-slot:hover { transform: translateY(-2px) scale(1.015); box-shadow: var(--shadow-md); z-index: 5; }
.plan-slot:active { transform: scale(.99); }
.plan-slot:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
/* `--ink` : la teinte ramenée vers la couleur du texte. Les teintes pures
   tombaient sous 2:1 de contraste sur leur fond pâle (l'orange était le pire) ;
   le mélange conserve la couleur tout en restant lisible, et suit
   automatiquement le thème sombre puisqu'il vise --foreground. */
.plan-slot, .plan-lrow { --ink: color-mix(in srgb, var(--tint) 45%, var(--foreground)); }
.pslot-time { font-size: .66rem; font-weight: 800; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pslot-end { font-style: normal; }
.pslot-who { font-size: .76rem; font-weight: 700; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pslot-sub { font-size: .68rem; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pslot-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: .3rem; font-size: .62rem; color: var(--muted-foreground); }
.pslot-lieu { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Les cartes trop courtes masquent la matiere et le pied pour rester lisibles. */
.plan-slot.is-short .pslot-foot, .plan-slot.is-short .pslot-sub { display: none; }

.tint-1 { --tint: #ff7e5f; }
.tint-2 { --tint: #2f9e64; }
.tint-3 { --tint: #4f8ef7; }
.tint-4 { --tint: #f2a541; }
.tint-5 { --tint: #9b6bd6; }
.tint-6 { --tint: #17a2a2; }

/* --- Vue liste --- */
.plan-list { display: flex; flex-direction: column; gap: 1.5rem; }
.plan-none { font-size: .88rem; color: var(--muted-foreground); text-align: center; padding: 2rem 0; }
.plan-ldayname {
  display: flex; align-items: baseline; justify-content: space-between; gap: .75rem;
  font-family: var(--font-sans); font-size: .82rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .05em; color: var(--muted-foreground);
  padding-bottom: .5rem; margin-bottom: .75rem; border-bottom: 1px solid var(--border);
}
.plan-lday.is-today .plan-ldayname { color: var(--primary-ink); border-bottom-color: var(--primary); }
.plan-ldayname span { font-size: .74rem; font-weight: 700; text-transform: none; letter-spacing: 0; }
.plan-lrow {
  --tint: var(--primary);
  width: 100%; display: flex; align-items: center; gap: 1rem; text-align: left;
  padding: .75rem .9rem; margin-bottom: .55rem; cursor: pointer;
  border: 1px solid var(--border); border-left: 3px solid var(--tint);
  border-radius: var(--r-md); background: var(--card); color: var(--foreground);
  transition: transform .18s var(--ease-out), box-shadow .18s var(--ease-out), border-color .18s var(--ease-out);
}
.plan-lrow:hover { transform: translateX(3px); box-shadow: var(--shadow-md); border-color: var(--tint); }
.plr-time { flex: none; width: 4.4rem; font-size: .8rem; font-weight: 800; color: var(--ink); line-height: 1.3; }
.plr-time em { display: block; font-style: normal; font-weight: 600; font-size: .72rem; color: var(--muted-foreground); }
.plr-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .1rem; }
.plr-main strong { font-size: .92rem; }
.plr-main span { font-size: .78rem; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plr-meta { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: .15rem; font-size: .74rem; color: var(--muted-foreground); }
.plr-lieu {
  padding: .12rem .45rem; border-radius: 999px; font-size: .66rem; font-weight: 700;
  background: color-mix(in srgb, var(--tint) 14%, transparent); color: var(--ink);
}

/* --- Formulaire de la modale --- */
.plan-modal { max-width: 560px; }
.plan-form { gap: 1.1rem; }
.pf-field { display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
.pf-field > label { font-size: .78rem; font-weight: 700; color: var(--muted-foreground); }
.pf-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: .75rem; align-items: end; }
.pf-row.pf-row-2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 520px) { .pf-row { grid-template-columns: 1fr 1fr; } .pf-dur { grid-column: 1 / -1; } }
.pf-hint { font-size: .74rem; color: var(--muted-foreground); min-height: 1em; }
.pf-duration {
  display: inline-flex; align-items: center; justify-content: center; min-width: 4.2rem; height: 2.75rem;
  padding: 0 .6rem; border-radius: var(--r-sm);
  background: var(--secondary); color: var(--primary-ink); font-weight: 800; font-size: .86rem;
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
.pf-duration.invalid { background: rgba(230,57,70,.12); color: var(--destructive-ink); }

.pf-days, .pf-lieux { display: flex; flex-wrap: wrap; gap: .4rem; }
.pf-day, .pf-lieu {
  border: 1px solid var(--border); background: var(--card); color: var(--muted-foreground);
  border-radius: 999px; cursor: pointer; font-weight: 700;
  transition: transform .14s var(--ease-out), background-color .18s var(--ease-out),
              color .18s var(--ease-out), border-color .18s var(--ease-out);
}
.pf-day { flex: 1; min-width: 2.6rem; padding: .5rem .2rem; font-size: .76rem; text-align: center; }
.pf-lieu { padding: .45rem .85rem; font-size: .78rem; }
.pf-day:hover, .pf-lieu:hover { border-color: var(--primary); color: var(--foreground); }
.pf-day.active, .pf-lieu.active {
  background: linear-gradient(135deg, var(--primary), var(--accent));
  border-color: transparent; color: var(--primary-foreground);
}
.pf-day:active, .pf-lieu:active { transform: scale(.94); }

.pf-error {
  margin: 0; padding: .6rem .75rem; border-radius: var(--r-sm);
  background: rgba(230,57,70,.1); color: var(--destructive-ink);
  font-size: .82rem; font-weight: 600;
}
.pf-spacer { flex: 1; }
.plan-modal .modal-foot { align-items: center; }
.btn.is-loading { opacity: .65; pointer-events: none; }

/* --- Animations --- */
@media (prefers-reduced-motion: no-preference) {
  .plan-stat { animation: planIn .45s var(--ease-out) both; }
  .plan-slot { animation: slotIn .38s var(--ease-out-quart) both; }
  .plan-lrow { animation: planIn .4s var(--ease-out) both; }
  @keyframes planIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  @keyframes slotIn { from { opacity: 0; transform: translateY(8px) scale(.96); } to { opacity: 1; transform: none; } }
  .pf-error.shake { animation: pfShake .4s var(--ease-out); }
  @keyframes pfShake {
    0%,100% { transform: translateX(0); } 20% { transform: translateX(-5px); }
    40% { transform: translateX(5px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(3px); }
  }
  .just-saved { animation: savedPulse 1.5s var(--ease-out); }
  @keyframes savedPulse {
    0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--tint) 55%, transparent); }
    45%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--tint) 0%, transparent); }
    100% { box-shadow: var(--shadow-sm); }
  }
}
@media (prefers-reduced-motion: reduce) {
  .plan-slot, .plan-lrow, .plan-stat { animation: none; }
  .plan-slot:hover, .plan-lrow:hover, .plan-stat:hover { transform: none; }
  .plan-view-ink { transition: none; }
}

/* --- Mobile : la grille horaire laisse place a la liste par jour --- */
@media (max-width: 760px) {
  .plan-head-actions { width: 100%; }
  .plan-head-actions .btn { flex: 1; justify-content: center; }
  .plan-views { display: none; }
  #planWeekCard { display: none; }
  #planListCard[hidden] { display: block; }
  .plr-meta { display: none; }
}

/* ===================================================================
   Tarifs par niveau (inscription répétiteur) + durées proposées
   =================================================================== */
.field-note { font-size: .82rem; color: var(--muted-foreground); line-height: 1.5; }

.tarif-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
@media (max-width: 820px) { .tarif-grid { grid-template-columns: 1fr; } }
.tarif-card {
  display: flex; flex-direction: column; gap: .6rem;
  padding: 1.1rem; border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--card);
  transition: border-color .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.tarif-card:focus-within { border-color: var(--primary); box-shadow: var(--shadow-sm); }
.tarif-head { display: flex; flex-direction: column; gap: .2rem; }
.tarif-niveau { font-family: var(--font-sans); font-size: .95rem; font-weight: 800; }
.tarif-classes { font-size: .72rem; color: var(--muted-foreground); }
.tarif-etat { font-size: .72rem; color: var(--muted-foreground); }
.tarif-card.requis .tarif-niveau::after {
  content: "requis"; margin-left: .45rem; padding: .1rem .4rem;
  font-size: .62rem; font-weight: 700; letter-spacing: .03em;
  border-radius: 999px; background: var(--secondary); color: var(--primary-ink);
}

/* Durée de référence, signalée sur la puce « 2 h » */
.dur-ref {
  margin-left: .4rem; padding: .08rem .35rem; border-radius: 999px;
  font-size: .6rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  background: var(--secondary); color: var(--primary-ink);
}
.chip-toggle.active .dur-ref { background: rgba(255,255,255,.25); color: #fff; }

/* ===================================================================
   Montants des demandes : bandeau de totaux + colonne chiffrée
   =================================================================== */
.totaux-bar { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 1rem; }
.tot-chip {
  --tc: var(--muted-foreground);
  flex: 1; min-width: 9rem;
  display: flex; flex-direction: column; gap: .15rem;
  padding: .75rem .9rem; border-radius: var(--r-md);
  background: var(--card); border: 1px solid var(--border);
  border-left: 3px solid var(--tc);
}
.tot-chip.ok { --tc: var(--success); }
.tot-chip.wait { --tc: var(--primary); }
.tot-val { font-family: var(--font-serif); font-size: 1.15rem; font-weight: 900; line-height: 1; color: var(--tc); }
.tot-lab { font-size: .74rem; color: var(--muted-foreground); }
.montant-cell { font-weight: 700; white-space: nowrap; cursor: help; }
.montant-cell small { font-weight: 500; color: var(--muted-foreground); }

/* ===================================================================
   Formulaire « Demander ce répétiteur » (fiche publique + espace parent)
   =================================================================== */
.dmd-form { display: flex; flex-direction: column; gap: 1rem; text-align: left; }
.dmd-title { font-family: var(--font-sans); font-size: 1rem; font-weight: 700; }
.dmd-sub { font-size: .8rem; color: var(--muted-foreground); margin-top: -.6rem; }
.dmd-field { display: flex; flex-direction: column; gap: .4rem; }
.dmd-field > label { font-size: .78rem; font-weight: 700; color: var(--muted-foreground); }
.dmd-hint { font-weight: 500; text-transform: none; opacity: .85; }
.dmd-wait { font-size: .82rem; color: var(--muted-foreground); text-align: center; padding: .75rem 0; }
/* Règle de tarif rattachée au choix de durée : elle explique le chiffre qui
   vient de bouger, elle n'est pas un avertissement. */
.dmd-note { margin-top: .5rem; font-size: .76rem; line-height: 1.5; color: var(--muted-foreground); }
.dmd-error {
  margin: 0; padding: .6rem .75rem; border-radius: var(--r-sm);
  background: rgba(230,57,70,.1); color: var(--destructive-ink);
  font-size: .82rem; font-weight: 600;
}

/* Le détail du calcul : le parent voit d'où vient chaque franc. */
.dmd-total { padding: .9rem 1rem; border-radius: var(--r-md); background: var(--muted); }
.dmd-lines { display: flex; flex-direction: column; gap: .35rem; }
.dmd-line { display: flex; justify-content: space-between; gap: 1rem; font-size: .8rem; color: var(--muted-foreground); }
.dmd-line span:last-child { font-weight: 700; color: var(--foreground); }
.dmd-sum {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  margin-top: .6rem; padding-top: .6rem; border-top: 1px solid var(--border);
  font-size: .85rem; font-weight: 700;
}
.dmd-sum strong { font-family: var(--font-serif); font-size: 1.35rem; font-weight: 900; color: var(--primary-ink); }

.dmd-done { text-align: center; padding: 1.25rem .5rem; color: var(--success-ink); }
.dmd-done h3 { font-family: var(--font-sans); font-size: 1rem; font-weight: 700; margin-top: .5rem; color: var(--foreground); }
.dmd-done p { font-size: .84rem; color: var(--muted-foreground); margin-top: .35rem; }
.dmd-done-total { color: var(--foreground) !important; }

@media (prefers-reduced-motion: no-preference) {
  /* Le total tressaute brièvement : on remarque qu'il vient de changer. */
  .bump { animation: totalBump .32s var(--ease-out-quart); }
  @keyframes totalBump {
    0% { transform: scale(1); } 45% { transform: scale(1.09); } 100% { transform: scale(1); }
  }
  .dmd-done svg { animation: doneIn .45s var(--ease-out-quart) both; }
  @keyframes doneIn { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
}
.dmd-sum strong { display: inline-block; transform-origin: right center; }

/* ---- Tarifs classe par classe (inscription répétiteur) ---- */
/* [hidden] doit primer : sinon display:flex le rend visible malgré tout. */
.tarif-vide[hidden] { display: none; }
.tarif-vide {
  display: flex; align-items: center; gap: 1rem;
  padding: 1.5rem; border: 1px dashed var(--border); border-radius: var(--r-lg);
  color: var(--muted-foreground); font-size: .86rem; line-height: 1.55;
}
.tarif-vide svg { flex: none; opacity: .5; }
.tarif-classes-grid { display: flex; flex-direction: column; gap: 1.25rem; }
.tarif-cycle { display: flex; flex-direction: column; gap: .6rem; }
.tc-titre {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--font-sans); font-size: .82rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .05em; color: var(--muted-foreground);
}
.tc-nb {
  padding: .1rem .45rem; border-radius: 999px; font-size: .66rem;
  text-transform: none; letter-spacing: 0; background: var(--secondary); color: var(--primary-ink);
}
.tc-champs { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: .6rem; }
.tarif-classe { display: flex; flex-direction: column; gap: .3rem; }
.tcl-nom { font-size: .78rem; font-weight: 700; }
.tarif-classe .input { height: 2.5rem; }

.tarif-outils {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--border);
}
.tarif-bulk { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; font-size: .8rem; font-weight: 700; color: var(--muted-foreground); }
.tarif-bulk .input { height: 2.4rem; width: 8.5rem; }
.tarif-compte { font-size: .78rem; font-weight: 700; color: var(--muted-foreground); }
.tarif-compte.complet { color: var(--success-ink); }

@media (prefers-reduced-motion: no-preference) {
  .tarif-classe { animation: planIn .35s var(--ease-out) both; }
  .input.flash { animation: champFlash .5s var(--ease-out); }
  @keyframes champFlash {
    0% { background-color: var(--secondary); } 100% { background-color: transparent; }
  }
}
@media (prefers-reduced-motion: reduce) { .tarif-classe { animation: none; } }

/* Rythme d'une demande : ce que le répétiteur doit voir avant d'accepter */
.rythme-cell { line-height: 1.35; }
.ryt-ligne { display: block; font-size: .78rem; color: var(--muted-foreground); white-space: nowrap; }
.ryt-ligne strong { color: var(--foreground); }
.ryt-total {
  display: inline-block; margin-top: .2rem; padding: .1rem .45rem;
  border-radius: 999px; font-size: .68rem; font-weight: 700;
  background: var(--secondary); color: var(--primary-ink); white-space: nowrap;
}

/* ---- Administration : plannings de tous les répétiteurs ---- */
.plannings-host { display: grid; grid-template-columns: repeat(auto-fill, minmax(370px, 1fr)); gap: 1rem; }
@media (max-width: 520px) { .plannings-host { grid-template-columns: 1fr; } }
.apl-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm); overflow: hidden;
  transition: box-shadow .2s var(--ease-out), border-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.apl-card:hover { box-shadow: var(--shadow-md); border-color: var(--accent); transform: translateY(-2px); }
.apl-head { display: flex; align-items: center; gap: .75rem; padding: .9rem 1rem; border-bottom: 1px solid var(--border); }
.apl-avatar { width: 40px; height: 40px; border-radius: 50%; flex: none; object-fit: cover; }
.apl-init {
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: .82rem; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
}
.apl-ident { display: flex; flex-direction: column; gap: .1rem; min-width: 0; flex: 1; }
.apl-ident strong { font-size: .92rem; }
.apl-meta { font-size: .74rem; color: var(--muted-foreground); }
.apl-heures { flex: none; font-family: var(--font-serif); font-weight: 900; font-size: 1.05rem; color: var(--primary-ink); }
.apl-heures small { font-family: var(--font-sans); font-size: .62rem; font-weight: 600; color: var(--muted-foreground); }

.apl-semaine { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; padding: .6rem; background: var(--muted); }
.apl-jour {
  display: flex; flex-direction: column; gap: .25rem; min-width: 0;
  padding: .4rem .25rem; border-radius: var(--r-sm); background: var(--card);
}
.apl-jour.vide { background: transparent; }
.apl-jnom { font-size: .6rem; font-weight: 800; text-transform: uppercase; color: var(--muted-foreground); text-align: center; }
.apl-slot {
  display: flex; flex-direction: column; gap: .05rem; padding: .22rem .25rem;
  border-radius: 4px; border-left: 2px solid var(--primary);
  background: var(--secondary); cursor: help; min-width: 0;
}
.apl-h { font-size: .58rem; font-weight: 800; color: var(--primary-ink); }
.apl-qui { font-size: .58rem; color: var(--foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.apl-libre { text-align: center; font-size: .7rem; color: var(--muted-foreground); opacity: .4; }

@media (prefers-reduced-motion: no-preference) {
  .apl-card { animation: planIn .4s var(--ease-out) both; }
}
@media (prefers-reduced-motion: reduce) {
  .apl-card { animation: none; }
  .apl-card:hover { transform: none; }
}

/* ===================================================================
   Détail d'une demande — fenêtre partagée répétiteur / administration
   =================================================================== */
.dd-overlay {
  position: fixed; inset: 0; z-index: 130;
  display: flex; align-items: center; justify-content: center; padding: 1rem;
  background: rgba(20,14,16,.55); backdrop-filter: blur(3px);
  opacity: 0; transition: opacity .24s var(--ease-out);
}
.dd-overlay.open { opacity: 1; }
.dd-card {
  width: 100%; max-width: 540px; max-height: 90vh; overflow: auto;
  display: flex; flex-direction: column;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  transform: translateY(14px) scale(.97); opacity: 0;
  transition: transform .32s var(--ease-out-quart), opacity .24s var(--ease-out);
}
.dd-overlay.open .dd-card { transform: none; opacity: 1; }

.dd-head {
  display: flex; align-items: center; gap: .75rem;
  padding: 1.1rem 1.25rem; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; background: var(--card); z-index: 1;
  border-radius: var(--r-xl) var(--r-xl) 0 0;
}
.dd-avatar {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: .85rem; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
}
.dd-ident { display: flex; flex-direction: column; gap: .1rem; min-width: 0; flex: 1; }
.dd-ident strong { font-size: .98rem; }
.dd-sub { font-size: .76rem; color: var(--muted-foreground); }
.dd-close {
  flex: none; width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--border); background: var(--card); color: var(--muted-foreground);
  display: inline-flex; align-items: center; justify-content: center;
  transition: color .18s ease, border-color .18s ease, transform .12s var(--ease-out);
}
.dd-close:hover { color: var(--foreground); border-color: var(--primary); }
.dd-close:active { transform: scale(.92); }

.dd-body { padding: 1.25rem; display: flex; flex-direction: column; gap: 1.4rem; }
.dd-bloc h4 {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted-foreground);
  padding-bottom: .45rem; margin-bottom: .6rem; border-bottom: 1px solid var(--border);
}
.dd-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: .3rem 0; }
.dd-k { font-size: .82rem; color: var(--muted-foreground); flex: none; }
.dd-v { font-size: .88rem; text-align: right; display: flex; flex-wrap: wrap; gap: .3rem; justify-content: flex-end; }
.dd-chip {
  padding: .12rem .5rem; border-radius: 999px; font-size: .74rem; font-weight: 600;
  background: var(--secondary); color: var(--primary-ink);
}
.dd-tag { font-size: .72rem; color: var(--muted-foreground); }

.dd-calcul { padding: .85rem 1rem; border-radius: var(--r-md); background: var(--muted); }
.dd-calc-l { display: flex; justify-content: space-between; gap: 1rem; font-size: .8rem; color: var(--muted-foreground); padding: .15rem 0; }
.dd-calc-l span:last-child { font-weight: 700; color: var(--foreground); }
.dd-calc-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  margin-top: .55rem; padding-top: .55rem; border-top: 1px solid var(--border);
  font-size: .84rem; font-weight: 700;
}
.dd-calc-total strong { font-family: var(--font-serif); font-size: 1.3rem; font-weight: 900; color: var(--primary-ink); }
.dd-msg { font-size: .86rem; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }

.dd-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: .7rem;
  padding: 1rem 1.25rem; border-top: 1px solid var(--border);
  position: sticky; bottom: 0; background: var(--card);
}
.dd-note { margin-right: auto; font-size: .76rem; color: var(--muted-foreground); }

/* La ligne devient cliquable dès lors qu'un détail existe. */
tr[data-demande] { cursor: pointer; }
tr[data-demande]:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

@media (prefers-reduced-motion: no-preference) {
  .dd-bloc { animation: planIn .38s var(--ease-out) both; }
  .dd-bloc:nth-child(2) { animation-delay: .05s; }
  .dd-bloc:nth-child(3) { animation-delay: .1s; }
  .dd-bloc:nth-child(4) { animation-delay: .15s; }
}
@media (prefers-reduced-motion: reduce) {
  .dd-card { transform: none; transition: opacity .12s linear; }
  .dd-bloc { animation: none; }
}
@media (max-width: 560px) { .dd-card { max-width: 100%; } .dd-foot { flex-wrap: wrap; } }

/* ---- Recherche de proximité ---- */
.geo-group .btn { justify-content: center; }
.geo-rayon { display: flex; flex-direction: column; gap: .35rem; margin-top: .75rem; font-size: .8rem; color: var(--muted-foreground); }
.geo-rayon strong { color: var(--primary-ink); }
.geo-rayon input[type="range"] { width: 100%; accent-color: var(--primary); }
.geo-clear {
  margin-top: .5rem; padding: 0; border: none; background: none; cursor: pointer;
  font-size: .74rem; font-weight: 600; color: var(--muted-foreground); text-decoration: underline;
}
.geo-clear:hover { color: var(--destructive-ink); }
.geo-etat { margin-top: .5rem; font-size: .74rem; line-height: 1.45; color: var(--muted-foreground); }
.geo-etat.ok { color: var(--success-ink); }
.geo-etat.ko { color: var(--destructive-ink); }

/* Distance affichée sur la carte du répétiteur */
.dist-badge {
  position: absolute; left: .55rem; bottom: .55rem; z-index: 2;
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .18rem .5rem; border-radius: 999px;
  font-size: .68rem; font-weight: 800;
  background: rgba(20,14,16,.72); color: #fff; backdrop-filter: blur(2px);
}
.tutor-card .avatar-wrap { position: relative; }

/* Couverture GPS du référentiel (administration) */
.chip.geo-complet { border-color: var(--success); }
.chip.geo-partiel { border-color: var(--primary); }
.chip.geo-absent { opacity: .68; border-style: dashed; }

/* ===================================================================
   Fiche « contrat » côté parent (assets/js/contrat.js)
   Rayons concentriques : carte 20px → blocs 14px → puces 10px.
   =================================================================== */
.ct-card { max-width: 600px; }
.ct-attente {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1rem; padding: 3rem 2rem; text-align: center;
  font-size: .9rem; color: var(--muted-foreground);
}
.ct-spinner {
  width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid var(--border); border-top-color: var(--primary);
  animation: ctSpin .8s linear infinite;
}
@keyframes ctSpin { to { transform: rotate(360deg); } }

.ct-head {
  display: flex; align-items: center; gap: .85rem;
  padding: 1.15rem 1.25rem; border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 2; background: var(--card);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
}
.ct-photo {
  flex: none; width: 52px; height: 52px; border-radius: 50%; object-fit: cover;
  /* Contour pur noir/blanc : un neutre teinté prendrait la couleur du fond
     et se lirait comme une salissure sur le bord de l'image. */
  outline: 1px solid rgba(0, 0, 0, .1); outline-offset: -1px;
}
.dark .ct-photo { outline-color: rgba(255, 255, 255, .1); }
.ct-photo-init {
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 1rem; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
  outline: none;
}
.ct-ident { display: flex; flex-direction: column; gap: .15rem; min-width: 0; flex: 1; }
.ct-ident strong { font-size: 1.02rem; text-wrap: balance; }
.ct-sub { font-size: .78rem; color: var(--muted-foreground); }

.ct-body { padding: 1.25rem; display: flex; flex-direction: column; gap: 1.5rem; }
.ct-bloc h4 {
  font-family: var(--font-sans); font-size: .72rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted-foreground);
  padding-bottom: .45rem; margin-bottom: .7rem; border-bottom: 1px solid var(--border);
}
.ct-row { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; padding: .32rem 0; }
.ct-k { font-size: .82rem; color: var(--muted-foreground); flex: none; }
.ct-v { font-size: .88rem; text-align: right; display: flex; flex-wrap: wrap; gap: .3rem; justify-content: flex-end; }
.ct-v a { color: var(--primary-ink); font-weight: 600; }
.ct-vide { font-size: .84rem; line-height: 1.55; color: var(--muted-foreground); text-wrap: pretty; }
.ct-chip-pale { background: var(--muted); color: var(--muted-foreground); }

/* --- le montant --- */
.ct-montant {
  /* En colonne : l'unite precede le chiffre, comme partout ailleurs. */
  display: flex; flex-direction: column; align-items: flex-start; gap: .1rem; margin-bottom: .85rem;
  padding: 1rem 1.15rem; border-radius: 14px;
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--primary) 12%, var(--card)),
    color-mix(in srgb, var(--accent) 9%, var(--card)));
  border: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
}
.ct-montant-val { font-family: var(--font-serif); font-size: 1.85rem; font-weight: 900; line-height: 1.05; color: var(--primary-ink); font-variant-numeric: tabular-nums; }
.ct-montant-unite { font-size: .74rem; font-weight: 700; color: var(--muted-foreground); text-transform: uppercase; letter-spacing: .04em; }
.ct-detail { padding: 0 .2rem; }
.ct-detail-l {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: .8rem; color: var(--muted-foreground); padding: .18rem 0;
}
.ct-detail-l span:last-child { font-weight: 700; color: var(--foreground); }

/* --- semaine --- */
.ct-semaine { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .3rem; }
.ct-jour {
  display: flex; flex-direction: column; align-items: center; gap: .3rem;
  padding: .5rem .2rem; border-radius: 10px;
  background: var(--muted); min-height: 76px;
}
.ct-jour.a-cours {
  background: color-mix(in srgb, var(--primary) 10%, var(--card));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 26%, transparent);
}
.ct-jour-nom {
  font-size: .64rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted-foreground);
}
.ct-jour.a-cours .ct-jour-nom { color: var(--primary-ink); }
.ct-creneau { display: flex; flex-direction: column; align-items: center; line-height: 1.25; }
.ct-creneau strong { font-size: .7rem; font-weight: 800; color: var(--foreground); }
.ct-creneau em { font-style: normal; font-size: .62rem; color: var(--muted-foreground); }
.ct-creneau-mat {
  font-size: .58rem; color: var(--muted-foreground); max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ct-libre { font-size: .7rem; color: var(--muted-foreground); opacity: .45; }
.ct-semaine-total { margin-top: .7rem; font-size: .8rem; color: var(--muted-foreground); text-align: center; }
.ct-semaine-total strong { color: var(--primary-ink); }

/* --- historique --- */
.ct-histo {
  display: grid; grid-template-columns: auto 1fr auto auto; gap: .7rem; align-items: center;
  padding: .5rem 0; font-size: .8rem; border-bottom: 1px solid var(--border);
}
.ct-histo:last-child { border-bottom: none; }
.ct-histo span:nth-child(2) { color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* --- la carte devient actionnable --- */
.tutor-card-action {
  display: flex; align-items: center; gap: .5rem; margin-top: .75rem;
}
.tutor-card-action .btn { flex: 1; justify-content: center; min-height: 40px; }

@media (prefers-reduced-motion: no-preference) {
  /* Entrée fractionnée : chaque bloc arrive après le précédent plutôt que
     d'animer le conteneur d'un seul tenant. */
  .ct-bloc { animation: ctIn .42s cubic-bezier(.2, 0, 0, 1) both; }
  @keyframes ctIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
  .ct-jour { transition-property: transform, background-color; transition-duration: .2s; transition-timing-function: cubic-bezier(.2, 0, 0, 1); }
  .ct-jour.a-cours:hover { transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .ct-bloc { animation: none; }
  .ct-spinner { animation-duration: 2s; }
}
@media (max-width: 560px) {
  .ct-card { max-width: 100%; }
  .ct-semaine { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ct-histo { grid-template-columns: 1fr auto; row-gap: .2rem; }
}

/* ===================================================================
   Séances : pointage du répétiteur, confirmation du parent
   Rayons concentriques : carte 14px → puces 8px.
   =================================================================== */
.seance-groupe {
  display: flex; align-items: center; gap: .5rem;
  font-family: var(--font-sans); font-size: .74rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted-foreground);
  margin: 1.5rem 0 .8rem;
}
.seance-groupe:first-child { margin-top: 0; }
.seance-groupe span {
  padding: .1rem .45rem; border-radius: 999px;
  background: var(--primary); color: var(--primary-foreground);
  font-size: .7rem; letter-spacing: 0;
}

.seance-card {
  display: grid;
  grid-template-columns: 11rem minmax(0, 1fr) 12rem auto;
  gap: 1.25rem; align-items: center;
  padding: 1rem 1.15rem; margin-bottom: .7rem;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 14px;
  /* Ombre plutôt que bordure marquée : elle s'adapte au fond. */
  box-shadow: 0 1px 2px rgba(20, 14, 16, .04);
  transition-property: transform, box-shadow, border-color;
  transition-duration: .2s;
  transition-timing-function: cubic-bezier(.2, 0, 0, 1);
}
.seance-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(20, 14, 16, .08); }
.seance-card.aujourdhui {
  border-color: color-mix(in srgb, var(--primary) 40%, transparent);
  background: color-mix(in srgb, var(--primary) 4%, var(--card));
}

.sc-quand { display: flex; flex-direction: column; gap: .15rem; }
.sc-jour { font-size: .72rem; color: var(--muted-foreground); text-transform: capitalize; }
.seance-card.aujourdhui .sc-jour { color: var(--primary-ink); font-weight: 700; }
.sc-heure { font-size: .96rem; font-weight: 800; }
.sc-duree { font-size: .72rem; color: var(--muted-foreground); }

.sc-qui { display: flex; flex-direction: column; gap: .12rem; min-width: 0; }
.sc-qui strong { font-size: .92rem; }
.sc-qui span { font-size: .8rem; color: var(--muted-foreground); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-mot { font-style: italic; }

.sc-etat { display: flex; flex-direction: column; align-items: flex-start; gap: .3rem; }
.sc-aide { font-size: .7rem; color: var(--muted-foreground); line-height: 1.35; text-wrap: pretty; }

.sc-actions { display: flex; flex-direction: column; gap: .45rem; align-items: stretch; }
.sc-actions .btn { justify-content: center; white-space: nowrap; min-height: 40px; }
.sc-actions .btn { transition-property: background-color, border-color, color, transform, box-shadow; }
.sc-actions .btn:active { transform: scale(.96); }
.sc-attente { font-size: .7rem; color: var(--muted-foreground); text-align: right; max-width: 9rem; text-wrap: pretty; }

@media (prefers-reduced-motion: no-preference) {
  .seance-card { animation: scIn .42s cubic-bezier(.2, 0, 0, 1) both; }
  @keyframes scIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
}
@media (prefers-reduced-motion: reduce) {
  .seance-card { animation: none; }
  .seance-card:hover { transform: none; }
}
@media (max-width: 900px) {
  .seance-card { grid-template-columns: 1fr 1fr; row-gap: .9rem; }
  .sc-actions { grid-column: 1 / -1; flex-direction: row; }
  .sc-actions .btn { flex: 1; }
  .sc-attente { text-align: left; max-width: none; }
}
@media (max-width: 560px) {
  .seance-card { grid-template-columns: 1fr; }
}

/* ===================================================================
   Cloche de notifications (partagée par les trois tableaux de bord)
   =================================================================== */
.notif-vide { padding: 1.75rem 1rem; text-align: center; font-size: .84rem; color: var(--muted-foreground); }
.notif-row {
  display: flex; gap: .7rem; width: 100%; text-align: left;
  padding: .8rem 1rem; border: none; border-bottom: 1px solid var(--border);
  background: none; cursor: pointer; color: inherit;
  transition-property: background-color;
  transition-duration: .16s;
}
.notif-row:last-child { border-bottom: none; }
.notif-row:hover { background: var(--muted); }
.notif-row.non-lue { background: color-mix(in srgb, var(--primary) 6%, transparent); }
.notif-row.non-lue .nr-titre::after {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-left: .4rem;
  border-radius: 50%; background: var(--primary); vertical-align: middle;
}
.nr-icone {
  flex: none; width: 30px; height: 30px; border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  background: var(--secondary); color: var(--primary-ink);
}
.nr-corps { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.nr-titre { font-size: .84rem; font-weight: 700; }
.nr-msg { font-size: .78rem; color: var(--muted-foreground); line-height: 1.4; text-wrap: pretty; }
.nr-quand { font-size: .7rem; color: var(--muted-foreground); opacity: .8; margin-top: .15rem; }

@media (prefers-reduced-motion: no-preference) {
  .notif-row { animation: scIn .3s cubic-bezier(.2, 0, 0, 1) both; }
}

/* ===================================================================
   Suivi des séances (administration)
   =================================================================== */
.assidu-row { display: flex; align-items: center; gap: .9rem; padding: .7rem 0; border-bottom: 1px solid var(--border); }
.assidu-row:last-child { border-bottom: none; }
.assidu-nom { font-size: .86rem; font-weight: 600; width: 11rem; flex: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.assidu-piste { flex: 1; height: 9px; border-radius: 999px; background: var(--muted); overflow: hidden; display: flex; }
.assidu-part { height: 100%; }
.assidu-part.ok { background: var(--success); }
.assidu-part.ko { background: var(--destructive); }
.assidu-part.litige { background: var(--primary); }
.assidu-val { font-size: .8rem; font-weight: 700; width: 3.5rem; text-align: right; flex: none; }
.assidu-detail { font-size: .72rem; color: var(--muted-foreground); width: 9rem; flex: none; text-align: right; }
@media (max-width: 720px) {
  .assidu-row { flex-wrap: wrap; }
  .assidu-nom { width: 100%; }
  .assidu-detail { width: auto; }
}

/* Cloche de notifications — partagée par les trois tableaux de bord */
/* ---- Cloche de notifications ---- */
.notif-wrap { position: relative; }
.notif-btn {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--card); color: var(--foreground);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: border-color .18s var(--ease-out), transform .12s var(--ease-out), background-color .18s var(--ease-out);
}
.notif-btn:hover { border-color: var(--primary); color: var(--primary-ink); }
.notif-btn:active { transform: scale(.94); }
.notif-badge {
  position: absolute; top: -3px; right: -3px; min-width: 18px; height: 18px; padding: 0 .25rem;
  border-radius: 999px; background: var(--destructive); color: #fff;
  font-size: .66rem; font-weight: 800; line-height: 18px; text-align: center;
  font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: no-preference) {
  .notif-badge { animation: badgePulse 2.4s ease-in-out infinite; }
  @keyframes badgePulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.14); } }
}
.notif-pop {
  position: absolute; right: 0; top: calc(100% + .5rem); z-index: 60;
  width: min(340px, 90vw); max-height: 380px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  animation: fadeUp .2s var(--ease-out);
}
.notif-pop-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .85rem 1rem; border-bottom: 1px solid var(--border); }
.notif-row { display: flex; gap: .7rem; padding: .8rem 1rem; border-bottom: 1px solid var(--border); }
.notif-row:last-child { border-bottom: none; }
.notif-row .nr-amount { font-weight: 800; color: var(--primary-ink); white-space: nowrap; }
.notif-row .nr-who { font-size: .86rem; font-weight: 600; }
.notif-row .nr-sub { font-size: .76rem; color: var(--muted-foreground); }
@media (prefers-reduced-motion: reduce) { .notif-pop { animation: none; } }

/* Sur petit écran, l'ancrage `right: 0` sur une cloche de 42 px poussait le
   panneau de 340 px hors de l'écran PAR LA GAUCHE — mesuré de x=-130 à x=210
   sur 390 px. Un débordement négatif ne crée aucune barre de défilement : il
   passait donc inaperçu, le contenu simplement rogné.
   Le panneau devient une feuille calée sur les deux bords. */
@media (max-width: 560px) {
  .notif-pop {
    position: fixed;
    top: calc(var(--entete-h, 4.5rem) + .5rem);
    left: .75rem; right: .75rem;
    width: auto; max-height: 70vh;
  }
}

/* ===================================================================
   Pastille de session sur les pages publiques
   Rayon extérieur 999px, avatar 50 % : concentriques par construction.
   =================================================================== */
.session-chip {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .3rem .8rem .3rem .3rem;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--card); color: inherit; text-decoration: none;
  min-height: 40px;
  transition-property: border-color, box-shadow, transform;
  transition-duration: .18s;
  transition-timing-function: cubic-bezier(.2, 0, 0, 1);
}
.session-chip:hover { border-color: var(--primary); box-shadow: var(--shadow-sm); }
.session-chip:active { transform: scale(.96); }
.session-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: .72rem; color: var(--primary-foreground);
  background: linear-gradient(135deg, var(--primary), var(--accent));
  background-size: cover; background-position: center;
}
.session-texte { display: flex; flex-direction: column; line-height: 1.1; text-align: left; }
.session-texte .sc-hi {
  font-size: .58rem; color: var(--muted-foreground);
  text-transform: uppercase; letter-spacing: .05em;
}
.session-texte strong { font-size: .82rem; }
@media (max-width: 560px) {
  .session-texte { display: none; }
  .session-chip { padding: .28rem; }
}

/* ===================================================================
   Échanger avec le répétiteur : un seul bouton, vers la messagerie
   ===================================================================
   Trois boutons vivaient ici — Appeler, WhatsApp, E-mail — avec leurs
   couleurs de marque. Ils ont disparu avec les coordonnées : les échanges
   restent dans l'application. */
.ct-ecrire {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px; margin-bottom: .6rem; text-decoration: none;
}
.ct-ecrire svg { flex: none; }

/* ===================================================================
   Formulaire « Mon profil » — reprend l'inscription
   =================================================================== */
.profil-form {
  display: flex; flex-direction: column; gap: 1.25rem;
  /* Même largeur que le formulaire d'inscription (900 px) : sur un panneau de
     1100 px, les champs s'étiraient à 508 px — un « Âge » à deux chiffres
     occupait la moitié de l'écran et l'œil devait traverser tout le vide. */
  max-width: 900px;
}
.profil-form .form-section { margin: 0; }
.profil-form .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* La requête média générique de `.form-grid` a une spécificité plus faible :
   sans ce rappel, le profil restait sur deux colonnes de 165 px sur mobile. */
@media (max-width: 640px) {
  .profil-form .form-grid { grid-template-columns: minmax(0, 1fr); }
}
.profil-actions {
  display: flex; justify-content: flex-end; gap: .75rem; flex-wrap: wrap;
  padding-top: .25rem;
}
.profil-actions .btn { min-height: 44px; }
.profil-actions .btn { transition-property: background-color, border-color, color, transform, box-shadow; }
.profil-actions .btn:active { transform: scale(.96); }
.pf-error.ok { background: rgba(47, 158, 100, .12); color: var(--success-ink); }

@media (prefers-reduced-motion: no-preference) {
  .profil-form .form-section { animation: ctIn .4s cubic-bezier(.2, 0, 0, 1) both; }
  .profil-form .form-section:nth-child(2) { animation-delay: .05s; }
  .profil-form .form-section:nth-child(3) { animation-delay: .1s; }
  .profil-form .form-section:nth-child(4) { animation-delay: .15s; }
  .profil-form .form-section:nth-child(5) { animation-delay: .2s; }
}
@media (prefers-reduced-motion: reduce) {
  .profil-form .form-section { animation: none; }
  .session-chip:hover { transform: none; }
}

/* ===================================================================
   Stabilité du chargement : réserver la place des images
   Sans rapport d'aspect, une image occupe 0 px puis pousse tout le
   contenu à son arrivée. Ces règles figent l'emprise à l'avance.
   =================================================================== */
.hero-visual img, .about-visual img, .auth-visual img,
.content-visual img, .cta-visual img { aspect-ratio: 4 / 3; object-fit: cover; width: 100%; }
.ann-thumb-wrap img, .news-media img { aspect-ratio: 16 / 10; }
.ann-lead-media img, .read-hero img { aspect-ratio: 16 / 9; }
.avatar, .ct-photo, .msg-avatar, .admin-avatar { aspect-ratio: 1; }
.testi-card img, .tcar-card img { aspect-ratio: 1; object-fit: cover; }
.page-banner img { aspect-ratio: 21 / 9; object-fit: cover; width: 100%; }
.tcard-avatar, .avatar-initials, .rev-avatar { aspect-ratio: 1; object-fit: cover; }
/* Ces avatars vivent dans des rangées `display: flex`, dont l'alignement par
   défaut est `stretch`. Combiné au `height: auto` de la règle ci-dessous —
   qui l'emporte en spécificité sur toute hauteur fixée par une classe — une
   photo carrée de 42 px s'étirait à 102 px et le `border-radius: 50%` en
   faisait une ellipse. `align-self` suffit à l'empêcher, sans toucher à la
   protection anti-saut. */
img.tcard-avatar, img.avatar-initials, img.rev-avatar { align-self: center; }

/* Un état vide honnête, plutôt qu'un exemple inventé. La règle était recopiée
   dans deux pages et déjà employée par `admin.js` : sa place est ici. */
.empty-note { font-size: .85rem; color: var(--muted-foreground); font-style: italic; }
.profile-photo img, .photo-preview img { aspect-ratio: 1; object-fit: cover; }
/* Toute image encore sans consigne garde au moins un ratio par défaut. */
img:not([width]):not([height]) { max-width: 100%; height: auto; }

/* ===================================================================
   Mise en page des formulaires — partagée
   Inscription ET « Mon profil » émettent le même balisage : ces règles
   vivaient dans les <style> des pages d'inscription, si bien que le
   formulaire de profil s'affichait sans grille, chaque champ occupant
   toute la largeur.
   =================================================================== */
.form-section { padding: 2rem; margin-bottom: 1.75rem; scroll-margin-top: 6rem; }
.form-section .fs-head { display: flex; align-items: center; gap: .85rem; margin-bottom: 1.5rem; }
.form-section .fs-num {
  width: 36px; height: 36px; border-radius: var(--r-sm);
  background: var(--secondary); color: var(--primary-ink);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-weight: 900; flex: none;
}
.form-section h2 { font-family: var(--font-sans); font-size: 1.1rem; font-weight: 700; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

/* ===================================================================
   [hidden] doit primer sur les `display` des composants.
   Placée en fin de feuille, cette règle gagne à égalité de spécificité
   contre `.btn`, `.tarif-vide`, etc. — sans `!important`, ce qui laisse
   les cas volontaires (ex. `#planListCard[hidden]` sur mobile) l'emporter
   grâce à leur spécificité supérieure.
   =================================================================== */
[hidden] { display: none; }

/* Carte de répétiteur dans l'espace parent (non cliquable en bloc :
   le bouton « Voir » porte l'action, la carte reste un conteneur). */
.tutor-card-dash { cursor: default; }
.tutor-card-dash .btn { transition-property: background-color, border-color, color, transform, box-shadow; }
.tutor-card-dash .btn:active { transform: scale(.96); }
.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
  padding: 3rem 1.5rem; text-align: center;
  font-size: .9rem; color: var(--muted-foreground);
}
@media (prefers-reduced-motion: no-preference) {
  .tutor-card-dash { animation: ctIn .42s cubic-bezier(.2, 0, 0, 1) both; }
}

/* Une puce de quartier porte deux actions explicites : crayon et croix. */
.quartier-chip {
  display: inline-flex; align-items: center; gap: .5rem;
  padding-right: .5rem;
  transition-property: border-color, box-shadow; transition-duration: .16s;
}
.quartier-chip:hover { border-color: var(--primary); box-shadow: var(--shadow-sm); }
.quartier-chip .qc-nom { margin-right: .3rem; }
.qc-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex: none;
  border: none; border-radius: 50%; background: none; cursor: pointer;
  color: var(--muted-foreground); font-size: .95rem; line-height: 1;
  transition-property: background-color, color, transform;
  transition-duration: .15s;
}
.qc-btn:hover { background: var(--card); color: var(--primary-ink); }
.qc-btn[data-supprimer]:hover { color: var(--destructive-ink); }
.qc-btn:active { transform: scale(.9); }
/* La zone tapable dépasse le rond visible : deux boutons de 24 px côte à côte
   seraient sinon trop serrés au doigt. Elle doit être CENTRÉE — sans `top`,
   `left` ni `transform` elle partait du coin haut-gauche, débordait de 10 px
   vers le bas-droite et empiétait sur le bouton voisin.
   Taille bornée par l'écart : deux cibles adjacentes ne doivent jamais se
   recouvrir, donc 24 px de bouton + 8 px d'écart = 32 px au maximum. */
.qc-btn { position: relative; }
.qc-btn::after {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 32px; height: 32px;
}
.form-modale .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-modale .form-grid > p { grid-column: 1 / -1; }
@media (max-width: 520px) { .form-modale .form-grid { grid-template-columns: 1fr; } }

/* ===================================================================
   Zones tactiles : étendre sans grossir
   Une puce de 8 px reste visuellement une puce, mais devient tapable.
   Le pseudo-élément agrandit la cible sans toucher à la mise en page.
   =================================================================== */
.tcar-dot { position: relative; }
.tcar-dot::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}

/* Les liens du menu mobile sont des entrées de navigation, pas du texte
   courant : ils doivent offrir la même prise qu'un bouton. */
@media (max-width: 920px) {
  .mobile-menu a { min-height: 44px; display: flex; align-items: center; }
}

/* Pied de page : les liens sont serrés les uns sous les autres, ce qui rend
   la frappe imprécise sur mobile. */
.site-footer a { display: inline-block; padding-block: .35rem; }
.site-footer .f-links a { min-height: 40px; display: flex; align-items: center; }

/* ===================================================================
   Envoi de fichiers : la jauge, c'est le fichier lui-même
   -------------------------------------------------------------------
   Un rond qui tourne ne dit ni où on en est, ni si ça avance. Ici
   l'aperçu apparaît immédiatement, voilé, et se découvre du bas vers
   le haut au rythme des octets qui partent : ce qui se remplit est
   littéralement ce qui est en train d'être envoyé. Sur une connexion
   mobile à Abidjan, un fichier de plusieurs mégaoctets prend des
   dizaines de secondes — l'attente doit être lisible.

   Seuls `transform` et `opacity` sont animés : rien ne quitte le GPU.
   =================================================================== */

/* Réservé aux lecteurs d'écran : l'information ne doit jamais reposer
   uniquement sur la couleur ou sur une icône. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.up-hote { position: relative; }

.up-jauge {
  position: absolute; inset: 0; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  /* Le conteneur peut être un rond (aperçu de 84 px) comme une carte :
     hériter du rayon évite d'avoir à le connaître. */
  border-radius: inherit;
  background: var(--muted);
  opacity: 0; transform: scale(.96);
  transition: opacity .2s var(--ease-out), transform .2s var(--ease-out);
}
.up-jauge.est-ouverte { opacity: 1; transform: none; }

.up-apercu {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* Un liseré discret, comme sur toutes les images du site. */
  outline: 1px solid rgba(0, 0, 0, .1); outline-offset: -1px;
}
.dark .up-apercu { outline-color: rgba(255, 255, 255, .1); }

/* Le voile se rétracte vers le haut : origine en haut, scaleY de 1 → 0. */
.up-voile {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom, rgba(20, 14, 16, .72), rgba(20, 14, 16, .58));
  transform-origin: top;
  transform: scaleY(1);
  /* La progression traduit une quantité réelle : elle avance à vitesse
     constante, c'est le seul cas où `linear` est le bon choix. */
  transition: transform .18s linear;
}

.up-etat {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  color: #fff;
  font-family: var(--font-sans); font-size: .78rem; font-weight: 800;
  letter-spacing: .01em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}
/* Le pourcentage change dix fois par seconde : sans chasse fixe, la
   largeur du texte danse à chaque chiffre. */
.up-pct { font-variant-numeric: tabular-nums; }

.up-coche, .up-croix {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  animation: upSurgir .22s var(--ease-out) both;
}
.up-coche { background: var(--success); color: #fff; }
.up-coche svg { width: 16px; height: 16px; }
.up-croix { background: var(--destructive); color: #fff; font-size: 1rem; }
/* Depuis .95 et non 0 : un élément qui naît d'un point n'a l'air de rien. */
@keyframes upSurgir {
  from { opacity: 0; transform: scale(.95); }
  to   { opacity: 1; transform: none; }
}

.up-jauge.est-finie .up-voile { opacity: 0; }
.up-jauge.est-en-echec { background: var(--destructive-soft, var(--muted)); }

/* Variante compacte : vignettes de galerie, où 28 px seraient trop gros. */
.up-jauge.up-mini .up-etat { font-size: .68rem; }
.up-jauge.up-mini .up-coche, .up-jauge.up-mini .up-croix { width: 22px; height: 22px; }

@media (prefers-reduced-motion: reduce) {
  /* Le mouvement disparaît, l'information reste : le pourcentage et la
     coche continuent de s'afficher, ils sautent simplement d'un état
     à l'autre. */
  .up-jauge, .up-voile { transition: none; }
  .up-coche, .up-croix { animation: none; }
}

/* Enveloppe créée à la volée autour d'un champ de fichier : un `<input>` ne
   peut pas contenir la jauge, il lui faut un parent positionnable. */
.up-enveloppe { position: relative; display: block; border-radius: var(--r-sm); }
.up-enveloppe > .input { width: 100%; }
/* Sur un champ étroit, la coche et le pourcentage doivent rester lisibles. */
.up-enveloppe .up-jauge { border-radius: var(--r-sm); }

/* Aperçu de la photo dans la pastille de profil : le fichier choisi se voit
   immédiatement, et c'est lui qui accueille la jauge d'envoi. */
.pc-photo { display: flex; align-items: center; gap: .75rem; }
.pc-photo .input { flex: 1; min-width: 0; }
.pc-apercu {
  position: relative; flex: none;
  width: 52px; height: 52px; border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--secondary); color: var(--primary-ink);
  font-family: var(--font-sans); font-size: .85rem; font-weight: 800;
  outline: 1px solid rgba(0, 0, 0, .1); outline-offset: -1px;
}
.dark .pc-apercu { outline-color: rgba(255, 255, 255, .1); }
.pc-apercu img { width: 100%; height: 100%; object-fit: cover; }
.hint.hint-erreur { color: var(--destructive-ink); font-weight: 600; }

/* ===================================================================
   Éditeur d'annonces : galerie sans couverture séparée
   -------------------------------------------------------------------
   La première image tient lieu de vignette dans les listes : l'admin
   doit le voir, sinon il ne sait pas ce que verront ses lecteurs.
   =================================================================== */
.gallery-item.est-vignette { outline: 2px solid var(--primary); outline-offset: -2px; }
.gi-vignette {
  position: absolute; left: 0; bottom: 0; z-index: 1;
  padding: .2rem .45rem;
  background: var(--primary); color: #fff;
  font-family: var(--font-sans); font-size: .62rem; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
  border-top-right-radius: var(--r-sm);
}
/* Coller une adresse d'image : le champ et son bouton sur une seule ligne,
   qui se scinde quand la place manque. */
.ann-url-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.ann-url-row .input { flex: 1; min-width: 12rem; }
.ann-url-row .btn { flex: 0 0 auto; min-height: 44px; }

/* ---------- Messagerie parent ↔ répétiteur ---------- */
.msg-shell { display: grid; grid-template-columns: 300px 1fr; gap: 1.5rem; height: 560px; }
@media (max-width: 800px) { .msg-shell { grid-template-columns: 1fr; height: auto; } }
.msg-list { overflow-y: auto; }
.msg-item { display: flex; gap: .8rem; padding: .9rem; border-radius: var(--r-md); cursor: pointer; }
.msg-item:hover, .msg-item.active { background: var(--muted); }
.msg-item .avatar-initials { width: 42px; height: 42px; border-radius: 50%; flex: none; object-fit: cover; }
.msg-item .m-name { font-weight: 700; font-size: .88rem; }
.msg-item .m-preview { font-size: .78rem; color: var(--muted-foreground); }
.msg-item .m-time { font-size: .7rem; color: var(--muted-foreground); margin-left: auto; }
.msg-thread { display: flex; flex-direction: column; }
.msg-thread-body { flex: 1; overflow-y: auto; padding: .5rem 1rem; display: flex; flex-direction: column; gap: .9rem; }
.bubble { max-width: 70%; padding: .7rem 1rem; border-radius: var(--r-lg); font-size: .87rem; }
.bubble.in { background: var(--muted); align-self: flex-start; border-bottom-left-radius: 4px; }
.bubble.out { background: linear-gradient(135deg, var(--primary), var(--accent)); color: #fff; align-self: flex-end; border-bottom-right-radius: 4px; }
.msg-input-row { display: flex; gap: .75rem; padding: 1rem; border-top: 1px solid var(--border); }

/* Ajouts propres au fil réel : initiales quand il n'y a pas de photo,
   compteur de non-lus, heure sous la bulle, bandeau de signalement. */
.msg-item .msg-initiale {
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: .9rem;
  background: linear-gradient(135deg, var(--primary), var(--accent));
}
.msg-item .m-time { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; }
.m-unread {
  min-width: 18px; height: 18px; padding: 0 .3rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--primary); color: #fff;
  font-size: .68rem; font-weight: 800; font-variant-numeric: tabular-nums;
}
.msg-badge {
  margin-left: auto; min-width: 20px; padding: 0 .35rem;
  background: var(--primary); color: #fff; font-size: .7rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.msg-thread-head { display: flex; justify-content: flex-end; padding: .5rem .75rem 0; min-height: 2rem; }
.msg-signale { font-size: .78rem; color: var(--destructive-ink); font-weight: 700; }

/* ---------- Le fil de l'administration ----------
   Épinglé en tête, il doit se distinguer d'un correspondant sans crier plus
   fort qu'une conversation en cours : un liseré et la marque du site suffisent.
   `.brand-mark` est le composant de l'en-tête, réutilisé ici — la pastille
   suivra la charte si elle change, au lieu d'en figer une copie. */
.msg-item-admin { border: 1px solid color-mix(in srgb, var(--primary) 28%, transparent); }
.msg-item-admin:hover, .msg-item-admin.active {
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.msg-item .msg-marque {
  width: 42px; height: 42px; flex: none;
  /* Rond, comme les autres avatars du fil : le logo y est rogné, ses coins
     arrondis disparaissent dans le cercle sans que rien du dessin ne se perde. */
  border-radius: 50%; object-fit: cover;
  filter: none;   /* pas d'ombre portée dans une liste dense */
}
/* « Équipe » plutôt qu'une coche : dit qui écrit, pas un statut à interpréter. */
.m-officiel {
  margin-left: .4rem; padding: .05rem .4rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: var(--primary-ink); font-size: .62rem; font-weight: 800;
  letter-spacing: .02em; vertical-align: middle;
}
/* L'en-tête du fil : là où les autres portent « Signaler », celui-ci porte
   son identité. La barre est alignée à droite (`.msg-thread-head`), d'où le
   `margin-right:auto` pour ramener la mention à gauche. */
.msg-officiel {
  display: inline-flex; align-items: center; gap: .5rem; margin-right: auto;
  font-size: .78rem; font-weight: 700; color: var(--primary-ink);
}
.msg-officiel .msg-marque { width: 24px; height: 24px; }
.bubble { position: relative; overflow-wrap: anywhere; }
/* Le `pre-wrap` descend sur le CORPS seul : sur la bulle entière, il faisait
   compter les sauts de ligne du gabarit comme du texte, et la ligne d'heure
   partait à la ligne avec une espace parasite devant. */
.bubble .b-corps { white-space: pre-wrap; }

/* Heure et accusé, sous le message — la place où l'œil les cherche. */
.bubble .b-meta {
  display: flex; align-items: center; justify-content: flex-end;
  gap: .3rem; margin-top: .25rem;
  font-size: .66rem; line-height: 1;
}
.bubble.in .b-meta { justify-content: flex-start; }
.bubble .b-time { opacity: .7; font-variant-numeric: tabular-nums; }

.bubble .b-etat { display: inline-flex; opacity: .75; }
.bubble .b-etat svg { width: 15px; height: 10px; }
/* Lu : deux coches ET une couleur. La forme suffit seule — un daltonien ou un
   écran en plein soleil distingue toujours une coche de deux. */
.bubble .b-etat.est-lu { opacity: 1; color: #7fe0c4; }

/* Séparateur de jour : une pastille centrée, posée sur le fil. */
.msg-jour {
  align-self: center; margin: .6rem 0 .2rem;
  font-size: .68rem; font-weight: 700; color: var(--muted-foreground);
}
.msg-jour span {
  padding: .2rem .6rem; border-radius: 999px;
  background: var(--muted);
}
.msg-input-row textarea.input { resize: none; max-height: 8rem; font: inherit; font-size: .88rem; }
.msg-erreur { flex-basis: 100%; font-size: .78rem; color: var(--destructive-ink); }

/* ---------- Bandeau « vous êtes déjà connecté » ---------- */
/* Posé par session-chip.js sur la connexion et les inscriptions. On avertit
   sans rediriger : changer de compte, ou s'inscrire comme répétiteur quand on
   a déjà un compte parent, doit rester possible. */
.session-bandeau {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: .9rem;
  padding: .9rem 1.1rem; margin-bottom: 1.25rem;
  border: 1px solid var(--border); border-left: 3px solid var(--primary);
  border-radius: var(--r-md); background: var(--muted);
}
.session-bandeau .sb-texte { display: flex; flex-direction: column; gap: .15rem; }
.session-bandeau strong { font-size: .92rem; }
.session-bandeau .sb-qui { font-size: .82rem; color: var(--muted-foreground); }
.session-bandeau .sb-actions { display: flex; gap: .5rem; flex-wrap: wrap; }
@media (max-width: 560px) {
  .session-bandeau { flex-direction: column; align-items: stretch; }
  .session-bandeau .sb-actions > * { flex: 1; }
}

/* ---------- Encart remplaçant le formulaire de demande ---------- */
/* Affiché à qui ne peut pas déposer de demande : visiteur anonyme, répétiteur,
   administrateur. Mieux vaut l'annoncer avant le remplissage qu'après l'envoi. */
.dmd-encart { padding: 1.75rem; text-align: center; }
.dmd-encart h3 { font-family: var(--font-sans); font-size: 1.05rem; font-weight: 700; }
.dmd-encart p {
  margin-top: .6rem; font-size: .88rem; color: var(--muted-foreground);
  text-wrap: pretty; max-width: 44ch; margin-inline: auto;
}
.dmd-encart-actions {
  display: flex; gap: .6rem; justify-content: center; flex-wrap: wrap; margin-top: 1.25rem;
}
@media (max-width: 480px) {
  .dmd-encart { padding: 1.25rem; }
  .dmd-encart-actions > * { flex: 1 1 100%; }
}

/* ===================================================================
   Zones de frappe sur mobile
   -------------------------------------------------------------------
   Mesuré à 390 px : puces de carrousel à 8 × 8, six icônes sociales à
   40 × 40, 17 des 18 liens du pied de page sous 44 px de haut. Le doigt
   n'a pas la précision de la souris — d'où ce plancher de 44 px, appliqué
   SANS changer le dessin : la surface est étendue par un pseudo-élément
   quand l'élément doit rester petit à l'œil.

   Règle absolue : deux zones étendues ne doivent jamais se recouvrir,
   sans quoi on corrige une frappe imprécise par une frappe fausse.
   =================================================================== */
/* Chaque composant garde SA règle là où il est défini : les puces du
   carrousel, le fil d'Ariane ou les liens de contact vivent dans le `<style>`
   de leur page et y reçoivent donc aussi leur zone de frappe — une règle
   placée ici perdrait de toute façon la cascade, ce `<link>` venant avant. */
@media (max-width: 640px) {
  /* Icônes sociales : 40 → 44, espacées de .5rem, aucun recouvrement. */
  .site-footer .footer-social a { width: 44px; height: 44px; }

  /* Liens du pied de page : les `li` gardent leur écart de .65rem, la hauteur
     de frappe passe à 44 px sans rapprocher les lignes. */
  /* `inline-flex`, pas `flex` : dans la barre du bas, le lien « Ouattware »
     suit le mot « Fait par » sur la même ligne. En `flex`, il passerait seul
     à la ligne suivante et couperait la phrase en deux. */
  .site-footer .footer-liens a,
  .site-footer .footer-bottom a,
  .site-footer .f-links a {
    min-height: 44px; display: inline-flex; align-items: center;
  }

  /* Puces de filtre et de matière : 40 → 44. La largeur compte autant que la
     hauteur — « 6ᵉ » ne mesurait que 43 px de large. */
  .chip-toggle { min-height: 44px; min-width: 44px; justify-content: center; }

  /* Cases à cocher : partagées par la connexion et les deux inscriptions.
     L'`input` fait 18 px, mais c'est le label qui reçoit la frappe — encore
     faut-il qu'il soit assez haut. */
  .check-row, .consent-row { min-height: 44px; }

  /* Œil du mot de passe : 71 × 34. Centré par `translateY(-50%)`, grandir en
     hauteur ne le déplace pas. */
  .password-toggle { height: 44px; }

  /* Logo : 149 × 30. */
  .brand { min-height: 44px; }
}

/* ============================================================
   Bandeau de finalisation d'inscription  (assets/js/onboarding.js)
   ============================================================
   Une inscription par Google ouvre l'espace en un clic, avec une fiche
   encore vide. Ce bandeau dit ce qu'il reste à faire — et se veut une
   invitation, pas une alerte : d'où la teinte chaude de la marque plutôt
   qu'un rouge d'erreur, pour quelqu'un qui n'a rien fait de mal. */
.onboarding-banner {
  display: flex; align-items: flex-start; gap: 1.25rem;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
  border-radius: var(--r-lg);
  background: var(--card);
  /* Ombres superposées plutôt qu'une bordure pleine : la profondeur
     s'adapte au fond, clair comme sombre. Le liseré coloré à gauche porte
     le sens, les deux autres couches portent le relief. */
  box-shadow:
    inset 3px 0 0 0 var(--primary),
    0 1px 2px rgba(61, 52, 54, .06),
    0 8px 24px -12px rgba(61, 52, 54, .18);
  /* L'entrée se joue à l'arrivée sur la page : opacité et translation
     seulement, les deux propriétés que le GPU compose sans repeindre. */
  opacity: 0; transform: translateY(10px);
  transition: opacity .45s var(--ease-out), transform .45s var(--ease-out);
}
.onboarding-banner.is-in { opacity: 1; transform: translateY(0); }

/* Chaque partie arrive à son tour : l'œil suit l'icône, lit le titre, puis
   trouve le bouton. Tout ensemble, le bloc se lirait d'un bloc — donc mal. */
.onboarding-banner .ob-icon,
.onboarding-banner .ob-body,
.onboarding-banner .ob-cta {
  opacity: 0; transform: translateY(6px);
  transition: opacity .4s var(--ease-out), transform .4s var(--ease-out);
}
.onboarding-banner.is-in .ob-icon { opacity: 1; transform: none; transition-delay: .06s; }
.onboarding-banner.is-in .ob-body { opacity: 1; transform: none; transition-delay: .16s; }
.onboarding-banner.is-in .ob-cta  { opacity: 1; transform: none; transition-delay: .26s; }

.onboarding-banner .ob-icon {
  flex: none; width: 42px; height: 42px;
  /* Rayon concentrique : 18px (extérieur) − 20px (marge) tombe sous zéro,
     on redescend donc d'un cran plutôt que de répéter le rayon du cadre. */
  border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  background: var(--secondary); color: var(--primary-ink);
}
.onboarding-banner .ob-icon svg { width: 19px; height: 19px; }

.onboarding-banner .ob-body { flex: 1; min-width: 0; }
.onboarding-banner .ob-title {
  font-size: 1rem; font-weight: 800; line-height: 1.3;
  text-wrap: balance;   /* un titre court ne doit pas laisser un mot seul */
}
.onboarding-banner .ob-desc {
  font-size: .86rem; color: var(--muted-foreground); margin-top: .2rem;
  text-wrap: pretty;
}
.onboarding-banner .ob-desc strong { color: var(--primary-ink); }

.onboarding-banner .ob-list {
  list-style: none; margin: .7rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .4rem;
}
.onboarding-banner .ob-list li {
  font-size: .78rem; font-weight: 600;
  padding: .3rem .6rem;
  border-radius: var(--r-sm);
  background: var(--muted); color: var(--foreground);
}
.onboarding-banner .ob-cta { flex: none; align-self: center; }

/* Rappel : le bandeau se signale quand on clique une action encore gelée.
   Une pulsation d'ombre, pas un tremblement — l'utilisateur est invité,
   pas réprimandé. */
@keyframes obRappel {
  0%   { box-shadow: inset 3px 0 0 0 var(--primary), 0 1px 2px rgba(61,52,54,.06), 0 8px 24px -12px rgba(61,52,54,.18); }
  40%  { box-shadow: inset 3px 0 0 0 var(--primary), 0 0 0 4px color-mix(in srgb, var(--primary) 26%, transparent), 0 8px 24px -12px rgba(61,52,54,.18); }
  100% { box-shadow: inset 3px 0 0 0 var(--primary), 0 1px 2px rgba(61,52,54,.06), 0 8px 24px -12px rgba(61,52,54,.18); }
}
.onboarding-banner.attire-l-oeil { animation: obRappel .9s var(--ease-out); }

/* Une action gelée reste lisible : on comprend qu'elle existe et qu'elle
   attend quelque chose. La masquer laisserait croire qu'elle n'existe pas. */
.est-gele {
  opacity: .5;
  cursor: not-allowed;
  filter: grayscale(.35);
}

@media (max-width: 640px) {
  .onboarding-banner { flex-wrap: wrap; gap: 1rem; }
  .onboarding-banner .ob-cta { width: 100%; align-self: stretch; }
}

@media (prefers-reduced-motion: reduce) {
  .onboarding-banner,
  .onboarding-banner .ob-icon,
  .onboarding-banner .ob-body,
  .onboarding-banner .ob-cta {
    opacity: 1; transform: none; transition: none; transition-delay: 0s;
  }
  .onboarding-banner.attire-l-oeil { animation: none; }
}

/* ============================================================
   Squelettes de chargement des cartes répétiteur
   ============================================================
   La grille de la page d'accueil se remplit depuis l'API. Sans ces blocs,
   la section s'effondrerait à zéro hauteur puis se déplierait d'un coup au
   retour du réseau — la page entière sautant sous le curseur. Ils tiennent
   la place exacte des cartes à venir. */
.tutor-card.tc-squelette {
  min-height: 19rem;
  border-radius: var(--r-lg);
  background: var(--card);
  box-shadow: 0 1px 2px rgba(61, 52, 54, .05);
  position: relative;
  overflow: hidden;
  pointer-events: none;
}
/* Un balayage lent plutôt qu'un clignotement : on annonce une attente, on
   ne réclame pas l'attention. */
.tutor-card.tc-squelette::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--muted), transparent);
  transform: translateX(-100%);
  animation: tcBalayage 1.6s var(--ease-out) infinite;
}
@keyframes tcBalayage { to { transform: translateX(100%); } }

@media (prefers-reduced-motion: reduce) {
  .tutor-card.tc-squelette::after { animation: none; opacity: .5; transform: none; }
}

/* ============================================================
   Panneau de filtres : repli « Plus de critères »  (recherche.html)
   ============================================================
   Neuf groupes empilés poussaient le bouton « Voir les résultats » hors de
   l'écran : on réglait des critères sans jamais voir le geste qui les
   applique. Matière, commune et budget — ce sur quoi on cherche vraiment —
   restent ouverts ; les six autres se replient. */
.filters-plus {
  border-top: 1px solid var(--border);
  padding-top: 1rem;
  margin-top: .25rem;
}
.filters-plus > summary {
  display: flex; align-items: center; gap: .5rem;
  cursor: pointer;
  font-size: .82rem; font-weight: 700;
  padding: .55rem .35rem;
  border-radius: var(--r-sm);
  list-style: none;                    /* le marqueur natif, remplacé par le chevron */
  /* 44 px de haut : la cible reste confortable au doigt. */
  min-height: 44px;
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
.filters-plus > summary::-webkit-details-marker { display: none; }
.filters-plus > summary:hover { background: var(--muted); color: var(--primary-ink); }
.filters-plus > summary:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px;
}
.filters-plus .fp-titre { flex: 1; }

/* Le nombre de critères repliés actuellement actifs. Sans lui, replier
   reviendrait à cacher que la recherche est restreinte. */
.filters-plus .fp-compte {
  flex: none;
  min-width: 1.35rem; padding: .1rem .4rem;
  border-radius: 999px;
  background: var(--primary); color: #fff;
  font-size: .7rem; font-weight: 800; text-align: center;
  font-variant-numeric: tabular-nums;
}
.filters-plus .fp-compte[hidden] { display: none; }

.filters-plus .fp-chevron {
  flex: none; width: 16px; height: 16px;
  transition: transform .25s var(--ease-out);
}
.filters-plus[open] > summary .fp-chevron { transform: rotate(180deg); }

.filters-plus .fp-corps {
  display: flex; flex-direction: column; gap: 1.1rem;
  padding-top: 1rem;
}
/* Le dernier groupe du repli n'a pas à porter de séparateur : le bouton de
   validation suit immédiatement. */
.filters-plus .fp-corps .filter-group:last-child {
  border-bottom: none; padding-bottom: 0;
}
/* `details` ne sait pas animer sa hauteur ; on anime le contenu, ce qui
   suffit à adoucir l'ouverture sans mesurer quoi que ce soit. */
.filters-plus[open] .fp-corps { animation: fadeUp .28s var(--ease-out); }

/* Le nombre de répétiteurs enseignant une matière, sur sa puce. Il évite de
   cliquer un filtre qui ne peut mener qu'à une liste vide. */
.chip-toggle .chip-compte {
  margin-left: .4rem;
  padding: .05rem .35rem;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: .68rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
  transition: background-color .2s var(--ease-out), color .2s var(--ease-out);
}
.chip-toggle.active .chip-compte {
  background: rgba(255, 255, 255, .25);
  color: inherit;
}

@media (prefers-reduced-motion: reduce) {
  .filters-plus .fp-chevron { transition: none; }
  .filters-plus[open] .fp-corps { animation: none; }
}

/* ============================================================
   Demande : les élèves à accompagner  (assets/js/demande-form.js)
   ============================================================
   Une ligne par niveau, chacune avec son compteur. Un enfant unique reste
   le cas courant : la seconde ligne ne s'ajoute qu'à la demande du parent. */
.dmd-eleves { display: flex; flex-direction: column; gap: .6rem; }
.dmd-eleve { display: flex; align-items: center; gap: .6rem; }
.dmd-eleve .dmd-eleve-classe { flex: 1; min-width: 0; }

/* Compteur −/+ : les deux boutons encadrent la valeur, dans un même cadre,
   pour qu'on les lise comme un seul contrôle et non trois éléments voisins. */
.dmd-compteur {
  flex: none; display: flex; align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--card);
  overflow: hidden;
}
.dmd-compteur .dmd-pas {
  width: 44px; height: 44px;          /* cible tactile confortable */
  border: 0; background: transparent;
  color: var(--foreground);
  font-size: 1.15rem; font-weight: 700; line-height: 1;
  cursor: pointer;
  transition: background-color .18s var(--ease-out), color .18s var(--ease-out), transform .18s var(--ease-out);
}
.dmd-compteur .dmd-pas:hover:not(:disabled) { background: var(--muted); color: var(--primary-ink); }
.dmd-compteur .dmd-pas:active:not(:disabled) { transform: scale(.96); }
.dmd-compteur .dmd-pas:disabled { opacity: .35; cursor: not-allowed; }
.dmd-compteur .dmd-pas:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.dmd-compteur .dmd-nb {
  min-width: 2.2rem; text-align: center;
  font-weight: 800; font-size: .95rem;
  /* Chiffres à chasse fixe : sans cela, passer de 1 à 2 décale les boutons. */
  font-variant-numeric: tabular-nums;
}

.dmd-eleve .dmd-retirer {
  flex: none; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--muted-foreground);
  cursor: pointer;
  transition: background-color .18s var(--ease-out), color .18s var(--ease-out);
}
.dmd-eleve .dmd-retirer svg { width: 15px; height: 15px; }
.dmd-eleve .dmd-retirer:hover { background: var(--muted); color: var(--destructive); }

.dmd-ajout {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-top: .6rem; padding: .5rem .2rem;
  min-height: 44px;
  border: 0; background: none;
  color: var(--primary-ink); font-size: .82rem; font-weight: 700;
  cursor: pointer;
}
.dmd-ajout svg { width: 15px; height: 15px; }
.dmd-ajout:hover { text-decoration: underline; }
.dmd-ajout[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .dmd-compteur .dmd-pas { transition: none; }
  .dmd-compteur .dmd-pas:active:not(:disabled) { transform: none; }
}

/* ============================================================
   Présentation du répétiteur  (profil-repetiteur.html)
   ============================================================
   C'est le seul endroit où le répétiteur parle en son nom. Le laisser en
   paragraphe nu lui donnait le poids d'une mention légale. */
.rep-presentation {
  position: relative;
  margin-top: .35rem;
  padding: 1.15rem 1.25rem 1.15rem 1.5rem;
  border-radius: var(--r-md);
  background: var(--muted);
  /* Le liseré porte le sens (une parole citée), l'ombre porte le relief. */
  box-shadow: inset 3px 0 0 0 var(--primary);
}
/* Guillemet en filigrane : il signale une citation sans occuper de place. */
.rep-presentation::before {
  content: "\201C";
  position: absolute; top: -.15rem; right: .6rem;
  font-family: var(--font-serif);
  font-size: 3.4rem; line-height: 1;
  color: var(--primary);
  opacity: .13;
  pointer-events: none;
}
.rep-presentation #repDescription {
  font-size: .92rem;
  color: var(--foreground);
  line-height: 1.7;
  text-wrap: pretty;            /* pas de mot seul en fin de paragraphe */
  white-space: pre-line;        /* les retours à la ligne saisis sont gardés */
}
/* Repli : six lignes suffisent à juger, le reste se déplie à la demande. */
.rep-presentation.est-replie #repDescription {
  display: -webkit-box;
  -webkit-line-clamp: 6;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.rep-presentation-plus {
  margin-top: .6rem; padding: .3rem 0;
  min-height: 32px;
  border: 0; background: none;
  color: var(--primary-ink); font-size: .82rem; font-weight: 700;
  cursor: pointer;
}
.rep-presentation-plus:hover { text-decoration: underline; }
.rep-presentation-plus[hidden] { display: none; }

/* ============================================================
   Photo de profil : les critères  (inscription-repetiteur.html)
   ============================================================
   Le champ acceptait les bons formats sans jamais dire à quoi la photo sert.
   C'est pourtant elle qui décide un parent de prendre contact. */
.photo-conseils {
  padding: .95rem 1.1rem;
  border-radius: var(--r-md);
  background: var(--muted);
  box-shadow: inset 3px 0 0 0 var(--primary);
}
.photo-conseils .pc-titre {
  display: flex; align-items: center; gap: .45rem;
  font-size: .84rem; font-weight: 800; color: var(--foreground);
  margin-bottom: .55rem;
}
.photo-conseils .pc-titre svg { width: 15px; height: 15px; flex: none; color: var(--primary-ink); }
.photo-conseils .pc-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: .3rem; }
.photo-conseils .pc-liste li {
  display: flex; align-items: flex-start; gap: .45rem;
  font-size: .81rem; color: var(--muted-foreground);
  text-wrap: pretty;
}
/* Le signe porte le sens : une liste à puces uniformes obligerait à lire
   chaque ligne pour savoir si elle autorise ou interdit. */
.photo-conseils .pc-liste li::before {
  flex: none; width: 1rem; font-weight: 800;
}
.photo-conseils .pc-oui::before { content: "\2713"; color: var(--success); }
.photo-conseils .pc-non::before { content: "\2715"; color: var(--destructive); }

/* ---------- Pièces justificatives ---------- */
.docs-intro {
  font-size: .82rem; color: var(--muted-foreground);
  margin-bottom: 1rem; text-wrap: pretty;
}
.doc-bloc .doc-input { display: none; }
/* « Prendre en photo » n'a de sens qu'avec un appareil : sur un écran tactile.
   Le proposer sur un poste fixe ouvrirait un sélecteur de fichiers déguisé. */
.doc-photo { display: none; }
@media (pointer: coarse) {
  .doc-photo {
    display: inline-flex; align-items: center; gap: .4rem;
    margin-top: .5rem; padding: .5rem .8rem;
    min-height: 44px;
    border: 1px solid var(--border); border-radius: var(--r-sm);
    background: var(--card); color: var(--primary-ink);
    font-size: .82rem; font-weight: 700;
    cursor: pointer;
    transition: border-color .18s var(--ease-out), transform .18s var(--ease-out);
  }
  .doc-photo svg { width: 15px; height: 15px; }
  .doc-photo:hover { border-color: var(--primary); }
  .doc-photo:active { transform: scale(.96); }
}
@media (prefers-reduced-motion: reduce) {
  .doc-photo { transition: none; }
  .doc-photo:active { transform: none; }
}

/* Pièces d'un dossier, dans la file de validation de l'administration.
   Une pièce absente se lit d'un coup d'œil : sans elle, on validait sans
   savoir qu'il manquait quelque chose. */
.doc-liens { display: flex; flex-wrap: wrap; gap: .3rem; }
.doc-lien {
  display: inline-flex; align-items: center;
  padding: .18rem .45rem;
  border-radius: var(--r-sm);
  font-size: .7rem; font-weight: 800;
  background: var(--secondary); color: var(--primary-ink);
  text-decoration: none;
  transition: background-color .18s var(--ease-out);
}
.doc-lien:hover { background: var(--primary); color: #fff; }
.doc-lien.doc-absent {
  background: transparent;
  color: var(--muted-foreground);
  /* Barré plutôt que grisé : le gris seul se confond avec un état inactif. */
  text-decoration: line-through;
  opacity: .7;
}
@media (prefers-reduced-motion: reduce) { .doc-lien { transition: none; } }

/* ============================================================
   Fratrie à l'inscription parent  (inscription-parent.html)
   ============================================================
   Un bloc par enfant. La base acceptait plusieurs élèves depuis toujours ;
   le formulaire n'en décrivait qu'un. */
.eleves-intro {
  font-size: .84rem; color: var(--muted-foreground);
  margin-bottom: 1.1rem; text-wrap: pretty;
}
.eleve-bloc {
  border: 0; margin: 0 0 1rem; padding: 1.1rem 1.2rem;
  border-radius: var(--r-md);
  background: var(--muted);
  /* Le liseré numérote visuellement la fratrie sans ajouter de chrome. */
  box-shadow: inset 3px 0 0 0 var(--primary);
  animation: fadeUp .3s var(--ease-out);
}
.eleve-bloc .eleve-legende {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 0; margin-bottom: .85rem;
}
.eleve-bloc .eleve-titre {
  font-size: .82rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--primary-ink);
}
.eleve-bloc .eleve-retirer {
  width: 40px; height: 40px;      /* cible confortable, même au doigt */
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--muted-foreground);
  cursor: pointer;
  transition: background-color .18s var(--ease-out), color .18s var(--ease-out);
}
.eleve-bloc .eleve-retirer svg { width: 15px; height: 15px; }
.eleve-bloc .eleve-retirer:hover { background: var(--card); color: var(--destructive); }
.eleve-bloc .eleve-retirer[hidden] { display: none; }

/* Le fond du bloc porte déjà la teinte `--muted` : les champs prennent celle
   de la carte pour rester lisibles, sinon ils s'y fondraient. */
.eleve-bloc .input { background: var(--card); }

.eleve-ajout {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 44px; padding: .5rem .9rem;
  border: 1px dashed var(--border); border-radius: var(--r-sm);
  background: transparent; color: var(--primary-ink);
  font-size: .84rem; font-weight: 700;
  cursor: pointer;
  transition: border-color .18s var(--ease-out), background-color .18s var(--ease-out), transform .18s var(--ease-out);
}
.eleve-ajout svg { width: 15px; height: 15px; }
.eleve-ajout:hover { border-color: var(--primary); background: var(--muted); }
.eleve-ajout:active { transform: scale(.96); }
.eleve-ajout[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .eleve-bloc { animation: none; }
  .eleve-ajout, .eleve-bloc .eleve-retirer { transition: none; }
  .eleve-ajout:active { transform: none; }
}

/* ============================================================
   Conflit de rôle sur un formulaire d'inscription
   ============================================================
   Une adresse e-mail détermine un rôle. Un parent connecté qui ouvre le
   formulaire répétiteur serait refusé en 409 à l'envoi : autant le lui dire
   avant qu'il ne saisisse six sections. */
.role-conflit {
  margin: 0 0 1.5rem;
  padding: 1.1rem 1.25rem;
  border-radius: var(--r-md);
  background: var(--muted);
  /* Liseré d'alerte, mais pas rouge : l'utilisateur ne s'est pas trompé de
     saisie, il s'est trompé de porte. */
  box-shadow: inset 3px 0 0 0 var(--warning);
  font-size: .88rem;
  line-height: 1.6;
  color: var(--muted-foreground);
  text-wrap: pretty;
}
.role-conflit strong { display: block; color: var(--foreground); margin-bottom: .2rem; }
.role-conflit a { color: var(--primary-ink); font-weight: 700; }

/* Le formulaire reste lisible : le masquer laisserait croire à une page
   cassée. `inert` (posé par main.js) le retire du clavier et des clics. */
form.est-gele {
  opacity: .45;
  filter: grayscale(.4);
  user-select: none;
}

/* ============================================================
   Messages directs de l'administration  (admin-messages.js)
   ============================================================
   L'administration écrit aux comptes, et leur répond.

   Le gabarit vient de `.msg-shell`, partagé avec la messagerie des autres
   espaces : liste à gauche, fil à droite. L'ancienne version coupait l'écran
   en deux moitiés fixes — un formulaire d'envoi campant à gauche même quand on
   lisait, et une liste qui DISPARAISSAIT au profit des bulles dès qu'on
   ouvrait un fil. Treize règles ont disparu avec elle. */
.md-colonne { display: flex; flex-direction: column; gap: .6rem; min-height: 0; }
.md-recherche { flex: none; height: 2.4rem; font-size: .84rem; }

/* Composer : un MODE du panneau de droite, pas un formulaire permanent. */
.md-envoi { display: flex; flex-direction: column; gap: 1rem; padding: 1rem; overflow-y: auto; }
.md-envoi[hidden] { display: none; }
.md-envoi-pied { display: flex; justify-content: flex-end; gap: .6rem; flex-wrap: wrap; }
.md-envoi-pied .btn { min-height: 44px; }
.md-erreur { color: var(--destructive); font-size: .84rem; font-weight: 600; }
.md-erreur[hidden] { display: none; }

/* Le rôle du destinataire, dans la liste : écrire à un parent ou à un
   répétiteur n'engage pas le même ton. */
.md-role {
  margin-left: .4rem; padding: .05rem .4rem;
  border-radius: 999px; background: var(--muted);
  font-size: .62rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .03em; color: var(--muted-foreground);
  vertical-align: middle;
}
/* Un fil en attente de réponse porte un lisieré : le gras seul se confond
   avec un simple message récent. */
.md-non-lu { box-shadow: inset 3px 0 0 0 var(--primary); }

.md-entete {
  display: flex; align-items: center; gap: .7rem;
  padding: .85rem 1rem; border-bottom: 1px solid var(--border);
}
.md-entete[hidden] { display: none; }
.md-entete .avatar-initials { width: 36px; height: 36px; border-radius: 50%; flex: none; }
.md-entete strong { display: block; font-size: .92rem; }
.md-entete-sous {
  display: block; font-size: .74rem; color: var(--muted-foreground);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ============================================================
   Fenêtre de finalisation d'inscription  (finalisation.js)
   ============================================================
   Une section à la fois, enregistrée au passage. Elle ne redemande que ce
   qui manque : le nom déjà fourni par Google n'est pas ressaisi. */
.fin-voile {
  position: fixed; inset: 0; z-index: 120;
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
  background: rgba(20, 14, 16, .55);
  backdrop-filter: blur(3px);
  animation: finVoile .2s var(--ease-out);
}
@keyframes finVoile { from { opacity: 0; } to { opacity: 1; } }

.fin-carte {
  width: 100%; max-width: 560px; max-height: 92vh;
  display: flex; flex-direction: column;
  background: var(--card);
  border-radius: var(--r-xl);
  box-shadow: 0 24px 60px -20px rgba(20, 14, 16, .5);
  animation: fadeUp .28s var(--ease-out);
  overflow: hidden;
}

.fin-tete {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; padding: 1.35rem 1.5rem 1rem;
}
.fin-eyebrow {
  font-size: .72rem; font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--primary-ink);
}
.fin-titre { font-family: var(--font-sans); font-size: 1.15rem; font-weight: 800; margin-top: .15rem; text-wrap: balance; }
.fin-fermer {
  flex: none; width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--muted-foreground);
  cursor: pointer;
  transition: background-color .18s var(--ease-out), color .18s var(--ease-out);
}
.fin-fermer svg { width: 17px; height: 17px; }
.fin-fermer:hover { background: var(--muted); color: var(--foreground); }

/* La jauge dit l'effort restant. Sans elle, six étapes ressemblent à un
   tunnel sans fin — et l'on abandonne à la troisième. */
.fin-jauge { height: 4px; background: var(--muted); margin: 0 1.5rem; border-radius: 999px; overflow: hidden; }
.fin-jauge-barre {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--primary), var(--accent));
  border-radius: 999px;
  transition: width .3s var(--ease-out);
}
.fin-compteur {
  padding: .5rem 1.5rem 0;
  font-size: .76rem; font-weight: 700; color: var(--muted-foreground);
  font-variant-numeric: tabular-nums;
}

.fin-corps {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 1rem 1.5rem 1.25rem;
  display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
  align-content: start;
}
@media (max-width: 520px) { .fin-corps { grid-template-columns: 1fr; } }
.fin-champ { display: flex; flex-direction: column; gap: .35rem; }
.fin-large, .fin-corps > .fin-large { grid-column: 1 / -1; }
.fin-corps label { font-size: .82rem; font-weight: 700; }
.fin-note { font-size: .78rem; color: var(--muted-foreground); text-wrap: pretty; }
.fin-tarif { display: flex; align-items: center; gap: .75rem; margin-bottom: .5rem; }
.fin-tarif label { flex: 0 0 5rem; font-size: .84rem; }

/* `.fin-corps` est une grille à deux colonnes : ces éléments-là s'adressent à
   l'étape entière, pas à un champ. Les laisser dans une demi-colonne couperait
   une consigne en deux et casserait un bloc de dépôt. */
.fin-corps > .fin-note,
.fin-corps > .fin-criteres,
.fin-corps > .doc-bloc { grid-column: 1 / -1; }

/* Les critères de photo : une consigne qu'on lit AVANT de choisir son fichier,
   pas un rappel après refus. Assez discrète pour ne pas concurrencer le bloc
   de dépôt, assez lisible pour être suivie. */
.fin-criteres {
  margin: 0; padding-left: 1.1rem;
  display: grid; gap: .25rem;
  font-size: .78rem; color: var(--muted-foreground); text-wrap: pretty;
}
.fin-criteres li { padding-left: .1rem; }

.fin-bascules { display: flex; flex-wrap: wrap; gap: .5rem; }
.fin-bascule {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px;                 /* cible tactile, comme partout ailleurs */
  padding: .4rem .8rem;
  border: 1px solid var(--border); border-radius: 999px;
  font-size: .84rem; font-weight: 600; cursor: pointer;
  transition: border-color .18s var(--ease-out), background .18s var(--ease-out);
}
.fin-bascule:hover { border-color: var(--primary); }
.fin-bascule:has(input:checked) {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}
.fin-corps textarea.input { resize: vertical; min-height: 5.5rem; font: inherit; }
@media (prefers-reduced-motion: reduce) { .fin-bascule { transition: none; } }

.fin-erreur {
  margin: 0 1.5rem; padding: .6rem .8rem;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--destructive) 10%, transparent);
  color: var(--destructive); font-size: .82rem; font-weight: 600;
}
.fin-erreur[hidden] { display: none; }

.fin-pied {
  display: flex; justify-content: flex-end; gap: .75rem;
  padding: 1rem 1.5rem 1.35rem;
}
/* Sans « Retour » à la première étape, le pied garde le bouton principal à
   droite : la position d'un bouton ne doit pas sauter d'une étape à l'autre. */
.fin-pied .btn { min-width: 8rem; }
@media (max-width: 520px) {
  .fin-pied { flex-direction: column-reverse; }
  .fin-pied .btn { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .fin-voile, .fin-carte { animation: none; }
  .fin-jauge-barre { transition: none; }
}

/* Bouton « Écrire » d'une carte de répétiteur.
   La carte EST un lien : le bouton se pose au-dessus, et `parent.js` annule
   la navigation au clic. Sans `position: relative` sur la carte, il partirait
   dans le flux du lien. */
.tutor-card { position: relative; }
.tc-ecrire {
  width: 100%;
  margin-top: .75rem;
  /* Cible tactile confortable, alignée sur le reste des boutons secondaires. */
  min-height: 40px;
}

/* ===================================================================
   « À régler » / « Vos gains » — assets/js/paiement-du.js
   ===================================================================
   Placé en tête du panneau Paiements : on vient sur cet écran pour payer,
   pas pour relire ce qui l'est déjà. */
.pdu {
  border-radius: var(--r-lg);
  padding: 1.15rem 1.25rem;
  margin-bottom: 1.5rem;
  background: var(--card);
  box-shadow: inset 0 0 0 1px var(--border), var(--shadow-sm);
}
/* Une somme due se signale sans virer à l'alarme : ce n'est pas une faute,
   c'est une échéance. */
.pdu-du { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 35%, transparent), var(--shadow-sm); }
.pdu-gain { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--success) 30%, transparent), var(--shadow-sm); }

.pdu-tete { display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.pdu-tete h3 { font-size: 1rem; font-weight: 800; }
.pdu-periode { font-size: .78rem; color: var(--muted-foreground); }
.pdu-total {
  margin-left: auto; font-size: 1.25rem; font-weight: 800;
  color: var(--primary-ink); font-variant-numeric: tabular-nums;
}

.pdu-liste { list-style: none; margin: .9rem 0 0; padding: 0; display: grid; gap: .5rem; }
.pdu-ligne {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .7rem .85rem; border-radius: var(--r-md);
  background: var(--muted);
}
.pdu-ligne strong { font-size: .9rem; display: block; }
.pdu-qui { font-size: .78rem; color: var(--muted-foreground); }
.pdu-montant { margin-left: auto; font-weight: 800; font-size: .95rem; }
.pdu-ligne .btn { min-height: 40px; }

.pdu-chiffres {
  display: grid; gap: .75rem; margin-top: .9rem;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}
.pdu-chiffre dt { font-size: .74rem; color: var(--muted-foreground); font-weight: 700; text-wrap: pretty; }
.pdu-chiffre dd { margin: .15rem 0 0; font-size: 1.1rem; font-weight: 800; }
.pdu-fort dd { color: var(--success-ink); }
/* La commission est montrée, pas cachée — mais ce n'est pas le chiffre qu'on
   vient chercher : elle passe au second plan sans disparaître. */
.pdu-discret dd { color: var(--muted-foreground); font-size: .95rem; }

.pdu-note { margin-top: .85rem; font-size: .78rem; color: var(--muted-foreground); text-wrap: pretty; }
.pdu-erreur {
  margin-top: .7rem; padding: .55rem .75rem; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--destructive) 10%, transparent);
  color: var(--destructive); font-size: .8rem; font-weight: 600;
}
.pdu-erreur[hidden] { display: none; }

@media (max-width: 560px) {
  .pdu-ligne { align-items: flex-start; }
  .pdu-ligne .btn { width: 100%; }
}

/* ===================================================================
   Fenêtre de finalisation — lieu et pièces justificatives
   =================================================================== */
.fin-aide {
  font-size: .72rem; color: var(--muted-foreground);
  margin-top: .2rem; text-wrap: pretty;
}
.fin-aide:empty { display: none; }

/* --- Cartes de dépôt ---
   Elles empruntaient `.doc-bloc` au formulaire pleine page, dessiné pour toute
   la largeur : dans une fenêtre à deux colonnes, l'icône collait au titre et
   l'état « déjà déposé » tenait dans une ligne qu'on ne voyait pas. Ici l'état
   vit sur la CARTE — bordure, pastille, couleur — pas seulement dans le texte. */
.fin-piece {
  grid-column: 1 / -1;
  border-radius: var(--r-md);
  padding: .2rem;
  background: var(--card);
  box-shadow: inset 0 0 0 1px var(--border);
  transition: box-shadow .18s var(--ease-out);
}
@media (min-width: 640px) { .fin-piece { grid-column: auto; } }

.fp-zone {
  display: flex; align-items: center; gap: .75rem;
  padding: .75rem .8rem; border-radius: calc(var(--r-md) - .2rem);
  cursor: pointer; min-height: 56px;
}
.fp-zone:hover { background: var(--muted); }
.fin-piece:has(.doc-input:focus-visible) { outline: 2px solid var(--ring); outline-offset: 2px; }

.fp-icone {
  width: 38px; height: 38px; flex: none; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--muted); color: var(--primary-ink);
}
.fp-texte { display: flex; flex-direction: column; min-width: 0; gap: .1rem; }
.fp-titre { font-size: .86rem; font-weight: 700; }
.fp-sous { font-size: .72rem; color: var(--muted-foreground); }

/* La pastille dit l'état d'un coup d'œil, sans lire le nom du fichier. */
.fp-etat {
  margin-left: auto; flex: none;
  width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px dashed var(--border);
}
.fin-piece.est-deja .fp-etat,
.fin-piece.est-choisi .fp-etat {
  border: 0; background: var(--success); position: relative;
}
.fin-piece.est-deja .fp-etat::after,
.fin-piece.est-choisi .fp-etat::after {
  content: ""; position: absolute; inset: 0;
  background: no-repeat center/11px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}
.fin-piece.est-choisi { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--success) 55%, transparent); }
.fin-piece.est-deja { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--success) 35%, transparent); }
.fin-piece.est-refuse { box-shadow: inset 0 0 0 1.5px var(--destructive); }
.fin-piece.est-refuse .fp-etat { border-color: var(--destructive); }

/* Le bouton appareil se détache de la zone cliquable : imbriqué dedans, un
   appui déclenchait le sélecteur de fichiers au lieu de la caméra. */
.fp-appareil { display: none; }
@media (pointer: coarse) {
  .fp-appareil {
    display: inline-flex; align-items: center; gap: .4rem;
    margin: 0 .8rem .6rem; padding: .45rem .75rem;
    min-height: 40px;
    border: 1px solid var(--border); border-radius: var(--r-sm);
    background: var(--card); color: var(--primary-ink);
    font-size: .78rem; font-weight: 700; cursor: pointer;
  }
  .fp-appareil:active { transform: scale(.97); }
}
.fp-nom {
  margin: 0 .8rem .55rem; font-size: .74rem; font-weight: 600;
  overflow-wrap: anywhere; text-wrap: pretty;
}
.fp-nom:empty { display: none; }
.fp-ok { color: var(--success-ink); }
.fp-erreur { color: var(--destructive); }
.fp-erreur::before { content: "⚠ "; }

@media (prefers-reduced-motion: reduce) {
  .fin-piece { transition: none; }
  .fp-appareil:active { transform: none; }
}

/* ===================================================================
   Familles d'onglets dans les barres latérales
   ===================================================================
   Neuf entrées côté parent, quinze côté administration : en liste plate, on
   les relit chaque fois au lieu de viser. Les intitulés ne sont pas
   cliquables — ce sont des repères, pas des destinations. */
.dash-groupe {
  margin: 1.1rem .9rem .25rem;
  font-size: .68rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted-foreground);
  opacity: .75;
}
/* Le premier groupe suit « Statistiques » : sans cette reprise, il collerait
   au lien du dessus. */
.dash-sidebar .dash-groupe:first-of-type { margin-top: .85rem; }

/* ===================================================================
   Boîte de confirmation — assets/js/confirmation.js
   ===================================================================
   `<dialog>` natif : le piège à focus, l'inertie de l'arrière-plan et la
   couche supérieure viennent du navigateur. On n'habille que l'apparence. */
.confirm-dlg {
  width: min(28rem, calc(100vw - 2rem));
  padding: 0; border: 0;
  border-radius: var(--r-xl);
  background: var(--card); color: var(--foreground);
  box-shadow: var(--shadow-lg), inset 0 0 0 1px var(--border);
  animation: confirmEntre .18s var(--ease-out);
}
.confirm-dlg::backdrop {
  background: rgba(20, 14, 16, .55);
  backdrop-filter: blur(2px);
  animation: confirmFond .18s var(--ease-out);
}
.confirm-dlg.est-partie { animation: confirmSort .14s var(--ease-out) forwards; }

@keyframes confirmEntre { from { opacity: 0; transform: scale(.96) translateY(8px); } }
@keyframes confirmSort  { to   { opacity: 0; transform: scale(.98) translateY(4px); } }
@keyframes confirmFond  { from { opacity: 0; } }

.confirm-corps { padding: 1.5rem; display: grid; gap: 1rem; }
.confirm-tete { display: flex; gap: .9rem; align-items: flex-start; }
.confirm-tete h2 { font-size: 1.05rem; font-weight: 800; line-height: 1.3; text-wrap: balance; }
.confirm-tete p { margin-top: .35rem; font-size: .87rem; line-height: 1.55; color: var(--muted-foreground); text-wrap: pretty; }

.confirm-icone {
  flex: none; width: 42px; height: 42px; border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--muted); color: var(--muted-foreground);
}
.confirm-icone svg { width: 20px; height: 20px; }
.est-danger .confirm-icone {
  background: color-mix(in srgb, var(--destructive) 12%, transparent);
  color: var(--destructive-ink);
}

/* Ce que la suppression emporte avec elle — la raison d'être de cette boîte. */
.confirm-details {
  padding: .8rem .95rem; border-radius: var(--r-md);
  background: var(--muted);
}
.confirm-details-titre { font-size: .74rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-foreground); }
.confirm-details ul { margin: .5rem 0 0; padding-left: 1.1rem; display: grid; gap: .25rem; }
.confirm-details li { font-size: .84rem; line-height: 1.45; text-wrap: pretty; }

.confirm-irrev { font-size: .8rem; font-weight: 700; color: var(--destructive-ink); }

.confirm-pied { display: flex; gap: .6rem; justify-content: flex-end; flex-wrap: wrap; }
.confirm-pied .btn { min-height: 44px; }

/* Bouton destructeur PLEIN : dans une boîte dont c'est l'unique enjeu, un
   simple texte rouge ne pèse pas assez face au bouton d'annulation. */
.btn-danger-plein {
  background: var(--destructive); color: #fff; border-color: var(--destructive);
}
.btn-danger-plein:hover { filter: brightness(.94); }

@media (max-width: 420px) {
  /* Pleine largeur, et l'action destructrice EN BAS : le pouce tombe d'abord
     sur « Annuler ». */
  .confirm-pied { flex-direction: column-reverse; }
  .confirm-pied .btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .confirm-dlg, .confirm-dlg::backdrop, .confirm-dlg.est-partie { animation: none; }
}

/* Variante avec saisie — le pendant de `window.prompt`. */
.confirm-saisie { display: grid; gap: .4rem; }
.confirm-saisie textarea.input {
  width: 100%; resize: vertical; min-height: 4.5rem;
  font: inherit; font-size: .88rem;
}
.confirm-saisie-erreur {
  font-size: .8rem; font-weight: 600; color: var(--destructive);
}
.confirm-saisie-erreur[hidden] { display: none; }

/* ---- Coordonnées du répétiteur, une fois la demande acceptée ----
   Des boutons, pas des lignes de texte : on appelle depuis son téléphone
   comme depuis son ordinateur, en un geste. */
.ct-contacts { display: grid; gap: .5rem; margin-top: .75rem; }
.ct-contact {
  display: flex; align-items: center; gap: .7rem;
  padding: .65rem .8rem; border-radius: 12px;
  background: var(--card); color: inherit; text-decoration: none;
  min-height: 44px;
  box-shadow: inset 0 0 0 1px var(--border);
  transition: box-shadow .18s var(--ease-out), transform .18s var(--ease-out);
}
.ct-contact:hover { box-shadow: inset 0 0 0 1px var(--primary), var(--shadow-sm); transform: translateY(-1px); }
.ct-contact:active { transform: scale(.985); }
.ct-contact svg { width: 18px; height: 18px; flex: none; }
/* Chaque canal garde sa couleur d'origine : on reconnaît WhatsApp au vert
   avant d'avoir lu le mot. */
.ct-contact.tel { color: var(--primary-ink); }
.ct-contact.wa { color: #1ea55c; }
.ct-contact.mail { color: #4f8ef7; }
.ct-contact span { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.ct-contact small {
  font-size: .64rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted-foreground); font-weight: 700;
}
.ct-contact strong {
  font-size: .86rem; color: var(--foreground);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  .ct-contact { transition: none; }
  .ct-contact:hover, .ct-contact:active { transform: none; }
}

/* Coordonnées dans une cellule de tableau (administration). Empilées, car
   côte à côte une adresse longue pousserait la colonne hors de l'écran. */
.cell-contact { display: grid; gap: .15rem; min-width: 0; }
.cell-lien {
  font-size: .78rem; color: var(--primary-ink); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.cell-lien:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ---- Écran de paiement du parent : une carte par contrat ----
   La liste à trois colonnes ne disait ni ce qu'on paie, ni pourquoi ce
   montant. Ici chaque contrat porte son répétiteur, son rythme, ses matières
   et le détail du calcul — c'est au moment de payer qu'on se le demande. */
.pdu-cartes { display: grid; gap: .75rem; margin-top: .9rem; }
@media (min-width: 1100px) { .pdu-cartes { grid-template-columns: repeat(2, 1fr); } }

.pdu-carte {
  display: flex; flex-direction: column; gap: .6rem;
  padding: .9rem 1rem; border-radius: var(--r-md);
  background: var(--card);
  box-shadow: inset 0 0 0 1px var(--border);
}
.pdu-carte.est-en-cours { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--warning, #e8a13a) 60%, transparent); }

.pdu-carte-tete { display: flex; align-items: center; gap: .7rem; }
.pdu-avatar { width: 40px; height: 40px; border-radius: 50%; flex: none; object-fit: cover; }
.pdu-initiale {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--muted); color: var(--muted-foreground);
  font-weight: 800; font-size: .9rem;
}
.pdu-carte-tete strong { display: block; font-size: .92rem; }
.pdu-carte .pdu-montant {
  margin-left: auto; font-size: 1.15rem; font-weight: 800;
  color: var(--primary-ink); white-space: nowrap;
}
.pdu-carte .pdu-montant small { font-size: .72rem; font-weight: 700; }
.pdu-matieres { display: flex; flex-wrap: wrap; gap: .35rem; }

/* Le calcul, replié : disponible sans encombrer celui qui ne le demande pas. */
.pdu-detail summary {
  cursor: pointer; font-size: .78rem; font-weight: 700;
  color: var(--primary-ink); list-style: none;
}
.pdu-detail summary::-webkit-details-marker { display: none; }
.pdu-detail summary::before { content: "▸ "; }
.pdu-detail[open] summary::before { content: "▾ "; }
.pdu-detail dl { margin: .5rem 0 0; display: grid; gap: .25rem; }
.pdu-detail dl > div { display: flex; justify-content: space-between; gap: 1rem; font-size: .8rem; }
.pdu-detail dt { color: var(--muted-foreground); }
.pdu-detail dd { margin: 0; font-weight: 700; }
.pdu-detail-total {
  margin-top: .35rem; padding-top: .35rem;
  border-top: 1px solid var(--border); font-weight: 800;
}
.pdu-detail-total dt { color: var(--foreground) !important; font-weight: 800; }

.pdu-attente {
  font-size: .78rem; font-weight: 600; color: var(--warning-ink, #8a6516);
  padding: .5rem .7rem; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--warning, #e8a13a) 14%, transparent);
  text-wrap: pretty;
}
.pdu-payer { width: 100%; min-height: 46px; gap: .5rem; }
.pdu-payer.est-occupe { opacity: .75; cursor: progress; }

/* Les moyens acceptés, annoncés avant le clic : le parent quitte le site pour
   payer, autant qu'il sache d'avance qu'il retrouvera son opérateur. */
.pdu-moyens { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: .9rem; }
.pdu-moyen {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .28rem .6rem; border-radius: 999px;
  background: var(--muted); font-size: .72rem; font-weight: 700;
  color: var(--muted-foreground);
}
.pdu-moyen i { width: 8px; height: 8px; border-radius: 50%; flex: none; }

/* Le bloc paiements en échec. Un ton neutre et non alarmiste : dans la
   majorité des cas ce n'est pas une panne, c'est qu'on est au mauvais endroit.
   Le bloc n'est masqué que lorsqu'il n'y a réellement rien à dire. */
.pdu-echec { box-shadow: inset 0 0 0 1px var(--border), var(--shadow-sm); }
.pdu-echec .pdu-tete h3 { color: var(--foreground); }
.pdu-echec-actions { margin-top: .9rem; display: flex; gap: .6rem; flex-wrap: wrap; }
.pdu-echec-actions .btn { min-height: 40px; }

/* ===================================================================
   Installer l'application  (assets/js/pwa.js)
   =================================================================== */
.pwa-band { background: var(--secondary); }
.pwa-carte {
  display: grid; gap: 2.5rem; align-items: center;
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 900px) { .pwa-carte { grid-template-columns: 1.15fr .85fr; } }

.pwa-texte h2 { font-size: 2rem; margin-top: .75rem; text-wrap: balance; }
.pwa-texte > p { margin-top: .9rem; max-width: 46ch; color: var(--muted-foreground); text-wrap: pretty; }

.pwa-atouts { list-style: none; margin: 1.75rem 0 0; padding: 0; display: grid; gap: 1rem; }
.pwa-atouts li { display: flex; gap: .85rem; align-items: flex-start; }
.pwa-atouts svg {
  width: 22px; height: 22px; flex: none; margin-top: .1rem;
  color: var(--primary-ink);
}
.pwa-atouts strong { display: block; font-size: .92rem; }
.pwa-atouts span { display: block; margin-top: .15rem; font-size: .84rem; color: var(--muted-foreground); text-wrap: pretty; }

.pwa-actions { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 1.75rem; }
.pwa-cta { min-height: 48px; gap: .55rem; }
.pwa-cta.est-installee { opacity: .6; cursor: default; }
/* Nommer les deux plateformes lève la question qu'on se pose devant un bouton
   d'installation : « est-ce que ça marche sur mon téléphone ? » */
.pwa-plateformes {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .8rem; font-weight: 600; color: var(--muted-foreground);
}
.pwa-plateformes svg { width: 15px; height: 15px; }
.pwa-note { margin-top: .85rem; font-size: .8rem; color: var(--muted-foreground); text-wrap: pretty; }
.pwa-note:empty { display: none; }

/* --- La maquette : l'icône sur un écran d'accueil --- */
.pwa-visuel { display: flex; justify-content: center; }
.pwa-tel {
  position: relative; width: 236px; padding: 10px;
  border-radius: 34px; background: #1c1418;
  box-shadow: 0 22px 50px -18px rgba(61, 52, 54, .55), inset 0 0 0 1.5px rgba(255,255,255,.08);
}
.pwa-encoche {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
  width: 78px; height: 18px; border-radius: 0 0 12px 12px; background: #1c1418; z-index: 2;
}
.pwa-ecran {
  border-radius: 26px; padding: 2rem .9rem 1.1rem;
  background: linear-gradient(165deg, #ffd9c8, #ffeadf 55%, #fff9f5);
  min-height: 380px;
}
.pwa-heure { text-align: center; font-size: .72rem; font-weight: 800; color: #6b4a3f; margin-bottom: 1.4rem; }
.pwa-grille { display: grid; grid-template-columns: repeat(4, 1fr); gap: .8rem .55rem; }
.pwa-app { display: grid; justify-items: center; gap: .3rem; }
/* Les autres applications sont des silhouettes : elles situent la scène sans
   attirer l'œil, qui doit tomber sur la nôtre. */
.pwa-app:not(.est-nous)::before {
  content: ""; width: 40px; height: 40px; border-radius: 11px;
  background: rgba(107, 74, 63, .13);
}
.pwa-app img { border-radius: 13px; box-shadow: 0 4px 10px -3px rgba(61,52,54,.4); }
.pwa-app small { font-size: .56rem; font-weight: 700; color: #6b4a3f; }
.est-nous { grid-column: 1; }

/* --- Bandeau de mise à jour --- */
.pwa-maj {
  position: fixed; left: 50%; bottom: 1rem; z-index: 90;
  transform: translate(-50%, 140%);
  display: flex; align-items: center; gap: .75rem;
  max-width: calc(100vw - 2rem);
  padding: .7rem .8rem .7rem 1.1rem;
  border-radius: 999px;
  background: var(--card); color: var(--foreground);
  box-shadow: var(--shadow-lg), inset 0 0 0 1px var(--border);
  font-size: .84rem; font-weight: 600;
  transition: transform .28s var(--ease-out);
}
.pwa-maj.est-visible { transform: translate(-50%, 0); }
.pwa-maj .btn { min-height: 36px; white-space: nowrap; }
.pwa-maj-fermer {
  border: 0; background: none; color: var(--muted-foreground);
  font-size: 1.2rem; line-height: 1; cursor: pointer;
  width: 32px; height: 32px; border-radius: 50%;
}
.pwa-maj-fermer:hover { background: var(--muted); color: var(--foreground); }
.pwa-glyphe { font-size: 1.05em; }

/* En mode application, la barre système mange le bas de l'écran sur iPhone. */
@media (display-mode: standalone) {
  body { padding-bottom: env(safe-area-inset-bottom); }
  .pwa-maj { bottom: calc(1rem + env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) {
  .pwa-maj { transition: none; }
}

/* ===================================================================
   Navigation d'application — assets/js/app-nav.js
   ===================================================================
   Sous 900 px seulement. Au-delà, la barre latérale reste seule maître : le
   module ne construit même pas la barre, ces règles ne servent qu'à garantir
   qu'un redimensionnement ne la laisse pas traîner. */
.app-tabs { display: none; }

@media (max-width: 900px) {
  .app-tabs {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    background: var(--card);
    box-shadow: 0 -1px 0 var(--border), 0 -8px 24px -18px rgba(61, 52, 54, .5);
    /* L'indicateur d'accueil de l'iPhone mange le bas de l'écran : sans cette
       réserve, le dernier onglet passe dessous et devient intouchable. */
    padding-bottom: env(safe-area-inset-bottom);
  }

  .app-tab {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px;
    /* 56 px : au-dessus du minimum de 44, parce qu'un onglet se vise en
       marchant, d'un pouce, sans regarder. */
    min-height: 56px; padding: 6px 4px;
    border: 0; background: none; cursor: pointer;
    color: var(--muted-foreground); text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .app-tab-ic { position: relative; display: grid; place-items: center; }
  .app-tab-ic svg { width: 23px; height: 23px; }
  .app-tab-txt {
    font-size: .63rem; font-weight: 700; letter-spacing: .01em;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* L'onglet actif se reconnaît à la COULEUR ET AU TRAIT. En plein soleil —
     le cas courant ici — la teinte seule ne se distingue plus. */
  .app-tab.est-actif { color: var(--primary-ink); }
  .app-tab.est-actif svg { stroke-width: 2.6; }
  .app-tab.est-actif .app-tab-txt { font-weight: 800; }
  .app-tab:active { background: var(--muted); }

  .app-tab-pastille {
    position: absolute; top: -4px; right: -8px;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 999px; background: var(--destructive); color: #fff;
    font-size: .58rem; font-weight: 800; line-height: 16px; text-align: center;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 0 0 2px var(--card);
  }
  .app-tab-pastille[hidden] { display: none; }

  /* La barre flotte au-dessus du contenu : sans cette réserve, le dernier
     élément de chaque page reste inatteignable, caché dessous. */
  body.a-app-tabs { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
  /* Le bandeau de mise à jour se pose au-dessus de la barre, pas dessous. */
  body.a-app-tabs .pwa-maj { bottom: calc(72px + env(safe-area-inset-bottom)); }

  /* Le burger et le menu déroulant faisaient double emploi avec les onglets.
     Ils restent en place pour les écrans intermédiaires du tableau de bord,
     mais disparaissent là où la barre les remplace. */
  body.a-app-tabs .dash-burger { display: none; }
}

/* --- La feuille « Plus » : les écrans qui ne tiennent pas dans cinq onglets --- */
.app-sheet {
  position: fixed; inset: 0; z-index: 95;
  display: flex; align-items: flex-end;
  background: rgba(20, 14, 16, .5); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .22s var(--ease-out);
}
.app-sheet.est-ouverte { opacity: 1; }
.app-sheet-carte {
  width: 100%; max-height: 82vh; overflow-y: auto;
  padding: .75rem 1rem calc(1rem + env(safe-area-inset-bottom));
  border-radius: 22px 22px 0 0;
  background: var(--card);
  transform: translateY(100%);
  transition: transform .26s var(--ease-out);
}
.app-sheet.est-ouverte .app-sheet-carte { transform: none; }
/* La poignée dit « ça glisse » sans l'écrire. */
.app-sheet-poignee {
  width: 38px; height: 4px; margin: 0 auto 1rem;
  border-radius: 999px; background: var(--border);
}
.app-sheet-grille { display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem; }
.app-sheet-item {
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  padding: .9rem .4rem; min-height: 76px;
  border: 0; border-radius: var(--r-md);
  background: var(--muted); color: var(--foreground);
  font-size: .7rem; font-weight: 700; text-align: center; cursor: pointer;
  line-height: 1.2;
}
.app-sheet-item:active { transform: scale(.97); }
.app-sheet-ic { color: var(--primary-ink); display: grid; place-items: center; }
.app-sheet-ic svg { width: 20px; height: 20px; }
.app-sheet-fermer { width: 100%; margin-top: .9rem; min-height: 46px; }

@media (prefers-reduced-motion: reduce) {
  .app-sheet, .app-sheet-carte { transition: none; }
  .app-sheet-item:active { transform: none; }
}

/* ===================================================================
   Écrans simplifiés sur téléphone (≤ 900 px)
   ===================================================================
   Le site était pensé pour le bureau : quatre colonnes de tuiles, des
   tableaux à huit colonnes, des rangées de quatre boutons. Rien de tout cela
   ne se lit ni ne se vise sur 375 px de large. */
@media (max-width: 900px) {

  /* --- Tuiles : deux colonnes, et le CHIFFRE prime sur l'étiquette ---
     Elles affichaient le libellé aussi gros que la valeur ; l'œil ne savait
     pas où se poser. */
  .tile-grid { grid-template-columns: repeat(2, 1fr); gap: .7rem; margin-bottom: 1.25rem; }
  .tile { padding: .9rem .85rem; }
  .tile-value { font-size: 1.55rem; line-height: 1.1; }
  .tile-label { font-size: .7rem; line-height: 1.25; }
  .tile-icon { width: 30px; height: 30px; }
  .tile-icon svg { width: 16px; height: 16px; }

  /* Une seule colonne sous 380 px écraserait deux tuiles côte à côte ; on
     garde deux colonnes et on rétrécit le texte. */
  @media (max-width: 380px) {
    .tile-value { font-size: 1.35rem; }
    .tile-label { font-size: .66rem; }
  }

  /* --- Le repli tableau → carte remonte de 640 à 900 px ---
     À 800 px, un tableau de huit colonnes débordait toujours : on lisait à
     l'horizontale, colonne par colonne. */
  table.data-table thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  table.data-table, table.data-table tbody { display: block; width: 100%; }
  table.data-table tr {
    display: block; background: var(--card);
    border: 1px solid var(--border); border-radius: var(--r-md);
    margin-bottom: .85rem; padding: .2rem .15rem; box-shadow: var(--shadow-sm);
  }
  table.data-table td {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; padding: .55rem .8rem; border: 0;
    font-size: .86rem; text-align: right;
  }
  /* L'étiquette de colonne revient devant la valeur : sans elle, une carte
     n'est qu'une pile de valeurs sans nom. */
  table.data-table td[data-label]::before {
    content: attr(data-label);
    font-size: .72rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .03em; color: var(--muted-foreground);
    text-align: left; flex: none;
  }
  table.data-table td:not([data-label]):empty { display: none; }
  table.data-table tbody tr:hover { background: var(--card); }

  /* --- Actions : pleine largeur, empilées ---
     Quatre boutons de 32 px côte à côte dans une cellule, c'est quatre
     cibles qu'on rate. */
  .action-cell {
    display: grid !important; gap: .4rem;
    padding: .6rem .8rem .8rem !important;
  }
  .action-cell .btn { width: 100%; min-height: 44px; justify-content: center; }
  .action-cell::before { display: none; }

  /* --- Les panneaux respirent moins large --- */
  .dash-main { padding: 1rem .85rem 0; }
  .panel-toolbar { gap: .6rem; }
  .panel-toolbar .btn { min-height: 44px; }

  /* Les champs de recherche et les sélecteurs se touchent au doigt. */
  .dash-main .input, .dash-main select.input { min-height: 44px; }
}

/* Bouton de compte dans l'en-tête, et sa feuille.
   La déconnexion ne vivait que dans la barre latérale des tableaux de bord —
   hors écran sous 900 px, et devenue inatteignable depuis que les onglets ont
   remplacé le burger. Elle est désormais à un geste, sur toutes les pages. */
.app-compte {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: none;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--card); color: var(--foreground);
  cursor: pointer;
  transition: border-color .18s var(--ease-out), transform .12s var(--ease-out);
}
.app-compte:hover { border-color: var(--primary); }
.app-compte:active { transform: scale(.94); }
.app-compte svg { width: 19px; height: 19px; }
/* Sur le hero sombre, l'en-tête est transparent : le bouton doit suivre. */
body.a-hero-media .site-header:not(.est-pose) .app-compte {
  background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.35); color: #fff;
}

.app-compte-role {
  margin: 0 0 .9rem; text-align: center;
  /* Pas de capitales : cette ligne porte le NOM de la personne des que la
     session est chargee, et un nom en capitales se lit mal. */
  font-size: .82rem; font-weight: 700; color: var(--muted-foreground);
  overflow-wrap: break-word;
}
.app-compte-actions { display: grid; gap: .6rem; }
.app-compte-actions .btn { width: 100%; min-height: 48px; justify-content: center; }

@media (prefers-reduced-motion: reduce) {
  .app-compte { transition: none; }
  .app-compte:active { transform: none; }
}

/* ===================================================================
   Défilement — assets/js/defilement.js
   =================================================================== */

/* --- L'en-tête se densifie dès qu'on défile ---
   À 85 % d'opacité, un contenu clair qui passe derrière suffit à faire perdre
   aux icônes leur contraste : le trait fait 2 px, il n'en faut pas plus. Dès
   le premier geste, le fond se ferme et une ombre détache la barre du contenu
   qui coule dessous. */
.site-header, .dash-topbar {
  transition: background-color .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
.site-header.est-defile {
  background: rgba(255, 249, 245, .97);
  box-shadow: 0 4px 20px -12px rgba(61, 52, 54, .5);
}
.dark .site-header.est-defile,
html.dark .site-header.est-defile { background: rgba(42, 32, 36, .97); }
.dash-topbar.est-defile { box-shadow: 0 4px 20px -12px rgba(61, 52, 54, .5); }

/* Sur l'accueil, l'en-tête est transparent tant qu'on est sur le hero : c'est
   `est-pose` qui commande, et il ne faut pas que `est-defile` le referme dès
   le premier pixel alors que le titre est encore à l'écran. */
body.a-hero-media .site-header.est-defile:not(.est-pose) {
  background: transparent; box-shadow: none;
}

/* --- La flèche de défilement --- */
.defil-btn {
  position: fixed; right: 1rem; z-index: 70;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  background: var(--card); color: var(--foreground);
  box-shadow: 0 8px 24px -10px rgba(61, 52, 54, .55);
  cursor: pointer;
  /* Absent tant qu'on n'a pas défilé : en haut de page, il n'aurait rien à
     proposer que le geste que la personne fait déjà. */
  opacity: 0; visibility: hidden; transform: translateY(10px) scale(.9);
  transition: opacity .22s var(--ease-out), transform .22s var(--ease-out),
              visibility .22s, border-color .18s var(--ease-out);
}
.defil-btn.est-visible { opacity: 1; visibility: visible; transform: none; }
.defil-btn:hover { border-color: var(--primary); }
.defil-btn:active { transform: scale(.92); }
.defil-btn svg {
  width: 21px; height: 21px;
  transition: transform .3s var(--ease-out);
}
/* Une seule icône qui pivote plutôt que deux qui se remplacent : le
   retournement dit lui-même que la direction a changé. */
.defil-btn.vers-le-haut svg { transform: rotate(180deg); }

/* La barre d'onglets occupe le bas de l'écran sur téléphone : le bouton se
   pose au-dessus, sinon il tombe pile sur les onglets. */
body.a-app-tabs .defil-btn { bottom: calc(72px + env(safe-area-inset-bottom)); }

@media (prefers-reduced-motion: reduce) {
  .defil-btn, .defil-btn svg, .site-header, .dash-topbar { transition: none; }
  .defil-btn.est-visible { transform: none; }
  .defil-btn:active { transform: none; }
}

/* ===================================================================
   Maquette de téléphone — les écrans qui défilent (assets/js/tel-car.js)
   ===================================================================
   Le cadre `.pwa-tel` existait déjà : on ne le redessine pas, on lui donne
   un contenu qui bouge. Les écrans sont du balisage, pas des captures —
   nets à toutes les densités, sans un octet à télécharger, et incapables de
   montrer une interface qui n'existe plus. */

.tel-car { display: flex; flex-direction: column; align-items: center; gap: 1rem; }

/* La piste porte les quatre écrans côte à côte ; on la translate d'un écran
   à la fois. `overflow: clip` plutôt que `hidden` : `hidden` créerait un
   conteneur de défilement, et un clic au clavier sur un écran hors champ
   ferait sauter la page pour le ramener dans la vue. */
.tel-ecran { overflow: clip; }
.tel-piste {
  display: flex; align-items: stretch;
  transition: transform .45s var(--ease-out);
  will-change: transform;
}
.tel-vue {
  flex: 0 0 100%; min-width: 0;
  display: flex; flex-direction: column; gap: .5rem;
  /* Toutes les vues font la hauteur de la plus haute : sans quoi le cadre du
     téléphone changerait de taille à chaque écran. */
  min-height: 300px;
}

.tel-titre {
  margin: 0 0 .15rem; font-size: .74rem; font-weight: 800;
  letter-spacing: .02em; color: #6b4a3f;
}
.tel-p { margin: 0; font-size: .66rem; line-height: 1.5; color: #7d5a4d; }

/* --- écran 1 : les fiches --- */
.tel-fiche {
  display: flex; align-items: center; gap: .5rem;
  padding: .45rem .5rem; border-radius: 12px;
  background: rgba(255, 255, 255, .82);
  box-shadow: 0 2px 8px -4px rgba(61, 52, 54, .4);
}
.tel-fiche.est-pale { opacity: .5; }
.tel-fiche img { border-radius: 50%; object-fit: cover; flex: none; }
.tel-fiche div { display: grid; min-width: 0; }
.tel-fiche strong { font-size: .7rem; color: #3d3436; }
.tel-fiche span { font-size: .6rem; color: #7d5a4d; }
.tel-note {
  margin-left: auto; flex: none;
  padding: .1rem .35rem; border-radius: 999px;
  background: var(--primary); color: #fff;
  font-size: .58rem; font-weight: 800;
}

/* --- écran 2 : l'acceptation --- */
.tel-etat {
  display: inline-flex; align-items: center; gap: .3rem; align-self: flex-start;
  padding: .2rem .5rem; border-radius: 999px;
  background: #1f7a4d; color: #fff; font-size: .62rem; font-weight: 800;
}
.tel-etat svg { width: 11px; height: 11px; }
.tel-contact {
  display: grid; gap: .3rem; margin-top: .2rem;
  padding: .5rem .6rem; border-radius: 12px;
  background: rgba(255, 255, 255, .82);
  font-size: .62rem; font-weight: 600; color: #3d3436;
}

/* --- écran 3 : la messagerie --- */
.tel-bulle {
  max-width: 82%; padding: .4rem .55rem; border-radius: 12px;
  font-size: .63rem; line-height: 1.45;
}
.tel-bulle.est-recue { background: rgba(255,255,255,.9); color: #3d3436; border-bottom-left-radius: 4px; }
.tel-bulle.est-envoyee {
  align-self: flex-end; background: var(--primary); color: #fff;
  border-bottom-right-radius: 4px;
}
.tel-saisie {
  margin-top: auto; padding: .4rem .6rem; border-radius: 999px;
  background: rgba(255,255,255,.7); color: #a08b81; font-size: .62rem;
}

/* --- écran 4 : le paiement --- */
.tel-montant {
  font-family: var(--font-serif); font-weight: 900;
  font-size: 1.75rem; line-height: 1; color: #3d3436;
  font-variant-numeric: tabular-nums;
}
.tel-montant small { font-size: .7rem; font-weight: 700; color: #7d5a4d; }
.tel-ligne {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: .63rem; color: #7d5a4d;
  padding-block: .3rem; border-bottom: 1px solid rgba(107, 74, 63, .14);
}
.tel-ligne strong { color: #3d3436; font-variant-numeric: tabular-nums; }
.tel-payer {
  margin-top: auto; text-align: center;
  padding: .5rem; border-radius: 999px;
  background: var(--primary); color: #fff;
  font-size: .66rem; font-weight: 800;
}

/* --- les puces --- */
.tel-dots { display: flex; align-items: center; gap: .5rem; }
.tel-dot {
  width: 8px; height: 8px; padding: 0; border: none; border-radius: 999px;
  background: var(--border); cursor: pointer;
  position: relative;
  transition: width .25s var(--ease-out), background-color .25s var(--ease-out);
}
.tel-dot.est-actif { width: 22px; background: var(--primary); }
/* Une puce de 8 px ne se vise pas au doigt : le dessin reste petit, la zone
   de frappe fait 44 px par un pseudo-élément — comme pour les témoignages. */
.tel-dot::after { content: ""; position: absolute; inset: -18px -8px; }

@media (prefers-reduced-motion: reduce) {
  .tel-piste { transition: none; }
  .tel-dot { transition: none; }
}

/* ===================================================================
   Mot de passe à l'inscription
   ===================================================================
   Le champ manquait : l'inscription ne créait qu'une fiche, et l'on repartait
   avec un profil dans lequel on ne pouvait plus jamais entrer. */

.mdp-boite { position: relative; display: flex; align-items: center; }
/* La place de l'œil est réservée dans le champ lui-même : sans ce retrait, le
   texte saisi passe dessous et devient illisible dès qu'il est un peu long. */
.mdp-boite .input { width: 100%; padding-right: 3rem; }

.mdp-oeil {
  position: absolute; right: .35rem;
  width: 40px; height: 40px; border: 0; border-radius: 10px;
  display: grid; place-items: center;
  background: none; color: var(--muted-foreground); cursor: pointer;
  transition: color .15s var(--ease-out), background-color .15s var(--ease-out);
}
.mdp-oeil:hover { color: var(--foreground); background: var(--muted); }
.mdp-oeil svg { width: 18px; height: 18px; }
/* Œil barré quand le mot de passe est visible : l'icône dit ce qui se passera
   au clic suivant, pas l'état courant — c'est la convention partout ailleurs. */
.mdp-oeil[aria-pressed="true"] svg { opacity: .55; }
.mdp-oeil[aria-pressed="true"]::after {
  content: ""; position: absolute; width: 22px; height: 2px;
  background: currentColor; transform: rotate(-45deg); border-radius: 2px;
}

.mdp-aide { margin: .35rem 0 0; font-size: .78rem; color: var(--muted-foreground); }
/* Le compte rendu de robustesse et de correspondance remplace l'aide : deux
   lignes qui se suivent diraient la même chose deux fois. */
.mdp-aide.est-faible { color: var(--destructive); font-weight: 600; }
.mdp-aide.est-correct { color: #1f7a4d; font-weight: 600; }

/* Le champ de confirmation signale le désaccord au fil de la frappe, pas à
   l'envoi : découvrir une faute de frappe après avoir rempli trois sections
   est le meilleur moyen d'abandonner. */
.input[aria-invalid="true"] { border-color: var(--destructive); }

@media (prefers-reduced-motion: reduce) {
  .mdp-oeil { transition: none; }
}

/* ===================================================================
   Consultation seule — assets/js/lecture-seule.js
   ===================================================================
   Trois des quatre comptes d'administration ne peuvent rien modifier. Le
   serveur le fait déjà respecter ; ici on le DIT, pour qu'on ne clique pas
   sur un bouton qui répondra 403. */

.ls-bandeau {
  display: flex; align-items: flex-start; gap: .7rem;
  margin: 0 0 1.5rem; padding: .85rem 1.1rem;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--primary) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--primary) 28%, transparent);
  color: var(--foreground); font-size: .88rem; line-height: 1.5;
}
.ls-bandeau svg { width: 18px; height: 18px; flex: none; margin-top: .1rem; color: var(--primary-ink); }

/* Le bouton reste VISIBLE, éteint. Le masquer ferait croire que la
   fonctionnalité n'existe pas ; l'éteindre dit qu'elle existe et qu'elle
   n'est pas pour vous — ce qui est la vérité. */
.est-verrouille {
  opacity: .45; cursor: not-allowed; filter: grayscale(.5);
}
.est-verrouille:hover { transform: none; }

/* Un champ en lecture seule ne doit pas ressembler à un champ saisissable :
   sans ce signal, on tape avant de comprendre que rien ne s'inscrit. */
body.est-lecture-seule .dash-main .input[readonly],
body.est-lecture-seule .dash-main .input:disabled {
  background: var(--muted); cursor: default;
}
