/* ===================== KinePro — feuille de styles ===================== */

/*
 * Palette.
 *
 * Toutes les couleurs vivent ici, et nulle part ailleurs : une teinte ecrite en dur
 * au milieu de la feuille est une teinte qui restera claire la nuit venue. Le jeu se
 * veut court — une terracotta de marque, des gris chauds, et quatre etats (succes,
 * danger, alerte, information, inchanges lors du reskin pour ne pas rouvrir leur
 * audit de contraste) — parce qu'un planning se lit d'un coup d'oeil, et qu'un coup
 * d'oeil ne distingue pas douze nuances.
 *
 * Chaque etat vient par paire : la couleur pleine pour le texte et les aplats francs,
 * sa version « douce » pour les fonds. En clair la douce est pale, en sombre elle est
 * profonde — c'est tout ce qui change, et les composants n'ont pas a le savoir.
 */
:root {
  color-scheme: light;

  --fond: #fbf3e7;
  --fond-doux: #f3e6d3;
  --surface: #ffffff;
  --surface-2: #f5ebdc;
  --bordure: #eadfc8;
  --texte: #241c15;
  --texte-doux: #6b5b47;

  --primaire: #c2410c;
  --primaire-fonce: #9a340b;
  --primaire-doux: #f6ddc4;
  --primaire-bordure: #eec8a3;
  /* Texte pose sur un aplat de couleur pleine : bouton primaire, pastille, avatar. */
  --sur-primaire: #ffffff;

  --accent: #b5791f;
  --succes: #1f7a45;
  --succes-doux: #e3f4ea;
  --succes-bordure: #c4e6d3;
  --danger: #b3261e;
  --danger-doux: #fbe6e4;
  --danger-bordure: #f0c8c5;
  /* Assombri d'un cran : sur son fond creme, l'ancien ocre tombait a 4,47 pour 1,
     juste sous le seuil de lisibilite d'un texte de 11 px. */
  --alerte: #8a5c08;
  --alerte-doux: #fdf1da;
  --alerte-bordure: #f0dcb4;
  --info: #1b4f9c;
  --info-doux: #dfeafd;

  /* Barre laterale : sombre dans les deux themes, c'est le repere de l'application. */
  --barre: #241c15;
  --barre-texte: #ede4d6;
  --barre-texte-doux: #b3a18a;
  --barre-lien: #d8ccb8;
  --barre-voile: rgba(255, 255, 255, .12);
  --degrade-marque: linear-gradient(140deg, #c2410c 0%, #9a340b 55%, #241c15 100%);

  /* Aplat inverse du fond : notification, infobulle. Clair sur sombre, et l'inverse. */
  --inverse: #241c15;
  --sur-inverse: #ffffff;
  /* Derriere une radio ou un scanner : un gris neutre qui ne teinte pas l'image, quel
     que soit le theme de marque — on n'y touche pas. */
  --fond-visionneuse: #11181d;
  --voile-modale: rgba(36, 28, 21, .55);

  --rayon: 12px;
  --rayon-s: 8px;
  --ombre: 0 1px 2px rgba(36, 25, 15, .08), 0 8px 24px rgba(36, 25, 15, .09);
  --ombre-modale: 0 24px 60px rgba(30, 20, 12, .32);
  /* Titres en Space Grotesk, texte courant en Work Sans — chargees via <link> dans
     chaque page (voir index.html) ; system-ui reste le repli tant qu'elles arrivent. */
  --police-titre: "Space Grotesk", "Segoe UI", system-ui, -apple-system, sans-serif;
  --police: "Work Sans", "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
}

/*
 * Theme sombre.
 *
 * Il s'applique quand le systeme le demande, sauf si la personne a explicitement
 * choisi le mode clair (`data-theme="light"`) — son choix passe avant celui de
 * l'appareil. Le bloc suivant le pose aussi a la demande, pour l'inverse.
 *
 * Les couleurs pleines s'eclaircissent : un vert a 20 % de luminosite sur un fond
 * noir se lit moins bien qu'il ne parait, et un cabinet qui pointe ses seances le
 * soir ne doit pas plisser les yeux pour distinguer « regle » de « impaye ».
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --fond: #1b140d;
    --fond-doux: #241c15;
    --surface: #2a2015;
    --surface-2: #332619;
    --bordure: #443423;
    --texte: #f3e7d6;
    --texte-doux: #b3a188;

    --primaire: #e8935a;
    --primaire-fonce: #f2aa76;
    --primaire-doux: #3a2113;
    --primaire-bordure: #5c3a20;
    --sur-primaire: #2b1408;

    --accent: #d9a441;
    --succes: #4cc07d;
    --succes-doux: #10281c;
    --succes-bordure: #1d4432;
    --danger: #f08c82;
    --danger-doux: #2e1715;
    --danger-bordure: #522a26;
    --alerte: #ddab4c;
    --alerte-doux: #2a2013;
    --alerte-bordure: #4a3a1c;
    --info: #86b3f2;
    --info-doux: #16222f;

    --barre: #15100a;
    --barre-texte: #e4d8c4;
    --barre-texte-doux: #a08f76;
    --barre-lien: #c9b99e;
    --barre-voile: rgba(255, 255, 255, .09);
    --degrade-marque: linear-gradient(140deg, #6b2d0c 0%, #4a1f09 55%, #1b140d 100%);

    --inverse: #f3e7d6;
    --sur-inverse: #1b140d;
    --fond-visionneuse: #05090b;
    --voile-modale: rgba(10, 6, 3, .68);

    --ombre: 0 1px 2px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .38);
    --ombre-modale: 0 24px 60px rgba(0, 0, 0, .6);
  }
}

/* Le meme theme, choisi a la main depuis la barre laterale. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --fond: #1b140d;
  --fond-doux: #241c15;
  --surface: #2a2015;
  --surface-2: #332619;
  --bordure: #443423;
  --texte: #f3e7d6;
  --texte-doux: #b3a188;

  --primaire: #e8935a;
  --primaire-fonce: #f2aa76;
  --primaire-doux: #3a2113;
  --primaire-bordure: #5c3a20;
  --sur-primaire: #2b1408;

  --accent: #d9a441;
  --succes: #4cc07d;
  --succes-doux: #10281c;
  --succes-bordure: #1d4432;
  --danger: #f08c82;
  --danger-doux: #2e1715;
  --danger-bordure: #522a26;
  --alerte: #ddab4c;
  --alerte-doux: #2a2013;
  --alerte-bordure: #4a3a1c;
  --info: #86b3f2;
  --info-doux: #16222f;

  --barre: #15100a;
  --barre-texte: #e4d8c4;
  --barre-texte-doux: #a08f76;
  --barre-lien: #c9b99e;
  --barre-voile: rgba(255, 255, 255, .09);
  --degrade-marque: linear-gradient(140deg, #6b2d0c 0%, #4a1f09 55%, #1b140d 100%);

  --inverse: #f3e7d6;
  --sur-inverse: #1b140d;
  --fond-visionneuse: #05090b;
  --voile-modale: rgba(10, 6, 3, .68);

  --ombre: 0 1px 2px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .38);
  --ombre-modale: 0 24px 60px rgba(0, 0, 0, .6);
}

* { box-sizing: border-box; }

html {
  /* Safari ne doit pas regrossir le texte quand on tourne le téléphone. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--police);
  background: var(--fond);
  color: var(--texte);
  font-size: 15px;
  line-height: 1.5;
  /* Pas de halo gris ni d'attente de double-tap au toucher. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Les zones qui défilent gardent leur élan sans entraîner la page derrière elles. */
.jour__creneaux, .modale__corps, .enveloppe-tableau, .apercu, .apercu__texte, .journal {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

h1, h2, h3, h4 { margin: 0 0 .5rem; line-height: 1.25; font-weight: 650; font-family: var(--police-titre); }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1.02rem; }
small { color: var(--texte-doux); }
[hidden] { display: none !important; }

/* ------------------------------- éléments ------------------------------- */

.logo {
  display: inline-grid; place-items: center;
  width: 38px; height: 38px; border-radius: 11px;
  background: var(--primaire-doux); font-size: 20px;
}
.logo--grand { width: 64px; height: 64px; font-size: 34px; border-radius: 18px; }

label { display: block; font-size: .82rem; font-weight: 600; color: var(--texte-doux); margin-bottom: .75rem; }
label > input, label > select, label > textarea { margin-top: .3rem; }

input, select, textarea {
  width: 100%; padding: .55rem .7rem;
  border: 1px solid var(--bordure); border-radius: var(--rayon-s);
  background: var(--surface); color: var(--texte);
  font: inherit; font-weight: 400;
}
textarea { min-height: 76px; resize: vertical; }
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--primaire); outline-offset: -1px; border-color: var(--primaire);
}
input[type="checkbox"] { width: auto; }

/*
 * Une donnée posée par le formulaire, que l'utilisateur ne remplit pas : elle garde la
 * forme et la place d'un champ, pour se lire là où l'œil l'attend, et le fond sourd
 * sans bordure de saisie dit qu'elle n'attend rien. Ce n'est pas un champ désactivé —
 * un champ, même grisé, prend le focus et laisse espérer qu'on pourra le changer.
 */
.champ-fige {
  margin: .25rem 0 .9rem;
  padding: .55rem .7rem;
  border: 1px solid var(--bordure); border-radius: var(--rayon-s);
  background: var(--fond-doux); color: var(--texte);
  font-weight: 600;
}

/*
 * Sur un écran tactile : champs à 16 px, faute de quoi iOS zoome tout seul à la saisie,
 * et cibles d'au moins 44 px, la taille d'un doigt.
 */
@media (pointer: coarse) {
  input, select, textarea { font-size: 16px; padding: .6rem .7rem; }
  .btn { min-height: 44px; }
  .btn--petit { min-height: 38px; padding: .4rem .75rem; }
  .btn-icone { min-width: 40px; min-height: 40px; }
  .onglet { padding: .7rem .5rem; }
  .tableau tbody tr { min-height: 44px; }
  .creneau { min-height: 38px; }
  .nav__lien { min-height: 44px; }
  .case { padding: .25rem 0; }
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .55rem .95rem; border: 1px solid transparent; border-radius: var(--rayon-s);
  background: var(--surface-2); color: var(--texte);
  font: inherit; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.btn:hover { filter: brightness(.97); }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn--primaire { background: var(--primaire); color: var(--sur-primaire); }
.btn--primaire:hover { background: var(--primaire-fonce); filter: none; }
.btn--danger { background: var(--danger-doux); color: var(--danger); border-color: var(--danger-bordure); }
.btn--succes { background: var(--succes-doux); color: var(--succes); border-color: var(--succes-bordure); }
.btn--contour { background: var(--surface); border-color: var(--bordure); }
.btn--discret { background: transparent; border-color: var(--bordure); color: var(--texte-doux); }
.btn--bloc { width: 100%; }
.btn--petit { padding: .3rem .6rem; font-size: .8rem; }

.btn-icone {
  border: 0; background: transparent; cursor: pointer;
  font-size: 1rem; color: var(--texte-doux); padding: .3rem .45rem; border-radius: 6px;
}
.btn-icone:hover { background: var(--surface-2); color: var(--texte); }

.grille { display: grid; gap: 0 .9rem; }
.grille--2 { grid-template-columns: 1fr 1fr; }
.grille--3 { grid-template-columns: repeat(3, 1fr); }
.rangee { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.rangee--fin { justify-content: flex-end; }
.espace { flex: 1; }

.carte {
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon); padding: 1.1rem; box-shadow: var(--ombre);
}

/* Champ de recherche à suggestions : la liste se resserre à la frappe. */
.combo { position: relative; margin-bottom: .3rem; }
.combo__champ { padding-right: 2.4rem; }
.combo__champ[readonly] { background: var(--primaire-doux); font-weight: 600; cursor: default; }
.combo__effacer {
  position: absolute; top: 50%; right: .3rem; transform: translateY(-50%);
  border: 0; background: transparent; cursor: pointer; border-radius: 6px;
  color: var(--texte-doux); padding: .3rem .45rem; line-height: 1;
}
.combo__effacer:hover { background: var(--surface); color: var(--texte); }

.combo__liste {
  position: absolute; z-index: 5; left: 0; right: 0; top: calc(100% + .25rem);
  margin: 0; padding: .25rem; list-style: none;
  max-height: 16rem; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon-s); box-shadow: var(--ombre);
}
.combo__option {
  display: grid; gap: .05rem; padding: .45rem .55rem;
  border-radius: 6px; cursor: pointer;
}
.combo__option--vise { background: var(--primaire-doux); }
.combo__nom { font-weight: 650; }
.combo__detail { font-size: .76rem; color: var(--texte-doux); }
.combo__option--creer {
  border-top: 1px solid var(--bordure); margin-top: .25rem; padding-top: .55rem;
  border-radius: 0 0 6px 6px; font-weight: 600; color: var(--primaire);
}
.combo__message { padding: .5rem .55rem; font-size: .84rem; color: var(--texte-doux); }

/* Encart déplié dans un formulaire, pour une saisie annexe (création de patient au vol). */
.encart {
  border: 1px solid var(--primaire); border-radius: var(--rayon-s);
  background: var(--primaire-doux); padding: .8rem .9rem; margin: 0 0 .9rem;
}
.encart legend {
  padding: 0 .4rem; font-size: .74rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--primaire-fonce);
}
.encart input { background: var(--surface); }
.encart > small { display: block; margin-top: .55rem; }

.etiquette {
  display: inline-block; padding: .12rem .5rem; border-radius: 999px;
  font-size: .72rem; font-weight: 700; letter-spacing: .01em;
  background: var(--surface-2); color: var(--texte-doux);
}
.etiquette--planifie { background: var(--primaire-doux); color: var(--primaire-fonce); }
.etiquette--confirme { background: var(--info-doux); color: var(--info); }
.etiquette--honore   { background: var(--succes-doux); color: var(--succes); }
.etiquette--annule   { background: var(--danger-doux); color: var(--danger); }
.etiquette--absent   { background: var(--alerte-doux); color: var(--alerte); }

/* Compteur « séance X / total » posé devant un rendez-vous. */
.compteur {
  display: inline-block; flex: none;
  padding: .06rem .4rem; border-radius: 999px;
  background: var(--primaire); color: var(--sur-primaire);
  font-size: .7rem; font-weight: 700; font-variant-numeric: tabular-nums;
  white-space: nowrap; cursor: help;
}
.compteur--complet { background: var(--succes); }
.compteur--depasse { background: var(--alerte); }

.jauge { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.jauge__remplissage { height: 100%; background: var(--primaire); border-radius: 999px; }

.message { padding: .6rem .8rem; border-radius: var(--rayon-s); font-size: .86rem; margin: 0 0 .8rem; }
.message.erreur { background: var(--danger-doux); color: var(--danger); }
.message.info { background: var(--primaire-doux); color: var(--primaire-fonce); }
.message.succes { background: var(--succes-doux); color: var(--succes); }

.vide { text-align: center; color: var(--texte-doux); padding: 2.2rem 1rem; }
.vide__icone { font-size: 2rem; display: block; margin-bottom: .4rem; }

/* ---------------------------- authentification ---------------------------- */

.auth {
  min-height: 100vh; display: grid; grid-template-columns: 1.05fr .95fr;
  background: var(--degrade-marque);
}
.auth__marque { padding: 4rem 3.5rem; color: var(--barre-texte); align-self: center; }
.auth__marque h1 { font-size: 2.4rem; margin-top: 1.1rem; color: #fff; }
.auth__marque p { max-width: 42ch; color: var(--barre-lien); }
.auth__marque .logo { background: var(--barre-voile); }
.auth__atouts { margin: 1.8rem 0 0; padding: 0; list-style: none; }
.auth__atouts li { padding: .45rem 0 .45rem 1.6rem; position: relative; color: var(--barre-texte); max-width: 46ch; }
.auth__atouts li::before { content: "✓"; position: absolute; left: 0; color: var(--primaire-fonce); font-weight: 700; }

.auth__panneau {
  background: var(--surface); padding: 3rem 3rem; align-self: stretch;
  display: flex; flex-direction: column; justify-content: center;
}
.form-auth { max-width: 420px; width: 100%; margin: 0 auto; }
.form-auth h2 { margin-bottom: 1.2rem; }

.onglets { display: flex; gap: .3rem; max-width: 420px; width: 100%; margin: 0 auto 1.6rem; background: var(--surface-2); padding: .25rem; border-radius: var(--rayon-s); }
.onglet {
  flex: 1; padding: .5rem; border: 0; border-radius: 6px; cursor: pointer;
  background: transparent; font: inherit; font-weight: 600; color: var(--texte-doux);
}
.onglet.actif { background: var(--surface); color: var(--primaire); box-shadow: var(--ombre); }

/* ------------------------------ mise en page ------------------------------ */

.app { display: grid; grid-template-columns: 248px 1fr; min-height: 100vh; }

.barre-laterale {
  background: var(--barre); color: var(--barre-texte); display: flex; flex-direction: column;
  padding: 1.1rem .8rem; gap: 1.2rem; position: sticky; top: 0; height: 100vh;
}
.barre-laterale__marque { display: flex; align-items: center; gap: .6rem; padding: .2rem .4rem; }
.barre-laterale__marque .logo { background: var(--barre-voile); }
.barre-laterale__titre { font-weight: 700; font-size: 1.1rem; color: #fff; font-family: var(--police-titre); }

.nav { display: flex; flex-direction: column; gap: .2rem; flex: 1; }
.nav__lien {
  display: flex; align-items: center; gap: .6rem; width: 100%;
  padding: .6rem .7rem; border: 0; border-radius: var(--rayon-s);
  background: transparent; color: var(--barre-lien); font: inherit; font-weight: 600;
  cursor: pointer; text-align: left;
}
.nav__lien:hover { background: var(--barre-voile); color: #fff; }
.nav__lien.actif { background: var(--primaire); color: var(--sur-primaire); }

.barre-laterale__pied { border-top: 1px solid var(--barre-voile); padding-top: .9rem; }
.praticien { display: flex; align-items: center; gap: .6rem; margin-bottom: .7rem; }
.praticien__avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: var(--primaire); color: var(--sur-primaire); font-weight: 700;
}
.praticien strong { display: block; font-size: .88rem; color: #fff; }
.praticien small { color: var(--barre-texte-doux); font-size: .75rem; text-transform: capitalize; }
.barre-laterale .btn--discret { color: var(--barre-lien); border-color: var(--barre-voile); }
.barre-laterale .btn--discret:hover { background: var(--barre-voile); }

.contenu { padding: 1.6rem 2rem 3rem; max-width: 1400px; width: 100%; }
.entete-vue { display: flex; align-items: flex-start; gap: 1rem; margin-bottom: 1.3rem; flex-wrap: wrap; }
.entete-vue p { margin: 0; color: var(--texte-doux); }

/* ---------------------------- tableau de bord ---------------------------- */

.statistiques { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: .9rem; margin-bottom: 1.4rem; }
/*
 * Les chiffres d'argent tiennent dans des tuiles larges : « 640 035 F CFA » se coupait
 * en deux au milieu du nombre.
 */
.statistiques { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

/*
 * La seconde rangée porte ce qu'aucune période ne commande. Ses tuiles ne s'étirent pas
 * sur toute la largeur comme celles du haut : deux chiffres étalés en pleine page
 * paraîtraient plus importants que les quatre au-dessus, alors qu'ils sont en retrait.
 */
.statistiques--hors-periode {
  grid-template-columns: repeat(auto-fit, minmax(13rem, 17rem));
  justify-content: start;
}
/* Deux rangées qui se suivent : un seul écart entre elles, comme entre deux tuiles. */
.statistiques + .statistiques { margin-top: -.5rem; }
.stat { background: var(--surface); border: 1px solid var(--bordure); border-radius: var(--rayon); padding: .9rem 1rem; }
.stat__valeur { font-size: 1.8rem; font-weight: 700; line-height: 1.1; font-family: var(--police-titre); }
.stat__libelle { font-size: .8rem; color: var(--texte-doux); font-weight: 600; }
/* Ce qu'une tuile doit préciser pour ne pas être lue de travers — « toutes dates ». */
.stat__note { margin-top: .15rem; font-size: .7rem; color: var(--texte-doux); }

/* ------------------------------ filtre de période ------------------------------ */

/*
 * Les raccourcis à gauche, les deux dates à droite : on choisit presque toujours par
 * raccourci, et la saisie à la main reste pour la question précise qu'aucun bouton ne
 * couvre — « du 3 au 17 mars ».
 */
.barre-periode {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .5rem;
}
.barre-periode__raccourcis { display: flex; gap: .35rem; flex-wrap: wrap; }
.barre-periode__date {
  display: flex; align-items: center; gap: .4rem; margin: 0;
  font-size: .8rem; color: var(--texte-doux); font-weight: 600;
}
.barre-periode__date input { width: auto; }
.barre-periode__resume { margin: 0 0 1rem; color: var(--texte-doux); }

/* Sur un téléphone, les dates passent sous les raccourcis et prennent la ligne. */
@media (max-width: 48rem) {
  .barre-periode__date { flex: 1 1 100%; }
  .barre-periode__date input { flex: 1; }
}

/* Un indicateur qui cache un détail : il doit se voir cliquable avant d'être cliqué. */
.stat--ouvrable {
  font: inherit; text-align: left; cursor: pointer; width: 100%;
  transition: border-color .12s, box-shadow .12s;
}
.stat--ouvrable:hover { border-color: var(--primaire); box-shadow: 0 0 0 1px var(--primaire); }
.stat--ouvrable:hover .stat__libelle { color: var(--primaire); }

.colonnes { display: grid; grid-template-columns: 1.35fr 1fr; gap: 1.1rem; align-items: start; }

/* Une colonne est une pile de cartes, empilées avec le même écart que les colonnes. */
.colonne-pile { display: grid; gap: 1.1rem; align-content: start; }

/*
 * Un élément de grille refuse par défaut de descendre sous la largeur de son contenu.
 * Sans cela, une carte contenant un tableau large gardait sa largeur pendant que sa
 * piste rétrécissait : elle passait sous la colonne voisine, qui la recouvrait. La
 * règle vaut pour les colonnes ET pour les cartes qu'elles empilent — c'est la carte,
 * pas la colonne, qui portait le tableau. Rétrécies, elles laissent leur propre
 * enveloppe défiler.
 */
.colonnes > *, .colonne-pile > * { min-width: 0; }

/* -------------------------------- planning -------------------------------- */

.planning-barre {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon); padding: .6rem .8rem; margin-bottom: 1rem;
}
.planning-barre__periode { font-weight: 700; min-width: 15rem; }

.semaine { display: grid; grid-template-columns: repeat(var(--jours, 6), minmax(0, 1fr)); gap: .6rem; }
.jour {
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon); overflow: hidden; display: flex; flex-direction: column;
}
.jour--ferme { background: repeating-linear-gradient(45deg, var(--fond) 0 8px, var(--fond-doux) 8px 16px); }
.jour--aujourdhui { border-color: var(--primaire); box-shadow: 0 0 0 1px var(--primaire); }
.jour__entete { padding: .55rem .7rem; border-bottom: 1px solid var(--bordure); background: var(--surface-2); }
.jour__nom { font-weight: 700; text-transform: capitalize; font-size: .88rem; }
.jour__date { font-size: .74rem; color: var(--texte-doux); }
.jour__creneaux { padding: .4rem; display: flex; flex-direction: column; gap: .25rem; overflow-y: auto; max-height: 62vh; }

/*
 * Les séances d'un même créneau, côte à côte.
 *
 * « auto-fit » avec une largeur plancher fait tout le travail : en vue journée la
 * colonne est large, les cartes s'alignent ; en vue semaine elle ne l'est pas, et
 * elles se réempilent d'elles-mêmes. Aucune des deux vues n'a besoin d'être nommée.
 *
 * Le « min(13rem, 100%) » n'est pas une précaution : c'est lui qui fait tenir la
 * promesse ci-dessus. « minmax(13rem, 1fr) » ne descend JAMAIS sous 13rem — quand la
 * colonne est plus étroite, la piste déborde au lieu de se replier, et la journée
 * gagnait une barre de défilement horizontale. Avec « min », le plancher s'efface
 * devant la largeur disponible.
 */
.creneau-groupe {
  display: grid; gap: .25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
}

.creneau {
  display: flex; align-items: center; gap: .4rem; width: 100%;
  padding: .35rem .45rem; border-radius: var(--rayon-s);
  border: 1px dashed var(--bordure); background: var(--surface);
  /* La taille du texte dépend de la vue : voir « .semaine--jour .creneau » plus bas. */
  font: inherit; color: var(--texte-doux); cursor: pointer; text-align: left;
}
.creneau:hover { border-color: var(--primaire); color: var(--primaire); background: var(--primaire-doux); }
.creneau__heure { font-variant-numeric: tabular-nums; font-weight: 600; flex: none; }
/*
 * Le nom du patient pousse les pastilles au bout de la ligne. Quand la colonne est
 * trop étroite — la vue semaine — elles passent dessous plutôt que d'écraser le nom :
 * une carte un peu plus haute se lit, un nom tronqué ne se lit plus.
 */
.creneau__ligne { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; min-width: 0; }
/*
 * « min-width: 0 » et la coupure : un élément de flex refuse par défaut de descendre
 * sous la largeur de son contenu, et « KADJELOT COULIBALY » est un mot que rien ne
 * coupe. Sans ces deux lignes, un nom long élargit sa carte, la carte élargit la
 * colonne, et la journée se met à défiler de côté.
 */
.creneau__ligne .creneau__patient { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.creneau__motif { font-size: .72rem; color: var(--texte-doux); }
.creneau--indispo { cursor: not-allowed; background: var(--surface-2); border-style: solid; opacity: .7; }
.creneau--indispo:hover { border-color: var(--bordure); color: var(--texte-doux); background: var(--surface-2); }

.creneau--rdv {
  border-style: solid; border-left: 4px solid var(--primaire);
  background: var(--primaire-doux); color: var(--texte); cursor: pointer;
  flex-direction: column; align-items: stretch; gap: .1rem;
}
.creneau--rdv[draggable="true"] { cursor: grab; }
.creneau--rdv[draggable="true"]:active { cursor: grabbing; }

/* Pendant un glisser-déposer : la carte tirée s'efface, les créneaux libres s'allument. */
.creneau--deplace { opacity: .35; }
.semaine--glisse .creneau > * { pointer-events: none; }
.semaine--glisse .creneau[data-libre] {
  border-color: var(--primaire); border-style: dashed;
  background: var(--primaire-doux); color: var(--primaire-fonce);
}
.semaine--glisse .creneau[data-libre].creneau--cible {
  background: var(--primaire); border-style: solid; color: var(--sur-primaire);
  transform: scale(1.02);
}
.creneau--rdv:hover { filter: brightness(.98); background: var(--primaire-doux); border-color: var(--primaire); }
.creneau--rdv .creneau__patient { font-weight: 700; }
.creneau--rdv.st-confirme { border-left-color: var(--info); background: var(--info-doux); }
.creneau--rdv.st-honore   { border-left-color: var(--succes); background: var(--succes-doux); }
.creneau--rdv.st-absent   { border-left-color: var(--alerte); background: var(--alerte-doux); }
.creneau--rdv.st-annule   { border-left-color: var(--danger); background: var(--danger-doux); text-decoration: line-through; opacity: .75; }

/* -------------------------------- patients -------------------------------- */

.recherche { position: relative; flex: 1; min-width: 240px; max-width: 420px; }
.recherche input { padding-left: 2.1rem; }
.recherche::before { content: "🔍"; position: absolute; left: .7rem; top: 50%; transform: translateY(-50%); font-size: .85rem; }

.tableau { width: 100%; border-collapse: collapse; background: var(--surface); }
.tableau th, .tableau td { text-align: left; padding: .6rem .8rem; border-bottom: 1px solid var(--bordure); }
.tableau th { font-size: .76rem; text-transform: uppercase; letter-spacing: .04em; color: var(--texte-doux); background: var(--surface-2); }
.tableau tbody tr { cursor: pointer; }
.tableau tbody tr:hover { background: var(--primaire-doux); }
.tableau__actions { text-align: right; white-space: nowrap; }
/* Le bouton et l'icône de suppression s'alignent sur la même ligne de base optique. */
.tableau__actions .btn-icone { vertical-align: middle; }
.enveloppe-tableau { border: 1px solid var(--bordure); border-radius: var(--rayon); overflow: auto; }

/* Grille des horaires hebdomadaires (paramètres et récapitulatif du tableau de bord). */
.tableau--horaires td { padding: .35rem .5rem; vertical-align: middle; }
.tableau--horaires input[type="time"] { width: 100%; min-width: 6.4rem; padding: .35rem .4rem; }
.tableau--horaires input[type="number"] { width: 4.6rem; padding: .35rem .4rem; }
.tableau--horaires tbody tr { cursor: default; }
.tableau--horaires tbody tr:hover { background: transparent; }
.tableau--horaires .jour-ferme { background: var(--surface-2); }
.tableau--horaires .jour-ferme input:not([type="checkbox"]) { opacity: .45; }

.case { display: flex; align-items: center; gap: .4rem; margin: 0; font-weight: 600; color: var(--texte); }
.case input { flex: none; }

/*
 * Une rubrique de fiche : un rectangle à elle.
 *
 * Un simple filet séparait les blocs. Sur une fiche longue — identité, prises en charge,
 * règlements, examens, historique — l'œil ne savait plus où l'un finissait et où le
 * suivant commençait, et un trait se confond vite avec les bordures de tableau qui
 * l'entourent. Le cadre le dit sans qu'on ait à le chercher.
 *
 * Il ne vaut que pour les CONTENEURS. Porté par un titre (« h3 ») ou par un message,
 * « fiche-section » reste ce qu'il était : un trait qui ouvre une nouvelle partie à
 * l'intérieur d'un formulaire. Encadrer un titre seul n'aurait aucun sens.
 */
div.fiche-section {
  border: 1px solid var(--bordure);
  border-radius: var(--rayon-s);
  background: var(--surface);
  padding: .9rem 1rem;
  margin-top: .9rem;
}
h3.fiche-section, p.fiche-section {
  border-top: 1px solid var(--bordure); padding-top: .9rem; margin-top: .9rem;
}
.def { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .55rem .9rem; }
.def div { min-width: 0; }
.def dt { font-size: .74rem; color: var(--texte-doux); font-weight: 600; text-transform: uppercase; letter-spacing: .03em; }
.def dd { margin: 0; word-break: break-word; }

/* Cures de soins, sur la fiche patient : une ordonnance par bloc. */
.cures { display: grid; gap: .6rem; margin-top: .5rem; }
.cure {
  padding: .6rem .75rem; border: 1px solid var(--bordure);
  border-left: 4px solid var(--primaire); border-radius: var(--rayon-s);
  background: var(--surface);
}
/* Une cure close reste lisible, mais cesse de réclamer le regard. */
.cure--close { border-left-color: var(--bordure); background: var(--surface-2); }

.documents { display: grid; gap: .5rem; }
.document {
  display: flex; align-items: center; gap: .7rem; padding: .55rem .7rem;
  border: 1px solid var(--bordure); border-radius: var(--rayon-s); background: var(--surface);
}
.document__icone { font-size: 1.3rem; }
.document__infos { flex: 1; min-width: 0; }
.document__titre { font-weight: 650; }
.document__meta { font-size: .76rem; color: var(--texte-doux); }

/* Aperçu d'une pièce jointe : imagerie, PDF ou compte rendu texte. */
.apercu {
  background: var(--fond-visionneuse); border-radius: var(--rayon-s);
  display: grid; place-items: center; padding: .5rem; overflow: auto; max-height: 70vh;
}
.apercu img { max-width: 100%; max-height: 66vh; object-fit: contain; display: block; }
.apercu iframe { width: 100%; height: 66vh; border: 0; border-radius: 6px; background: #fff; }
/* Zoomée, l'image déborde et le cadre défile : utile pour scruter une radio. */
.apercu--zoom { place-items: start; min-height: 40vh; }
.apercu--zoom img { max-width: none; max-height: none; }

.zoom { display: inline-flex; align-items: center; border: 1px solid var(--bordure); border-radius: var(--rayon-s); }
.zoom .btn-icone { padding: .3rem .5rem; font-weight: 700; }
.zoom__valeur {
  min-width: 4.4rem; font-size: .78rem; font-weight: 600; font-variant-numeric: tabular-nums;
  border-inline: 1px solid var(--bordure); border-radius: 0;
}

.apercu__texte {
  margin: 0; padding: .9rem; max-height: 66vh; overflow: auto;
  background: var(--surface-2); border-radius: var(--rayon-s);
  white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: .84rem;
}

/* --------------------------------- modale --------------------------------- */

.modale { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 1rem; }
.modale__fond { position: absolute; inset: 0; background: var(--voile-modale); }
.modale__boite {
  position: relative; background: var(--surface); border-radius: var(--rayon);
  width: min(720px, 100%); max-height: 92vh; display: flex; flex-direction: column;
  box-shadow: var(--ombre-modale);
}
.modale--large .modale__boite { width: min(1060px, 100%); }
.modale__entete { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.2rem; border-bottom: 1px solid var(--bordure); }
.modale__entete h2 { margin: 0; flex: 1; }
.modale__corps { padding: 1.2rem; overflow-y: auto; }
.modale__pied { display: flex; gap: .5rem; justify-content: flex-end; flex-wrap: wrap; margin-top: 1.1rem; padding-top: 1rem; border-top: 1px solid var(--bordure); }

/* ------------------------------ notifications ------------------------------ */

.notifications { position: fixed; right: 1rem; bottom: 1rem; z-index: 80; display: grid; gap: .5rem; max-width: 380px; }
.notification {
  display: flex; align-items: center; gap: .8rem;
  padding: .7rem .9rem; border-radius: var(--rayon-s); background: var(--inverse); color: var(--sur-inverse);
  box-shadow: var(--ombre); font-size: .87rem; animation: apparait .18s ease-out;
}
.notification__action {
  flex: none; padding: .25rem .6rem; border-radius: 6px; cursor: pointer;
  border: 1px solid currentColor; background: color-mix(in srgb, currentColor 14%, transparent);
  color: inherit; font: inherit; font-weight: 700;
}
.notification__action:hover { background: color-mix(in srgb, currentColor 28%, transparent); }
.notification--succes { background: var(--succes); color: var(--sur-primaire); }
.notification--erreur { background: var(--danger); color: var(--sur-primaire); }
@keyframes apparait { from { opacity: 0; transform: translateY(8px); } }

/* -------------------------------- responsive -------------------------------- */

@media (max-width: 1100px) {
  .colonnes { grid-template-columns: 1fr; }
  .semaine { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ============================ Téléphones et tablettes ============================ */

@media (max-width: 820px) {
  .auth { grid-template-columns: 1fr; min-height: 100dvh; }
  .auth__marque { padding: calc(2rem + env(safe-area-inset-top)) 1.5rem 1rem; text-align: center; }
  .auth__marque h1 { font-size: 1.9rem; }
  .auth__marque p { margin-inline: auto; }
  /* Les arguments restent alignés à gauche : centrés, les coches flottent loin du texte. */
  .auth__atouts { text-align: left; max-width: 30rem; margin-inline: auto; }
  .auth__atouts li { padding-left: 1.4rem; }
  .auth__panneau { padding: 1.5rem 1.15rem calc(2.5rem + env(safe-area-inset-bottom)); }

  /* La barre latérale se scinde : identité en haut, navigation en bas sous le pouce. */
  .app { grid-template-columns: 1fr; min-height: 100dvh; }

  .barre-laterale {
    position: fixed; inset: 0 0 auto 0; z-index: 30;
    height: auto; flex-direction: row; align-items: center; gap: .6rem;
    padding: .5rem .8rem; padding-top: calc(.5rem + env(safe-area-inset-top));
    box-shadow: 0 1px 0 var(--barre-voile);
  }
  .barre-laterale__marque { flex: 1; min-width: 0; gap: .5rem; padding: 0; }
  .barre-laterale__marque .logo { width: 32px; height: 32px; font-size: 17px; border-radius: 9px; }
  .barre-laterale__titre { font-size: .95rem; }
  .barre-laterale__cabinet { max-width: 9rem; }

  .barre-laterale__pied {
    border-top: 0; padding-top: 0; display: flex; align-items: center; gap: .5rem; flex: none;
  }
  .praticien { margin: 0; gap: .45rem; }
  .praticien__avatar { width: 32px; height: 32px; font-size: .78rem; }
  /* Seul le bloc nom + spécialité disparaît ; l'avatar reste comme repère de compte. */
  .praticien > div:not(.praticien__avatar) { display: none; }
  .barre-laterale__pied .btn { width: auto; padding: .45rem .7rem; font-size: .78rem; }

  .nav {
    position: fixed; inset: auto 0 0 0; z-index: 30;
    flex-direction: row; gap: 0; background: var(--barre);
    border-top: 1px solid var(--barre-voile);
    padding: .25rem .2rem; padding-bottom: calc(.25rem + env(safe-area-inset-bottom));
  }
  .nav__lien {
    flex: 1; min-width: 0; flex-direction: column; gap: .12rem;
    padding: .4rem .15rem; font-size: .64rem; line-height: 1.15; text-align: center;
    border-radius: 10px;
  }
  .nav__lien span { font-size: 1.15rem; }

  /* Le contenu se glisse entre les deux barres fixes. */
  .contenu {
    padding: .9rem .9rem 1.5rem;
    padding-top: calc(3.9rem + env(safe-area-inset-top));
    padding-bottom: calc(4.6rem + env(safe-area-inset-bottom));
  }

  .entete-vue { gap: .5rem; margin-bottom: .9rem; }
  .entete-vue h1 { font-size: 1.35rem; }
  .entete-vue .espace { display: none; }
  .carte { padding: .9rem; }
  .colonnes { gap: .8rem; }
  .grille--2, .grille--3 { grid-template-columns: 1fr; }

  .statistiques { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: .55rem; }
  .stat { padding: .6rem .7rem; }
  .stat__valeur { font-size: 1.4rem; }
  .stat__libelle { font-size: .72rem; }

  .planning-barre { gap: .4rem; padding: .5rem; }
  .planning-barre__periode { min-width: 0; flex: 1 1 100%; order: -1; font-size: .92rem; }
  .jour__creneaux { max-height: none; }

  .offres { grid-template-columns: 1fr; }
  .notifications { right: .7rem; left: .7rem; bottom: calc(4.9rem + env(safe-area-inset-bottom)); max-width: none; }

  /* Les fenêtres deviennent des panneaux glissés depuis le bas. */
  .modale { place-items: end stretch; padding: 0; }
  .modale__boite {
    width: 100%; max-height: 92dvh;
    border-radius: var(--rayon) var(--rayon) 0 0;
    animation: monte .22s ease-out;
  }
  .modale__entete {
    position: sticky; top: 0; z-index: 1; background: var(--surface);
    border-radius: var(--rayon) var(--rayon) 0 0;
  }
  .modale__corps { padding: 1rem 1rem calc(1.2rem + env(safe-area-inset-bottom)); }
  .modale__pied { position: sticky; bottom: 0; background: var(--surface); padding-bottom: .4rem; }
  .modale--large .modale__boite { width: 100%; }
}

@keyframes monte { from { transform: translateY(14px); opacity: 0; } }

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

/*
 * Vue journée : une seule colonne, sur toute la largeur.
 *
 * Après les requêtes de média, et volontairement : celle de 1100 px impose deux
 * colonnes pour resserrer la semaine, ce qui n'a aucun sens quand il n'y a qu'un jour
 * — la moitié de l'écran restait vide, et les séances d'un même créneau n'avaient pas
 * la place de se ranger côte à côte. Même spécificité, donc c'est l'ordre qui tranche.
 */
.semaine--jour { grid-template-columns: minmax(0, 1fr); }

/*
 * En vue semaine, chaque colonne est une fenêtre plafonnée : sept ascenseurs valent
 * mieux qu'une page de sept jours dépliés. En vue journée il n'y a qu'une colonne, et
 * ce plafond n'apporte plus rien — il enferme la journée dans un cadre qu'il faut
 * faire défiler alors que la page, elle, ne bouge pas. On le lève : c'est la page qui
 * défile, et la journée se lit d'un bloc.
 */
.semaine--jour .jour__creneaux { max-height: none; overflow-y: visible; }

/*
 * Le texte des cartes est plus petit en vue semaine qu'en vue journée.
 *
 * Six colonnes se partagent la largeur d'un écran : ce qui se lit à l'aise sur une
 * colonne pleine y devient serré, et les pastilles « non payé » finissaient sous le
 * nom faute de place sur la ligne. Deux dixièmes de millimètre gagnés par caractère
 * suffisent à les ramener à côté. La vue journée, elle, a toute la place : elle garde
 * la taille d'origine, et c'est là qu'on lit une fiche de près.
 */
.creneau { font-size: .74rem; }
.creneau--rdv .creneau__patient { font-size: .78rem; }
.semaine--jour .creneau { font-size: .78rem; }
.semaine--jour .creneau--rdv .creneau__patient { font-size: .82rem; }

/*
 * Décalage des séances qui se chevauchent, en vue journée.
 *
 * Deux séances d'un même créneau se posent côte à côte. Tant qu'elles commencent à la
 * même heure, les lire à la même hauteur est juste ; dès que l'une démarre dix minutes
 * après l'autre, c'est faux — et c'est exactement ce qu'on ne voyait pas. Celle qui
 * commence plus tard descend donc de ce qu'elle a de retard, comme sur un agenda
 * Outlook : l'œil lit l'écart avant de lire les heures.
 *
 * « --decalage » est un nombre de minutes, posé par le script. Un créneau fait une
 * trentaine de minutes pour une carte d'environ deux rem et demie : neuf centièmes de
 * rem par minute gardent la proportion. Le plafond protège d'un rendez-vous hors trame
 * qui commencerait beaucoup plus tard et creuserait un trou dans la journée.
 *
 * Sans « align-items: start », la grille étire toutes les cartes à la même hauteur et
 * la descente ne se verrait pas : la carte décalée se contenterait d'être plus courte.
 */
.semaine--jour .creneau-groupe { align-items: start; }
.semaine--jour .creneau--decale {
  margin-top: min(calc(var(--decalage) * .09rem), 2.4rem);
}

/*
 * La frise : la journée sur un axe du temps.
 *
 * Tout se règle sur « --px », la hauteur d'une minute. À 1,6 px, une séance de 45 min
 * fait 72 px — deux lignes de texte y tiennent — et une journée de dix heures tient en
 * une page qu'on fait défiler une fois. Chaque élément porte son départ « --t » et sa
 * durée « --d » en minutes, comptés depuis le haut du cadre : la mise en page est la
 * même arithmétique que l'horaire, et rien ne peut mentir sur sa position.
 */
.frise {
  --px: 1.6px;
  display: grid; grid-template-columns: 3rem minmax(0, 1fr); gap: .5rem;
  padding: .5rem .7rem .9rem;
}
.frise__heures, .frise__scene { position: relative; height: calc(var(--minutes) * var(--px)); }

.frise__heure {
  position: absolute; top: calc(var(--t) * var(--px)); right: 0;
  transform: translateY(-.55em);
  font-size: .72rem; font-variant-numeric: tabular-nums; color: var(--texte-doux);
}

/* Un trait par heure pleine, dessiné par le fond plutôt que par soixante éléments. */
.frise__scene {
  border-left: 1px solid var(--bordure);
  background-image: repeating-linear-gradient(to bottom,
    var(--bordure) 0 1px, transparent 1px calc(60 * var(--px)));
}

.frise__hors, .frise__pause, .frise__revolu, .frise__libre, .creneau--frise {
  position: absolute; top: calc(var(--t) * var(--px)); height: calc(var(--d) * var(--px));
}
.frise__hors, .frise__pause, .frise__revolu {
  left: 0; right: 0; pointer-events: none; overflow: hidden;
}
.frise__hors { background: var(--surface-2); }
.frise__revolu { background: rgb(0 0 0 / .035); }
.frise__pause {
  background: var(--surface-2);
  display: flex; align-items: center; justify-content: center;
  font-size: .72rem; color: var(--texte-doux);
}

/*
 * Les bandes libres restent invisibles tant qu'on ne les survole pas : dessiner soixante
 * créneaux vides par journée masquerait les séances, qui sont ce qu'on vient lire. Elles
 * sont posées avant les séances, donc dessous — là où deux séances ne prennent que la
 * moitié de la largeur, la place restante se voit et reste cliquable.
 */
.frise__libre {
  left: 0; right: 0; padding: 0 .3rem; border: 0; border-radius: var(--rayon-s);
  background: transparent; color: transparent; font: inherit; font-size: .68rem;
  display: flex; align-items: center; cursor: pointer;
}
.frise__libre:hover { background: var(--primaire-doux); color: var(--primaire); }
.semaine--glisse .frise__libre { background: var(--primaire-doux); color: var(--primaire); }
.semaine--glisse .frise__libre.creneau--cible {
  background: var(--primaire); color: var(--sur-primaire);
}
/*
 * Pendant un déplacement, les séances laissent passer la souris.
 *
 * Sur la frise les bandes libres sont dessous : sans cela, une séance pleine largeur
 * couvrirait la bande qu'on vise et le dépôt serait impossible. Rien n'est perdu — on
 * ne dépose pas sur une séance, et là où il n'y a plus de place il n'y a pas de bande.
 */
.semaine--glisse .creneau--frise { pointer-events: none; }
.semaine--glisse .frise__libre > * { pointer-events: none; }

/*
 * Une séance occupe sa durée en hauteur et sa part de largeur. « --colonne » est son
 * rang dans la grappe de séances qui se recouvrent, « --colonnes » la taille de cette
 * grappe : seule une séance à cheval sur une autre se rétrécit, la journée normale garde
 * ses cartes pleine largeur.
 */
.creneau--frise {
  left: calc(var(--colonne) / var(--colonnes) * 100%);
  width: calc(100% / var(--colonnes));
  padding: .25rem .4rem; overflow: hidden;
  /* Deux séances voisines ne doivent pas se toucher ni masquer le trait de l'heure. */
  box-shadow: 0 1px 2px rgb(0 0 0 / .06);
}
.creneau--frise .creneau__motif { display: none; }
/* Une séance courte n'a de place que pour sa première ligne : le nom y passe avant tout. */
.creneau--frise .creneau__ligne { flex-wrap: nowrap; }

.frise__annules {
  display: grid; gap: .25rem; padding: 0 .7rem .7rem;
}

@media (max-width: 560px) {
  /* Les tableaux se replient en fiches : une ligne = un bloc lisible au pouce. */
  .tableau--fiches thead { display: none; }
  .tableau--fiches, .tableau--fiches tbody, .tableau--fiches tr, .tableau--fiches td { display: block; }
  .tableau--fiches tr {
    border-bottom: 1px solid var(--bordure); padding: .7rem .8rem;
    display: grid; grid-template-columns: 1fr auto; gap: .15rem .6rem;
  }
  .tableau--fiches td { border: 0; padding: 0; }
  .tableau--fiches td[data-etiquette]::before {
    content: attr(data-etiquette) " · ";
    font-size: .74rem; font-weight: 600; color: var(--texte-doux);
  }
  .tableau--fiches td[data-principal] { grid-column: 1 / -1; font-size: 1rem; }
  .tableau--fiches td.tableau__actions { grid-column: 1 / -1; text-align: left; margin-top: .4rem; }
  .enveloppe-tableau:has(.tableau--fiches) { border: 0; }

  .rangee > .btn { flex: 1 1 auto; }
}

/* ===================== Couche SaaS : cabinet et abonnement ===================== */

.barre-laterale__cabinet {
  display: block; color: var(--barre-texte-doux); font-size: .72rem; line-height: 1.2;
  max-width: 11rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Bandeau d'état de l'abonnement, en tête de chaque vue. */
.bandeau {
  display: flex; align-items: center; gap: .9rem; flex-wrap: wrap;
  padding: .6rem .9rem; margin-bottom: 1.1rem;
  border-radius: var(--rayon-s); font-size: .87rem; font-weight: 500;
  background: var(--primaire-doux); color: var(--primaire-fonce);
  border: 1px solid var(--primaire-bordure);
}
.bandeau--alerte { background: var(--alerte-doux); color: var(--alerte); border-color: var(--alerte-bordure); }
.bandeau .btn { margin-left: auto; }

/* Catalogue des offres. */
.offres { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .8rem; margin-top: .6rem; }
.offre {
  border: 1px solid var(--bordure); border-radius: var(--rayon-s);
  padding: .8rem; background: var(--surface); display: flex; flex-direction: column; gap: .35rem;
}
.offre--actuelle { border-color: var(--primaire); box-shadow: 0 0 0 1px var(--primaire); }
.offre__nom { font-weight: 700; }
.offre__prix { font-size: 1.5rem; font-weight: 700; line-height: 1.1; font-family: var(--police-titre); }
.offre__prix small { font-size: .74rem; font-weight: 600; color: var(--texte-doux); }
.offre__detail { font-size: .76rem; color: var(--texte-doux); }
.offre__argument { margin: 0 0 .4rem; font-size: .8rem; flex: 1; }

/* Journal d'audit. */
.journal { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow-y: auto; }
.journal li {
  display: grid; grid-template-columns: 9.5rem 8rem 1fr; gap: .5rem;
  padding: .35rem 0; border-bottom: 1px solid var(--bordure); font-size: .8rem;
}
.journal__date { color: var(--texte-doux); font-variant-numeric: tabular-nums; }
.journal__qui { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }

@media (max-width: 860px) {
  .journal li { grid-template-columns: 1fr; gap: .1rem; }
  .bandeau .btn { margin-left: 0; }
}

/* ------------------ logo du cabinet et photo du patient ------------------ */

/* Le logo remplace l'icône par défaut dans la barre latérale : même gabarit. */
.logo img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }

.apercu-logo {
  width: 88px; height: 88px; border-radius: 12px; flex: none;
  border: 1px dashed var(--bordure); background: var(--fond-doux);
  display: grid; place-items: center; overflow: hidden;
}
.apercu-logo img { width: 100%; height: 100%; object-fit: contain; }
.apercu-logo__vide { font-size: .72rem; color: var(--texte-doux); text-align: center; padding: .3rem; }

/* Prise de vue : le flux occupe la largeur, en carré comme le portrait qui en sortira. */
.camera {
  aspect-ratio: 1; width: min(420px, 100%); margin: 0 auto;
  background: var(--fond-visionneuse); border-radius: var(--rayon);
  overflow: hidden; display: grid; place-items: center;
}
.camera video { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Portrait du patient, en tête de sa fiche. */
.photo-patient {
  width: 96px; height: 96px; border-radius: 50%; flex: none; overflow: hidden;
  border: 2px solid var(--bordure); background: var(--fond-doux);
  display: grid; place-items: center;
}
.photo-patient img { width: 100%; height: 100%; object-fit: cover; }
.photo-patient__initiales { font-size: 1.6rem; font-weight: 700; color: var(--texte-doux); }

/* L'avatar accueille un portrait à la place des initiales. */
.praticien__avatar { overflow: hidden; }
.praticien__avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Vignette d'un membre dans la liste de l'équipe. */
.vignette-membre {
  width: 38px; height: 38px; border-radius: 50%; flex: none; overflow: hidden;
  background: var(--fond-doux); border: 1px solid var(--bordure);
  display: grid; place-items: center;
  font-size: .78rem; font-weight: 700; color: var(--texte-doux);
}
.vignette-membre img { width: 100%; height: 100%; object-fit: cover; }

/* Bascule jour / semaine dans la barre du planning. */
.onglets--compact { margin: 0; width: auto; flex: none; }
.onglets--compact .onglet { padding: .38rem .85rem; font-size: .82rem; }

/* Règlement d'une séance, sur la carte du planning. */
.creneau__regle,
.creneau__impaye {
  display: inline-block; flex: none; padding: .05rem .4rem;
  border-radius: 999px; font-size: .68rem; font-weight: 700; letter-spacing: .02em;
}
.creneau__regle { background: var(--succes-doux); color: var(--succes); }
.creneau__impaye { background: var(--danger-doux); color: var(--danger); }

/* Séance passée dont on n'a pas dit si elle avait eu lieu. */
.creneau__a-pointer {
  display: inline-block; flex: none; padding: .05rem .4rem;
  border-radius: 999px; font-size: .68rem; font-weight: 700;
  background: var(--alerte-doux); color: var(--alerte);
}

/* Créneau déjà passé : ouvert à la saisie, mais visuellement en retrait. */
.creneau--revolu { opacity: .62; }
.creneau--revolu:hover { opacity: 1; }

/* Bilan du jour dans l'en-tête de colonne : séances pointées et séances réglées. */
.jour__bilan {
  display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .15rem;
  font-size: .7rem; font-weight: 700; color: var(--texte-doux);
}
.jour__bilan span { white-space: nowrap; }
.jour__bilan--complet { color: var(--succes); }

/* =============================== facturation =============================== */

/*
 * Deux colonnes : à gauche on fabrique une facture, à droite on retrouve celles qui
 * existent. Sous 60rem elles s'empilent — la fabrication d'abord, qui est ce qu'on
 * vient faire.
 */
.grille-facturation {
  display: grid; gap: 1rem;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
}
@media (max-width: 60rem) { .grille-facturation { grid-template-columns: 1fr; } }

/* Le total avant émission : les mêmes lignes que le bas de la facture, dans le même ordre. */
.recap {
  display: grid; gap: .3rem; margin-top: .9rem; padding: .7rem .9rem;
  border: 1px solid var(--bordure); border-radius: var(--rayon-s); background: var(--fond-doux);
}
.recap > div { display: flex; justify-content: space-between; gap: 1rem; }
.recap__du { padding-top: .35rem; border-top: 1px solid var(--bordure); font-size: 1.05rem; }
.recap__du strong { color: var(--primaire); }

/*
 * La facture elle-même. Elle est dessinée pour le papier : fond blanc, texte noir,
 * et les mêmes règles à l'écran — ce qu'on relit doit être ce qu'on imprimera, sans
 * surprise au moment de lancer l'impression.
 */
.facture {
  background: #fff; color: #1a1a1a;
  padding: 1.6rem; border: 1px solid var(--bordure); border-radius: var(--rayon-s);
  font-size: .9rem; line-height: 1.5;
}
.facture__entete {
  display: flex; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap;
  padding-bottom: 1rem; border-bottom: 2px solid #1a1a1a;
}
/* Le logo à gauche, l'adresse à côté : l'œil lit l'image puis le nom, dans cet ordre. */
.facture__identite { display: flex; align-items: flex-start; gap: .9rem; }
.facture__logo {
  flex: none; width: auto; max-width: 120px; max-height: 68px;
  object-fit: contain; object-position: left top;
}
.facture__cabinet { display: block; font-size: 1.15rem; margin-bottom: .2rem; }
.facture__piece { text-align: right; }
.facture__titre { font-size: 1.5rem; font-weight: 700; letter-spacing: .08em; }
.facture__parties {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin: 1.2rem 0;
}
@media (max-width: 34rem) { .facture__parties { grid-template-columns: 1fr; } }
.facture__etiquette {
  display: block; font-size: .68rem; text-transform: uppercase;
  letter-spacing: .06em; color: #666;
}
.facture__lignes { width: 100%; border-collapse: collapse; margin-top: .6rem; }
.facture__lignes th, .facture__lignes td { padding: .45rem .5rem; }
/*
 * La désignation prend ce qui reste ; la quantité et les montants ne gardent que la
 * place qu'il leur faut. Sans ces largeurs, « Qté » s'étalait sur un quart de la page
 * pour y afficher « 12 ».
 */
.facture__lignes th:first-child, .facture__lignes td:first-child { width: auto; }
.facture__lignes th:nth-child(2), .facture__lignes td:nth-child(2) { width: 4rem; }
.facture__lignes th:nth-child(3), .facture__lignes td:nth-child(3) { width: 8rem; }
.facture__lignes th:last-child, .facture__lignes td:last-child { width: 8rem; }
.facture__lignes thead th {
  border-bottom: 1px solid #1a1a1a; text-align: left;
  font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
}
.facture__lignes tbody tr { border-bottom: 1px solid #e5e5e5; }
.facture__lignes tfoot td { padding-top: .5rem; }
.facture__lignes tfoot tr:first-child td { border-top: 1px solid #1a1a1a; }
.facture__du td { font-size: 1.1rem; border-top: 1px solid #1a1a1a; }
.facture__notes { margin-top: 1rem; font-style: italic; }
.facture__pied { margin-top: 1.4rem; font-size: .75rem; color: #666; }

/* Une facture annulée reste lisible, mais le dit avant tout le reste. */
.facture__annulee {
  margin: 0 0 1rem; padding: .5rem .8rem; border: 2px solid #b3261e;
  color: #b3261e; font-weight: 700; letter-spacing: .08em; text-align: center;
}

/*
 * Impression de la facture.
 *
 * Ces règles s'appliquent dans le document autonome que « facturation.js » fabrique —
 * il ne contient que la facture, et cette feuille de style. Il n'y a donc rien à
 * masquer : une tentative précédente le faisait depuis la page elle-même, et rendait
 * une feuille blanche parce que la modale qui porte la facture est en « position:
 * fixed », plafonnée à 92vh et en « overflow: auto ». Un ancêtre qui découpe découpe
 * aussi à l'impression.
 *
 * C'est le chemin du PDF : « Enregistrer au format PDF » est une destination
 * d'impression sur tous les systèmes, et cela évite d'embarquer une bibliothèque.
 */
@media print {
  /*
   * Marge de page nulle, et c'est voulu.
   *
   * Les navigateurs impriment leur propre en-tête et leur propre pied de page — le
   * titre du document en haut, l'adresse du serveur et le numéro de page en bas — et
   * ils les logent dans la marge de la feuille. Aucune propriete CSS ne les eteint :
   * c'est un reglage de la boite d'impression, que le cabinet n'a pas a decocher a
   * chaque facture. Sans marge, ils n'ont plus ou se mettre.
   *
   * La marge du papier devient donc une marge interieure de la facture. Contrepartie
   * assumee : sur une facture de deux pages, la seconde commence plus haut — une
   * marge interieure ne se repete pas d'une page a l'autre. Une facture tient sur une
   * page dans l'immense majorite des cas, et une bordure manquante en haut de la
   * seconde coute moins cher qu'une adresse de serveur en bas de chacune.
   */
  @page { margin: 0; }

  /* Seule sur la feuille, la facture n'a plus de cadre, mais porte la marge du papier. */
  .facture { padding: 15mm 13mm; border: 0; border-radius: 0; font-size: 11pt; }

  /* Le logo s'imprime tel quel : sans cela, les navigateurs omettent les images de
     fond et compriment parfois celles qu'ils gardent. */
  .facture__logo { print-color-adjust: exact; -webkit-print-color-adjust: exact; }

  /* Rien de tout cela ne suit la facture dans le document d'impression ; la règle
     reste pour le cas où la page entière serait imprimée depuis le navigateur. */
  [data-sans-impression] { display: none; }

  /* Une facture de trente séances tient sur deux feuilles : l'en-tête du tableau se
     répète en haut de chacune, et une ligne ne se coupe pas en deux. */
  .facture__lignes thead { display: table-header-group; }
  .facture__lignes tr { break-inside: avoid; }
  .facture__entete, .facture__parties { break-inside: avoid; }
}
