:root {
  --bg: #0b141a;
  --panel: #142630;
  --panel-2: #1a303c;
  --panel-3: #203946;
  --text: #f4eee5;
  --muted: #9eabb2;
  --gold: #d7b36b;
  --copper: #c96d38;
  --copper-dark: #a94f29;
  --green: #55b58a;
  --red: #d66f68;
  --amber: #d69a43;
  --blue: #71a4d2;
  --status-in-progress: var(--green);
  --status-waiting: var(--copper);
  --status-completed: var(--blue);
  --status-no-show: var(--red);
  --connection-connected: var(--green);
  --connection-disconnected: var(--red);
  --line: rgba(215, 179, 107, .18);
  --gutter: clamp(10px, .8vw, 16px);
  --gap: clamp(10px, .75vw, 15px);
  --radius: clamp(18px, 1.35vw, 26px);
  --shadow: 0 18px 44px rgba(0, 0, 0, .28);
}

* { box-sizing: border-box; }

html,
body {
  width: 100%;
  min-height: 100%;
  margin: 0;
  overflow-x: hidden;
}

body {
  color: var(--text);
  background:
    radial-gradient(circle at 16% -8%, rgba(53, 85, 101, .2), transparent 34%),
    linear-gradient(145deg, #0f1b22, var(--bg));
  font-family: "Segoe UI", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; }
button:focus-visible { outline: 3px solid rgba(215, 179, 107, .5); outline-offset: 3px; }

.app-shell {
  display: grid;
  /* Trois rangées depuis B002 : la barre, la bande d'environnement, le
     contenu. La bande est en `auto` — elle occupe sa hauteur de texte quand
     elle paraît, et rien du tout quand elle est masquée. Sans cette rangée
     explicite, elle prenait la rangée souple et poussait tout l'écran. */
  grid-template-rows: clamp(68px, 8.4vh, 82px) auto minmax(0, 1fr);
  width: 100vw;
  height: 100vh;
  min-height: 100dvh;
}

/*
 * L'en-tête garde sa grille d'origine (contenu large + actions rapides).
 * Le contenu, lui, a la sienne depuis la refonte du 30/07/2026 : le planning
 * passe à GAUCHE et la fiche client à DROITE, à la demande de David. Les deux
 * grilles ne s'alignent donc plus — c'est le prix assumé de la permutation.
 */
.topbar,
.workspace {
  display: grid;
  gap: var(--gap);
  padding-right: var(--gutter);
  padding-left: var(--gutter);
}

.topbar { grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }

/*
 * GAUCHE : le planning. DROITE : le client et l'encaissement.
 * David, 30/07 : « le calendrier est beaucoup trop grand, il faut le mettre
 * à peu près sur le tiers de la page, voire même un quart, ça suffira. »
 * 1fr / 3fr = 25 % / 75 %.
 */
.workspace { grid-template-columns: minmax(232px, 1fr) minmax(0, 3fr); }

.topbar {
  position: relative;
  z-index: 5;
  align-items: center;
  border-bottom: 1px solid var(--line);
  background: rgba(8, 18, 25, .98);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .24);
  overflow: visible;
}

.header-main {
  display: grid;
  grid-template-columns: clamp(82px, 6vw, 108px) minmax(0, 1fr);
  align-items: center;
  min-width: 0;
  height: 100%;
}

.brand { display: flex; align-items: center; height: 100%; }
.brand-mark {
  display: grid;
  place-items: center;
  width: clamp(78px, 5.5vw, 100px);
  aspect-ratio: 1;
  overflow: hidden;
  border: 3px solid #132733;
  border-radius: 50%;
  background: #050a0e;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .42), 0 0 0 1px rgba(215, 179, 107, .26);
  transform: translateY(5px);
}
.brand-mark img { display: block; width: 100%; height: 100%; object-fit: cover; }

.day-state {
  display: grid;
  /* B002 — une colonne de plus : le bandeau d'environnement s'insère entre
     l'heure et le voyant de connexion. `auto` et non `1fr` : il prend ce qu'il
     lui faut et ne pousse rien. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, auto) minmax(0, 1fr);
  align-items: center;
  min-width: 0;
  height: 100%;
}
.date-stack { display: flex; align-items: center; justify-content: center; gap: clamp(9px, 1vw, 18px); min-width: 0; }
.date-stack strong,
.date-stack small,
.day-state time,
.connection-state { white-space: nowrap; }
.date-stack strong { font-size: clamp(15px, 1.15vw, 22px); font-weight: 800; }
.date-stack small { padding-left: clamp(9px, 1vw, 18px); border-left: 1px solid var(--line); color: var(--gold); font-size: clamp(14px, 1.05vw, 20px); font-weight: 850; }
.day-state time { min-width: clamp(64px, 5vw, 92px); padding: 0 clamp(10px, 1vw, 20px); border-right: 1px solid var(--line); border-left: 1px solid var(--line); color: #fff8ed; text-align: center; font: 700 clamp(23px, 1.7vw, 31px)/1 Georgia, serif; }
.connection-state { display: grid; place-items: center; justify-self: center; width: 28px; height: 28px; }
.connection-state i { display: block; width: 9px; height: 9px; border-radius: 50%; }
.connection-state.is-connected i { background: var(--connection-connected); box-shadow: 0 0 0 5px rgba(85, 181, 138, .12); }
.connection-state.is-disconnected i { background: var(--connection-disconnected); box-shadow: 0 0 0 5px rgba(214, 111, 104, .12); }

/* ==========================================================================
   B002 — OÙ TRAVAILLE-T-ON
   --------------------------------------------------------------------------
   Le bandeau est permanent et sur tous les écrans, parce que la barre du haut
   l'est. Il ne se replie pas et ne se ferme pas : c'est le seul endroit qui
   distingue un Hub d'entraînement d'un Hub de production, lesquels sont
   autrement identiques au pixel près.

   Les couleurs disent le degré d'attention, pas la marque : le cuivre pour
   l'entraînement (ceci n'est pas réel), le vert sobre pour la production
   (tout est en ordre, et c'est bien du réel), le rouge pour ce qui ne
   concorde pas. L'indéterminé prend l'ambre — on ne sait pas, ce n'est pas
   la même chose que « c'est faux ».
   ========================================================================== */

/* Deux lignes, et non une seule : d'un seul tenant, le bandeau s'allongeait
   assez pour rogner la date. La première ligne porte ce qui décide — où l'on
   est, sur quel terminal ; la seconde porte les deux versions, nommées. Tout
   reste visible en permanence, rien n'est replié. */
.environnement-badge {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  justify-self: center;
  gap: 1px;
  max-width: 100%;
  padding: 4px clamp(8px, .7vw, 14px);
  border: 1px solid currentColor;
  border-radius: clamp(10px, .8vw, 14px);
  min-width: 0;
  line-height: 1.15;
}
.environnement-badge b,
.environnement-badge small {
  display: block;
  max-width: 100%;
  overflow: hidden;
  color: inherit;
  letter-spacing: .04em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}
.environnement-badge b { font-size: clamp(9px, .62vw, 12px); font-weight: 850; }
.environnement-badge small { font-size: clamp(8px, .5vw, 10px); font-weight: 700; opacity: .85; }
/* Non confirmé par le serveur : le trait devient discontinu. La forme dit ce
   que le mot dit déjà — l'information n'est pas vérifiée. */
.environnement-badge.is-non-confirme { border-style: dashed; }

.environnement-badge.is-entrainement { color: var(--copper); background: rgba(201, 109, 56, .12); }
.environnement-badge.is-production   { color: var(--green);  background: rgba(85, 181, 138, .12); }
.environnement-badge.is-indetermine  { color: var(--amber);  background: rgba(214, 154, 67, .12); }
.environnement-badge.is-incoherent   { color: var(--red);    background: rgba(214, 111, 104, .16); }

/* La bande. Aucune fermeture, aucun repli : elle disparaît quand la cause
   disparaît, et pas avant. */
.environnement-bande {
  margin: 0;
  padding: clamp(6px, .55vw, 10px) var(--gutter);
  font-size: clamp(11px, .72vw, 14px);
  font-weight: 700;
  line-height: 1.35;
  text-align: center;
}
.environnement-bande[hidden] { display: none; }
.environnement-bande.is-entrainement { color: #0b141a; background: var(--copper); }
.environnement-bande.is-indetermine  { color: #0b141a; background: var(--amber); }
.environnement-bande.is-incoherent   { color: #fff8ed; background: var(--copper-dark); border-bottom: 2px solid var(--red); }
.environnement-bande.is-production   { display: none; }

/* Le rappel de l'écran de paiement, et celui de l'écran de connexion. */
.pay-environnement,
.login-environnement {
  margin: 6px 0 0;
  font-size: clamp(10px, .68vw, 13px);
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.pay-environnement.is-entrainement, .login-environnement.is-entrainement { color: var(--copper); }
.pay-environnement.is-production,   .login-environnement.is-production   { color: var(--green); }
.pay-environnement.is-indetermine,  .login-environnement.is-indetermine  { color: var(--amber); }
.pay-environnement.is-incoherent,   .login-environnement.is-incoherent   { color: var(--red); }

.quick-actions {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: clamp(6px, .55vw, 10px);
  align-items: center;
  width: 100%;
  min-width: 0;
}

.free-slot,
.reservation-admin,
.top-new-client {
  width: 100%;
  height: clamp(46px, 5.6vh, 56px);
  min-width: 0;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 16px;
  color: #fff;
  box-shadow: 0 9px 22px rgba(0, 0, 0, .28);
  cursor: pointer;
}
.free-slot { display: flex; align-items: center; justify-content: center; gap: clamp(7px, .7vw, 12px); padding: 5px 8px; background: #173245; text-align: left; }
.free-slot:hover { background: #1d3d50; }
.free-slot small,
.free-slot strong { display: block; }
.free-slot small { color: #efbd91; font-size: clamp(7px, .52vw, 10px); font-weight: 900; letter-spacing: .08em; text-transform: uppercase; }
/* C3 — `nowrap` sur l'HEURE seulement. Le bouton fait 44 px de haut et 69 de
   large : sans cette garde, un libellé un peu long y passe sur trois lignes et
   déborde — c'est ce qui est arrivé avec « dim. 2 14:20 » à la revue visuelle.
   La légende, elle, GARDE son retour à la ligne : « Prochain libre » a besoin
   de ses deux lignes pour tenir dans 43 px. Un jour (« dim. 2 ») tient sur une. */
.free-slot strong { margin-top: 2px; font-size: clamp(16px, 1.05vw, 20px); white-space: nowrap; }
.clock { position: relative; flex: 0 0 auto; width: clamp(26px, 2vw, 34px); aspect-ratio: 1; border: 2px solid #efc5a9; border-radius: 50%; }
.clock::before,
.clock::after { position: absolute; left: 48%; top: 16%; width: 2px; height: 31%; border-radius: 2px; background: #efc5a9; content: ""; transform-origin: 1px 100%; }
.clock::after { transform: rotate(125deg); }

.reservation-admin {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(6px, .55vw, 10px);
  width: 100%;
  padding: 5px 7px;
  background: #173245;
  text-align: left;
}
.reservation-admin:hover { background: #1d3d50; }
.reservation-copy small,
.reservation-copy strong { display: block; }
.reservation-copy small { color: #efbd91; font-size: clamp(7px, .52vw, 10px); font-weight: 900; letter-spacing: .08em; text-transform: uppercase; }
.reservation-copy strong { margin-top: 2px; color: #fff; font-size: clamp(15px, 1vw, 19px); }
.calendar-access-icon { position: relative; display: block; flex: 0 0 auto; width: 28px; height: 26px; border: 2px solid #efc5a9; border-radius: 5px; }
.calendar-access-icon::before { position: absolute; left: -2px; right: -2px; top: 6px; border-top: 2px solid #efc5a9; content: ""; }
.calendar-access-icon::after { position: absolute; left: 5px; top: -5px; width: 2px; height: 7px; border-radius: 2px; background: #efc5a9; box-shadow: 12px 0 #efc5a9; content: ""; }
.calendar-access-icon i { position: absolute; left: 6px; top: 12px; width: 4px; height: 4px; border-radius: 1px; background: #efc5a9; box-shadow: 8px 0 #efc5a9, 0 7px #efc5a9, 8px 7px #efc5a9; }

.top-new-client { display: grid; place-items: center; padding: 0; background: linear-gradient(145deg, #d17a45, #ad512c); }
.top-new-client:hover { background: linear-gradient(145deg, #dc8751, #b95d34); }
.new-person-icon { position: relative; display: block; width: 38px; height: 34px; }
.new-person-icon::before { position: absolute; left: 5px; top: 0; width: 13px; height: 13px; border: 2px solid currentColor; border-radius: 50%; content: ""; }
.new-person-icon::after { position: absolute; left: 0; bottom: 0; width: 24px; height: 14px; border: 2px solid currentColor; border-radius: 13px 13px 5px 5px; content: ""; }
.new-person-icon i::before,
.new-person-icon i::after { position: absolute; right: 0; top: 12px; width: 13px; height: 2px; border-radius: 2px; background: currentColor; content: ""; }
.new-person-icon i::after { transform: rotate(90deg); }

.utilities { position: relative; display: flex; gap: 6px; align-items: center; }
.utilities button { display: grid; place-items: center; width: clamp(38px, 2.65vw, 48px); aspect-ratio: 1; padding: 0; border: 1px solid var(--line); border-radius: 14px; color: #eadfd0; background: #142731; cursor: pointer; }
.utilities button:hover { background: #1d3541; }
.gear { font-size: clamp(17px, 1.15vw, 21px); }
/* ---------------------------------------------------------------------------
   C6 — la recherche client, à la place du bouton « nouveau client » supprimé.
   Elle occupe la même cellule de la rangée d'actions : rien n'a bougé autour.
   --------------------------------------------------------------------------- */
.client-search { position: relative; min-width: 0; }
.client-search input {
  width: 100%;
  height: clamp(46px, 5.6vh, 56px);
  padding: 0 12px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 16px;
  color: #f2e7d7;
  background: #173245;
  font-size: clamp(13px, .85vw, 15px);
}
.client-search input::placeholder { color: #8f9ca3; }
.client-search input:focus-visible { outline: 2px solid #efc5a9; outline-offset: 1px; }
.client-search-results {
  position: absolute;
  z-index: 30;
  top: calc(100% + 9px);
  right: 0;
  width: max-content;
  min-width: 100%;
  max-width: min(340px, 82vw);
  max-height: min(52vh, 380px);
  padding: 6px;
  overflow-y: auto;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 14px;
  background: rgba(13, 27, 35, .99);
  box-shadow: 0 18px 38px rgba(0, 0, 0, .42);
  scrollbar-color: rgba(215, 179, 107, .35) transparent;
  scrollbar-width: thin;
}
.client-search-results button {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 10px;
  color: #efe9e1;
  background: transparent;
  text-align: left;
  cursor: pointer;
}
.client-search-results button:hover,
.client-search-results button:focus-visible { background: rgba(215, 179, 107, .16); outline: none; }
.client-search-results strong { display: block; font-size: 15px; font-weight: 800; }
.client-search-results small { display: block; margin-top: 2px; color: #b3bdc2; font-size: 12px; }
.client-search-message { margin: 0; padding: 8px 10px; color: #b3bdc2; font-size: 12px; }
.client-search-message.is-error { color: #f0a58c; }

/* C8 — la fiche client. Même ancrage et même largeur que les résultats : elle
   les remplace dans le panneau, elle ne s'ouvre pas à côté. */
.client-file {
  position: absolute;
  z-index: 30;
  top: calc(100% + 9px);
  right: 0;
  width: max-content;
  min-width: 100%;
  max-width: min(360px, 86vw);
  max-height: min(64vh, 460px);
  padding: 12px;
  overflow-y: auto;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 14px;
  background: rgba(13, 27, 35, .99);
  box-shadow: 0 18px 38px rgba(0, 0, 0, .42);
  scrollbar-color: rgba(215, 179, 107, .35) transparent;
  scrollbar-width: thin;
}
.client-file h3 { margin: 0; color: #fff5e8; font-size: 18px; font-weight: 800; }
.client-file .cf-contact { margin: 3px 0 0; color: #b3bdc2; font-size: 13px; }
/* La barre d'actions n'est plus réservée à l'aperçu de la recherche : la fiche
   complète la porte aussi depuis C10. Elle est donc décrite une fois, sans
   préfixe, et chaque vue n'ajuste que ses marges. */
.cf-actions { display: flex; gap: 6px; margin: 10px 0; }
.cf-actions button { flex: 1; min-height: 38px; border: 1px solid rgba(215, 179, 107, .22); border-radius: 10px; font-size: 13px; font-weight: 800; cursor: pointer; }
/* C10, 02/08/2026 — une CLASSE et non un identifiant : « Prendre rendez-vous »
   apparaît maintenant dans les trois vues de la fiche, et trois fois le même
   `id` dans une page est une faute qui ne se voit pas.
   Sa géométrie est portée ici, et non par `.cf-actions button`, parce que dans
   la colonne du Hub il n'y a pas de barre : il y est seul sous les cases. */
.cf-book {
  min-height: 38px;
  border: 1px solid rgba(215, 179, 107, .35);
  border-radius: 10px;
  color: #16303f;
  background: #e8c48a;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}
#client-file-back  { color: #d4dadd; background: rgba(255, 255, 255, .07); }
.client-file .cf-stats { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.client-file .cf-stat { flex: 1 1 62px; padding: 6px 8px; border-radius: 9px; background: rgba(215, 179, 107, .1); text-align: center; }
.client-file .cf-stat b { display: block; color: #fff5e8; font-size: 17px; font-weight: 900; }
.client-file .cf-stat span { display: block; margin-top: 1px; color: #b3bdc2; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; }
/* Le compteur de produits porte sa propre explication : « 0 » sans un mot
   laisserait croire que le client n'a rien acheté, alors qu'on ne l'a jamais
   enregistré. Voir l'encadré de `handleClientHistory`. */
.client-file .cf-stat.is-pending b { color: #8f9ca3; }
.client-file .cf-note { margin: 0 0 10px; color: #8f9ca3; font-size: 11px; font-style: italic; }
/* Les CASES — demande de David, 02/08/2026 : « tu me montres des cases avec les
   3 derniers rdv, les trois prochains, les 3 derniers produits, les dates ».
   Chacune porte son titre, ses trois lignes, et ce qui reste au-delà. */
.cf-box {
  margin-top: 9px;
  padding: 8px 9px;
  border: 1px solid rgba(215, 179, 107, .18);
  border-radius: 11px;
  background: rgba(255, 255, 255, .03);
}
.cf-box h4 { margin: 0 0 6px; color: #efbd91; font-size: 10px; font-weight: 900; letter-spacing: .08em; text-transform: uppercase; }
.cf-more { margin: 6px 0 0; color: #8f9ca3; font-size: 11px; }
.client-file ul, .cf-box ul { margin: 0; padding: 0; list-style: none; }
.client-file li, .cf-box li { padding: 5px 7px; border-radius: 8px; color: #efe9e1; font-size: 13px; }
.client-file li + li, .cf-box li + li { margin-top: 3px; }
.client-file li.cf-next, .cf-box li.cf-next { background: rgba(215, 179, 107, .14); }
.client-file li small, .cf-box li small { display: block; margin-top: 2px; color: #b3bdc2; font-size: 11px; }
.client-file li.cf-off, .cf-box li.cf-off { opacity: .62; }
.client-file .cf-empty, .cf-box .cf-empty { margin: 0; color: #8f9ca3; font-size: 12px; font-style: italic; }
.cf-open {
  width: 100%;
  min-height: 40px;
  margin-top: 11px;
  border: 1px solid rgba(215, 179, 107, .35);
  border-radius: 10px;
  color: #16303f;
  background: #e8c48a;
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

/* La fiche complète, dans l'overlay : deux colonnes dès qu'il y a la place. */
#client-overlay-body .cf-full { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 700px) {
  #client-overlay-body .cf-full { grid-template-columns: 1fr 1fr; }
  #client-overlay-body .cf-full > .cf-wide { grid-column: 1 / -1; }
}
#client-overlay-body .cf-stats { margin: 0; }
/* C10 — « Prendre rendez-vous » depuis la fiche complète. Seul bouton de la
   barre, on l'empêche de s'étirer sur toute la largeur de l'overlay. */
#client-overlay-body .cf-actions { margin: 6px 0 10px; }
#client-overlay-body .cf-actions .cf-book { flex: 0 0 auto; min-width: 190px; padding: 0 16px; }
#client-overlay-body .cf-box { margin-top: 0; }
#client-overlay-body h3 { margin: 0 0 2px; color: #fff5e8; font-size: 20px; }
#client-overlay-body .cf-contact { margin: 0 0 4px; color: #b3bdc2; font-size: 13px; }

/* C9 — agir sur le rendez-vous. Deux boutons, jamais trois : la colonne fait
   206 px au plus étroit, et trois boutons n'y tiennent pas sur une ligne —
   défaut déjà payé le 30/07. */
.booking-actions { display: flex; gap: 6px; margin-top: 6px; }
.booking-actions button {
  flex: 1;
  min-height: 36px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 10px;
  color: #d4dadd;
  background: rgba(255, 255, 255, .06);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}
.booking-actions button:hover:not([disabled]) { background: rgba(255, 255, 255, .12); }
.booking-actions button[disabled] { opacity: .45; cursor: default; }
#booking-cancel:not([disabled]) { color: #f0a58c; border-color: rgba(240, 165, 140, .35); }
.booking-actions button.is-armed { color: #16303f; background: #f0a58c; border-color: #f0a58c; }

/* Le bandeau « fiche déjà connue » du formulaire de prise de rendez-vous — C7.
   Il ne bloque rien : il informe, et il propose de reprendre la fiche. */
.free-slot-known {
  margin: 0 0 8px;
  padding: 7px 9px;
  border: 1px solid rgba(215, 179, 107, .3);
  border-radius: 10px;
  background: rgba(215, 179, 107, .12);
  color: #fff5e8;
  font-size: 12px;
}
.free-slot-known[hidden] { display: none; }
.free-slot-known b { display: block; font-size: 14px; }
.free-slot-known button {
  margin-top: 6px;
  padding: 5px 9px;
  border: 1px solid rgba(215, 179, 107, .4);
  border-radius: 8px;
  color: #16303f;
  background: #e8c48a;
  font-size: 12px;
  font-weight: 800;
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
   C3 — le panneau du « Prochain libre »

   Même motif que le menu des options : un bouton, et un panneau ancré dessous.
   Il est ancré à GAUCHE (`left: 0`) parce que son bouton est le premier de la
   rangée — ancré à droite, il déborderait de l'écran sur une tablette.

   ⚠️  `width: max-content` avec `max-width` : le panneau doit pouvoir porter un
       nom de prestation long sans étirer la colonne d'actions qui le contient.
   --------------------------------------------------------------------------- */
.free-slot-control { position: relative; }
.free-slot-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 9px);
  left: 0;
  width: max-content;
  min-width: 208px;
  max-width: min(304px, 78vw);
  padding: 10px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 14px;
  background: rgba(13, 27, 35, .99);
  box-shadow: 0 18px 38px rgba(0, 0, 0, .42);
}
.free-slot-service-label {
  display: block;
  margin: 0 0 5px;
  color: #efbd91;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.free-slot-menu select {
  width: 100%;
  min-height: 38px;
  padding: 0 8px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 10px;
  color: #f2e7d7;
  background: #16303f;
  font-size: 14px;
}
/* C3-b — la journée entière, en puces.
   Une prestation de 10 min produit plus de cent créneaux : en liste verticale
   le panneau serait interminable. En puces, une journée tient en quelques
   lignes et David balaie du regard. La hauteur est bornée et c'est la LISTE
   qui défile, jamais le panneau entier — la prestation reste sous la main. */
.free-slot-list { max-height: min(46vh, 340px); margin: 9px 0 0; overflow-y: auto; scrollbar-color: rgba(215, 179, 107, .35) transparent; scrollbar-width: thin; }
.free-slot-day { margin: 0 0 4px; color: #efbd91; font-size: 10px; font-weight: 900; letter-spacing: .06em; text-transform: uppercase; }
.free-slot-day + .free-slot-times { margin-bottom: 10px; }
.free-slot-times { display: flex; flex-wrap: wrap; gap: 5px; }
.free-slot-times button {
  min-width: 56px;
  padding: 7px 9px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 9px;
  color: #fff5e8;
  background: rgba(215, 179, 107, .1);
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
}
.free-slot-times button:hover { background: rgba(215, 179, 107, .26); }
.free-slot-times button:focus-visible { outline: 2px solid #efc5a9; outline-offset: 1px; }
/* Le premier créneau est celui qu'on annonce spontanément : il se distingue
   sans qu'on ait à comparer des dizaines de puces identiques. */
.free-slot-times button.is-first { background: rgba(215, 179, 107, .3); border-color: rgba(215, 179, 107, .5); }

/* Le formulaire — trois champs, et le nom comme le téléphone sont obligatoires
   (charte §5bis R1). Ils portent `required` : ce n'est pas décoratif. */
.free-slot-form { display: grid; gap: 3px; }
.free-slot-chosen { margin: 0 0 8px; color: #fff5e8; font-size: 15px; font-weight: 800; }
.free-slot-form label { color: #efbd91; font-size: 10px; font-weight: 900; letter-spacing: .06em; text-transform: uppercase; }
.free-slot-form input {
  min-height: 38px;
  margin-bottom: 6px;
  padding: 0 9px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 10px;
  color: #f2e7d7;
  background: #16303f;
  font-size: 15px;
}
.free-slot-form input:focus-visible { outline: 2px solid #efc5a9; outline-offset: 1px; }
.free-slot-form input.is-error { border-color: #f0a58c; }
.free-slot-form-actions { display: flex; gap: 6px; margin-top: 4px; }
.free-slot-form-actions button { flex: 1; min-height: 40px; border: 1px solid rgba(215, 179, 107, .22); border-radius: 10px; font-size: 14px; font-weight: 800; cursor: pointer; }
#free-slot-back   { color: #d4dadd; background: rgba(255, 255, 255, .07); }
#free-slot-submit { color: #16303f; background: #e8c48a; }
#free-slot-submit[disabled] { opacity: .55; cursor: default; }
.free-slot-form-status { margin: 7px 0 0; color: #b3bdc2; font-size: 12px; }
.free-slot-form-status.is-error { color: #f0a58c; }
.free-slot-form-status:empty { display: none; }

.free-slot-status { margin: 8px 0 0; color: #b3bdc2; font-size: 12px; }
.free-slot-status.is-error { color: #f0a58c; }
.free-slot-status:empty { display: none; }

.options-control { position: relative; }
.options-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 9px);
  right: 0;
  width: 196px;
  padding: 7px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 14px;
  background: rgba(13, 27, 35, .99);
  box-shadow: 0 18px 38px rgba(0, 0, 0, .42);
}
.utilities .options-menu button {
  display: flex;
  width: 100%;
  min-height: 42px;
  aspect-ratio: auto;
  justify-content: flex-start;
  gap: 10px;
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  color: #f1e5d6;
  background: transparent;
  font-size: 12px;
  font-weight: 750;
  white-space: nowrap;
}
.utilities .options-menu button:hover,
.utilities .options-menu button:focus-visible { background: rgba(215, 179, 107, .12); }
.logout-icon { color: #d7b36b; font-size: 17px; }
.tiles { display: grid; grid-template-columns: repeat(2, 7px); gap: 3px; }
.tiles i { width: 7px; height: 7px; border-radius: 2px; background: currentColor; }

.workspace {
  align-items: stretch;
  min-height: 0;
  padding-top: var(--gutter);
  padding-bottom: var(--gutter);
}

.client-card,
.calendar-card,
.agenda-card { border: 1px solid var(--line); box-shadow: var(--shadow), inset 0 1px rgba(255, 255, 255, .025); }

/*
 * DEUX RANGÉES : le corps, puis l'encaissement.
 *
 * David, 30/07 : « je ne veux pas de barre de défilement, ça veut dire encore
 * un clic pour aller en bas, ça me prend beaucoup trop de temps. Je veux tout
 * en même temps. »
 *
 * Donc AUCUN `overflow` nulle part : tout est dimensionné pour tenir. Les
 * zones élastiques (les deux champs de texte) absorbent la hauteur restante
 * au lieu de la réclamer.
 */
.client-card {
  container-type: inline-size;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: clamp(8px, .6vw, 12px);
  width: 100%;
  height: 100%;
  min-height: 0;
  padding: clamp(12px, 1vw, 18px);
  border-radius: var(--radius);
  background: radial-gradient(circle at 10% 0%, rgba(55, 88, 104, .23), transparent 34%), linear-gradient(145deg, #172a36, #101e28 72%);
}

.client-head { display: grid; flex: none; grid-template-columns: auto minmax(0, 1fr); gap: clamp(9px, .75vw, 13px); align-items: center; min-width: 0; }
.client-head-copy { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.current-line { display: flex; align-items: center; gap: 9px; color: #b4c0c6; font-size: 10px; font-weight: 850; letter-spacing: .11em; text-transform: uppercase; }
.current-line time { margin-left: 3px; padding: 5px 9px; border-radius: 999px; color: #f2e7d7; background: rgba(215, 179, 107, .13); box-shadow: inset 0 0 0 1px rgba(215, 179, 107, .16); font-size: 12px; letter-spacing: 0; }
.current-line .close-client {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-left: auto;
  padding: 0;
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 10px;
  color: #eadfd0;
  background: rgba(20, 39, 49, .88);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
.current-line .close-client:hover { background: #1d3541; }
.live-dot { width: 8px; height: 8px; border-radius: 50%; background: #647178; }
.live-dot.is-in-progress { background: var(--status-in-progress); animation: hub-breathe 1.8s ease-in-out infinite; }
.live-dot.is-completed { background: var(--status-completed); }
.live-dot.is-no-show { background: var(--status-no-show); }
.live-dot.is-unknown { background: var(--amber); }

.identity { min-width: 0; margin: 0; }
/* Titre nettement réduit : il occupait jusqu'à 64 px et écrasait tout le reste
   de la fiche. `overflow-wrap` évite qu'un nom composé déborde de la carte. */
.identity h1 { margin: 0; overflow-wrap: anywhere; color: #fff8ee; font: 500 clamp(24px, 2.05vw, 34px)/1.05 Georgia, serif; letter-spacing: -.02em; text-shadow: 0 2px 20px rgba(0, 0, 0, .16); }
.identity p { margin: 5px 0 0; overflow-wrap: anywhere; color: #c4cdd1; font-size: clamp(13px, .92vw, 16px); }

/*
 * DEUX COLONNES, demande de David : « le nom du client avec ce qu'il fait,
 * et puis les notes qu'on a préparées ensemble ».
 *
 * `min-height: 0` partout dans la chaîne : sans lui, un enfant de grille ou de
 * flex refuse de devenir plus petit que son contenu, et les champs de texte
 * feraient déborder la carte au lieu de se comprimer.
 */
.client-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
  gap: clamp(9px, .7vw, 14px);
  min-height: 0;
}

.client-col { display: flex; flex-direction: column; gap: clamp(7px, .55vw, 11px); min-height: 0; }

/* La carte de fidélité prend ce qui reste, sans jamais pousser. */
/* La colonne est une pile flex : la fiche client est le SEUL élément élastique,
   donc c'est elle qui absorbe la hauteur libérée par la carte de fidélité —
   et c'est elle qui défile, jamais la colonne entière. */
.client-col-who .client-file-inline { flex: 1 1 auto; min-height: 0; }

.fact-row { display: grid; flex: none; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(7px, .55vw, 10px); }
.fact,
.note-box { border: 1px solid rgba(215, 179, 107, .14); border-radius: 16px; background: rgba(31, 51, 63, .94); box-shadow: inset 0 1px rgba(255, 255, 255, .025); }
.fact { padding: clamp(10px, .75vw, 14px); }
.fact span,
.note-box span,
.kicker { display: block; color: #9eabb1; font-size: clamp(8px, .5vw, 10px); font-weight: 850; letter-spacing: .1em; text-transform: uppercase; }
.fact strong { display: block; margin-top: 6px; color: #f5eee5; font-size: clamp(13px, .8vw, 15px); }
/* `flex: 1 1 0` + `min-height: 0` : le bloc prend la place disponible et la
   rend quand il n'y en a plus, au lieu d'imposer sa hauteur. */
.note-box { display: flex; flex: 1 1 0; flex-direction: column; min-height: 0; padding: clamp(10px, .7vw, 14px); background: linear-gradient(145deg, rgba(34, 57, 70, .98), rgba(26, 45, 57, .98)); }
.note-box p { margin: 8px 0 0; color: #d4dde0; font-size: clamp(12px, .72vw, 14px); line-height: 1.5; }
.note-box textarea { flex: 1 1 0; width: 100%; min-height: 62px; margin-top: 7px; padding: 8px 10px; resize: none; border: 1px solid rgba(215, 179, 107, .16); border-radius: 12px; outline: none; color: #e8eff1; background: rgba(9, 22, 29, .38); font: inherit; line-height: 1.5; }
.note-box textarea:focus { border-color: rgba(215, 179, 107, .55); box-shadow: 0 0 0 3px rgba(215, 179, 107, .08); }
.note-box textarea:disabled { color: #8e9aa0; cursor: default; opacity: .78; }
.save-client-note { align-self: flex-end; flex: none; margin-top: 7px; padding: 6px 11px; border: 1px solid rgba(215, 179, 107, .25); border-radius: 10px; color: #f7eee3; background: #274251; font-weight: 800; cursor: pointer; }
.save-client-note:hover:not(:disabled) { background: #315365; }
.save-client-note:disabled { cursor: default; opacity: .42; }

/* Fidélité — une ligne, plus une carte. Elle occupait 277 px de haut pour une
   image sans donnée ; ces pixels vont à la fiche client. */
.loyalty-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 6px 0 0;
  padding: 6px 9px;
  border: 1px solid rgba(215, 179, 107, .18);
  border-radius: 10px;
  background: rgba(255, 255, 255, .03);
  color: #b3bdc2;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.loyalty-line b { color: #efbd91; font-size: 14px; letter-spacing: 0; }

/* La fiche client dans la colonne : c'est ELLE qui prend la hauteur libérée,
   et c'est elle seule qui défile si le client a beaucoup d'historique. */
.client-file-inline { min-height: 0; margin-top: 8px; overflow-y: auto; scrollbar-color: rgba(215, 179, 107, .35) transparent; scrollbar-width: thin; }
.client-file-inline .cf-box { margin-top: 7px; }
.client-file-inline .cf-box:first-child { margin-top: 0; }
.client-file-inline .cf-open { margin-top: 8px; min-height: 34px; font-size: 12px; }
/* C10 — le rendez-vous suivant se prend depuis la colonne, sans quitter la
   journée. Même gabarit que « Voir la fiche complète », juste au-dessus : la
   colonne fait 206 px au plus étroit, deux boutons côte à côte n'y tiennent
   pas — défaut déjà payé le 30/07. */
.client-file-inline .cf-book { display: block; width: 100%; margin-top: 8px; min-height: 34px; font-size: 12px; }
/*
 * BARRE D'ENCAISSEMENT — dernière rangée de la fiche, donc toujours visible.
 * Un séparateur la détache du contenu qui défile derrière elle.
 */
.checkout-bar { display: flex; gap: 10px; padding-top: clamp(8px, .6vw, 12px); border-top: 1px solid rgba(215, 179, 107, .16); }

.checkout {
  display: flex;
  flex: 1;
  gap: 14px;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: clamp(52px, 4.4vh, 64px);
  padding: 0 16px;
  border: 0;
  border-radius: 14px;
  color: #fff;
  background: linear-gradient(145deg, #cf7945, #aa532d);
  box-shadow: 0 12px 27px rgba(0, 0, 0, .26);
  cursor: pointer;
}

.checkout-label { font-size: clamp(15px, 1.05vw, 18px); font-weight: 900; letter-spacing: .02em; }
.checkout:disabled { cursor: default; opacity: .45; box-shadow: none; }
.checkout:hover { background: linear-gradient(145deg, #dc8650, #b85f34); }

/* CA-3g — REPRISE APRÈS COUPURE, avant même d'ouvrir la caisse. Même logique
   visuelle que `.pay-retry` : bordure ambre, un état d'attente à saisir tout
   de suite, pas un refus. Ne coexiste jamais avec `.checkout` actif : soit on
   encaisse, soit on réessaie. */
.checkout-retry {
  flex: 1;
  min-height: clamp(52px, 4.4vh, 64px);
  border: 2px solid var(--amber);
  border-radius: 14px;
  background: transparent;
  color: var(--amber);
  font-size: clamp(15px, 1.05vw, 18px);
  font-weight: 900;
  letter-spacing: .02em;
  cursor: pointer;
}
.checkout-retry:disabled { cursor: default; opacity: .45; }
.register-icon { position: relative; display: block; flex: none; width: 26px; height: 21px; border: 2px solid currentColor; border-radius: 4px; }
.register-icon::before { position: absolute; left: 4px; top: -9px; width: 18px; height: 8px; border: 2px solid currentColor; border-bottom: 0; border-radius: 4px 4px 0 0; content: ""; }
.register-icon::after { position: absolute; left: 5px; right: 5px; bottom: 4px; height: 3px; border-top: 2px solid currentColor; border-bottom: 2px solid currentColor; content: ""; }
.register-icon i { position: absolute; right: 4px; top: 4px; width: 4px; height: 4px; border-radius: 50%; background: currentColor; }

/* Vignette, et non plus panneau : la photo prenait toute la hauteur de la
   fiche pour une information secondaire. */
.photo-panel { position: relative; flex: none; width: clamp(76px, 6.4vw, 104px); aspect-ratio: 1; overflow: hidden; border-radius: 18px; background: #73543d; box-shadow: inset 0 0 0 1px rgba(234, 197, 145, .1); }
.photo-panel::after { position: absolute; inset: 0; border: 1px solid rgba(241, 218, 184, .1); border-radius: inherit; background: linear-gradient(180deg, rgba(15, 24, 30, .04), rgba(9, 15, 20, .24)); content: ""; pointer-events: none; }
.photo-panel img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center 28%; mix-blend-mode: multiply; opacity: .78; filter: saturate(.82) contrast(1.05) brightness(.9); }
/* L'état de la photo n'est plus affiché en pastille : il est lu par les
   lecteurs d'écran et par hub.js, mais n'encombre plus la vignette. */
.photo-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.change-client-photo { position: absolute; z-index: 2; right: 5px; bottom: 5px; padding: 4px 7px; border: 1px solid rgba(241, 218, 184, .28); border-radius: 8px; color: #fff4e7; background: rgba(10, 19, 25, .84); font-size: 9px; font-weight: 850; cursor: pointer; }
.change-client-photo:hover:not(:disabled) { background: rgba(25, 47, 59, .94); }
.change-client-photo:disabled { cursor: default; opacity: .42; }

.planning-column { display: grid; align-self: stretch; grid-template-rows: minmax(330px, 48%) minmax(0, 1fr); gap: var(--gap); width: 100%; height: auto; min-height: 0; }
.calendar-card,
.agenda-card { min-height: 0; border-radius: var(--radius); background: linear-gradient(150deg, #172a35, #101e27); }

.calendar-card { container-type: inline-size; display: grid; grid-template-rows: auto minmax(0, 1fr); padding: clamp(12px, .9vw, 18px); }
.calendar-head { display: flex; align-items: flex-start; justify-content: space-between; }
.calendar-head h2 { margin: 0; color: #fff5e8; font: 500 clamp(28px, 2vw, 38px)/1 Georgia, serif; letter-spacing: -.02em; }
.calendar-titles { min-width: 0; }
.calendar-titles h2 { margin-top: 0; }
.calendar-titles p { margin: 7px 0 0; color: var(--gold); font-size: clamp(17px, 1vw, 21px); font-weight: 800; line-height: 1; }
.month-buttons { display: flex; gap: 6px; }
.month-buttons button { width: clamp(42px, 2.7vw, 50px); aspect-ratio: 1; padding: 0; border: 1px solid var(--line); border-radius: 12px; color: #f2e7d7; background: #203743; font-size: 30px; cursor: pointer; }
.month-buttons button:hover { background: #294552; }
.calendar-grid { display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; margin-top: clamp(7px, .7vh, 12px); }
.weekdays,
.dates { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.weekdays span { display: flex; align-items: center; justify-content: center; gap: 4px; padding-bottom: 5px; color: #8f9ca3; text-align: center; font-size: clamp(11px, .68vw, 14px); font-weight: 900; }
.weekdays b { color: #c9d0d3; font-size: clamp(13px, .78vw, 16px); }
.weekdays small { color: #8b989e; font-size: clamp(10px, .62vw, 13px); }
.weekdays .shabbat b { color: var(--gold); }
.dates { grid-template-rows: repeat(6, minmax(0, 1fr)); min-height: 0; }
.dates button { display: flex; align-items: center; justify-content: center; flex-direction: column; justify-self: center; align-self: center; width: clamp(39px, 2.45vw, 48px); aspect-ratio: 1; padding: 2px 0 0; border: 0; border-radius: 12px; color: #e5e0d9; background: transparent; cursor: pointer; }
.dates .civil-day { font-size: clamp(14px, .9vw, 18px); font-weight: 900; line-height: 1; }
.dates .hebrew-day { margin-top: 3px; color: var(--gold); font-size: clamp(10px, .62vw, 13px); font-weight: 850; line-height: 1; }
.dates button:hover { background: #29404d; }
.dates .outside { color: #59666d; }
.dates .outside .hebrew-day { color: #59666d; }
.dates .shabbat:not(.selected) .civil-day { color: #e4c789; }
.dates .today:not(.selected) { box-shadow: inset 0 0 0 1px rgba(215, 179, 107, .55); }
.dates .selected { color: #fff; background: var(--copper); box-shadow: 0 7px 18px rgba(0, 0, 0, .28); }
.dates .selected .hebrew-day { color: #fff4dd; }

.agenda-card { container-type: inline-size; display: grid; grid-template-rows: minmax(0, 1fr); padding: 6px clamp(9px, .65vw, 13px); }
.appointments { display: flex; flex-direction: column; min-height: 0; padding-top: 4px; overflow-x: hidden; overflow-y: auto; scrollbar-color: rgba(215, 179, 107, .35) transparent; scrollbar-width: thin; }
.appointment { display: grid; flex: 0 0 clamp(58px, 7.2vh, 66px); grid-template-columns: 58px 9px minmax(0, 1fr) 86px; grid-template-rows: 1fr 1fr; gap: 7px; align-items: center; min-height: 0; padding: 4px 7px; border: 0; border-bottom: 1px solid rgba(215, 179, 107, .1); border-radius: 12px; color: #efe9e1; background: transparent; text-align: left; cursor: pointer; }
.appointment:last-child { border-bottom-color: transparent; }
.appointment:hover { background: rgba(45, 68, 80, .65); }
.appointment.is-selected { border-bottom-color: transparent; box-shadow: inset 0 0 0 1px rgba(234, 223, 208, .16); }
.appointment time { grid-row: 1 / 3; font-size: clamp(15px, .95vw, 19px); font-weight: 900; }
.appointment .dot { grid-row: 1 / 3; width: 8px; height: 8px; border-radius: 50%; background: #647178; }
.who { grid-row: 1 / 3; min-width: 0; }
.who strong,
.who small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.who strong { font-size: clamp(14px, .9vw, 18px); }
.who small { margin-top: 4px; color: #b3bdc2; font-size: clamp(10px, .64vw, 13px); }
.appointment .meta { align-self: end; justify-self: end; max-width: 86px; overflow: hidden; color: #b3bdc2; font-size: clamp(10px, .62vw, 12px); text-overflow: ellipsis; white-space: nowrap; }
.appointment > b { align-self: start; justify-self: end; padding: 5px 7px; border-radius: 999px; color: #d4dadd; background: rgba(255, 255, 255, .08); font-size: clamp(9px, .56vw, 11px); white-space: nowrap; }
.appointment.is-in-progress { background: rgba(50, 101, 83, .32); box-shadow: inset 3px 0 var(--status-in-progress); }
.appointment.is-in-progress .dot { background: var(--status-in-progress); animation: hub-breathe 1.8s ease-in-out infinite; }
.appointment.is-in-progress > b { color: #9ce2c2; background: rgba(67, 154, 116, .22); }
.appointment.is-waiting .dot { background: var(--status-waiting); }
.appointment.is-waiting > b { color: #efb383; background: rgba(201, 109, 56, .2); }
.appointment.is-completed .dot { background: var(--status-completed); }
.appointment.is-completed > b { color: #b8daf6; background: rgba(71, 120, 167, .25); }
.appointment.is-no-show .dot { background: var(--status-no-show); }
.appointment.is-no-show > b { color: #f0a09b; background: rgba(181, 71, 65, .2); }
.appointment.is-unknown .dot { background: var(--amber); }
.appointment.is-unknown > b { color: #f0c47d; background: rgba(192, 127, 38, .2); }

.checkout-overlay {
  position: fixed;
  z-index: 60;
  inset: 0;
  display: grid;
  place-items: center;
  padding: clamp(12px, 2.2vw, 34px);
  background: rgba(4, 10, 14, .78);
  backdrop-filter: blur(12px);
}

.checkout-dialog {
  position: relative;
  display: block;
  width: min(1180px, 100%);
  max-height: min(820px, calc(100vh - 24px));
  overflow: hidden;
  border: 1px solid rgba(215, 179, 107, .28);
  border-radius: 28px;
  color: #eef3f4;
  background:
    radial-gradient(circle at 0 0, rgba(63, 96, 111, .22), transparent 34%),
    linear-gradient(145deg, #172b36, #0d1b24 72%);
  box-shadow: 0 36px 90px rgba(0, 0, 0, .56);
}

.checkout-body {
  display: grid;
  grid-template-columns: minmax(0, 1.65fr) minmax(280px, .75fr);
  max-height: min(820px, calc(100vh - 24px));
  min-height: 0;
}
.service-catalog { min-height: 0; padding: clamp(16px, 1.8vw, 26px); overflow-y: auto; }
.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(145px, 1fr));
  gap: clamp(10px, 1vw, 15px);
}
.service-tile {
  position: relative;
  display: block;
  aspect-ratio: 1.08;
  min-width: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid rgba(215, 179, 107, .17);
  border-radius: 20px;
  color: #edf2f3;
  background: linear-gradient(145deg, rgba(37, 62, 74, .96), rgba(24, 43, 53, .96));
  box-shadow: inset 0 1px rgba(255, 255, 255, .025);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.service-tile:has(.service-tile-main:hover:not(:disabled)) { transform: translateY(-2px); border-color: rgba(215, 179, 107, .42); }
.service-tile.is-selected {
  border-color: rgba(227, 164, 95, .78);
  background: linear-gradient(145deg, rgba(73, 77, 69, .98), rgba(47, 60, 61, .98));
  box-shadow: 0 12px 28px rgba(0, 0, 0, .24), inset 0 0 0 1px rgba(238, 174, 102, .2);
  transform: translateY(-2px);
}
.service-tile.is-booking-service::after {
  position: absolute;
  right: -22px;
  top: 13px;
  width: 86px;
  padding: 3px 0;
  color: #24180f;
  background: #e0a161;
  content: "RDV";
  font-size: 8px;
  font-weight: 950;
  letter-spacing: .08em;
  text-align: center;
  transform: rotate(42deg);
  pointer-events: none;
  z-index: 4;
}
.service-tile-main {
  display: grid;
  width: 100%;
  height: 100%;
  place-items: center;
  padding: 18px;
  border: 0;
  color: inherit;
  background: transparent;
  text-align: center;
  cursor: pointer;
}
.service-tile-main strong {
  max-width: 90%;
  font-size: clamp(14px, 1.15vw, 18px);
  line-height: 1.18;
  transition: transform .16s ease;
}
.service-tile.is-expanded .service-tile-main strong { transform: translateY(-21px); }
.service-clear {
  position: absolute;
  z-index: 5;
  left: 10px;
  top: 10px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid rgba(255, 214, 173, .4);
  border-radius: 9px;
  color: #fff0df;
  background: rgba(23, 34, 38, .78);
  font-size: 18px;
  cursor: pointer;
}
.service-clear:hover { background: #7b4234; }
.service-inline-controls {
  position: absolute;
  z-index: 5;
  left: 50%;
  bottom: 12px;
  display: grid;
  grid-template-columns: 34px 38px 34px;
  gap: 4px;
  align-items: center;
  padding: 4px;
  border: 1px solid rgba(235, 184, 121, .24);
  border-radius: 13px;
  background: rgba(10, 24, 30, .88);
  transform: translateX(-50%);
}
.service-inline-controls button {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 9px;
  color: #fff2e2;
  background: #31505c;
  font-size: 20px;
  cursor: pointer;
}
.service-inline-controls button:hover { background: #426776; }
.service-inline-controls strong { text-align: center; font-size: 14px; }
.service-tile.is-unavailable { opacity: .48; }
.product-tile {
  display: grid;
  place-items: center;
  padding: 18px;
  border-color: rgba(215, 179, 107, .12);
  color: #d6dfe2;
  background: linear-gradient(145deg, rgba(24, 44, 54, .98), rgba(13, 29, 38, .98));
  text-align: center;
  opacity: 1 !important;
}
.product-tile strong { max-width: 90%; font-size: clamp(14px, 1.15vw, 18px); line-height: 1.18; }

.checkout-summary {
  display: flex;
  justify-content: space-between;
  flex-direction: column;
  gap: 18px;
  min-height: 0;
  padding: clamp(18px, 2vw, 28px);
  border-left: 1px solid rgba(215, 179, 107, .15);
  background: rgba(8, 20, 27, .42);
}
.checkout-client {
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(215, 179, 107, .16);
}
.checkout-client span,
.checkout-client strong { display: block; }
.checkout-client span { color: #8fa0a7; font-size: 9px; font-weight: 850; letter-spacing: .1em; text-transform: uppercase; }
.checkout-client strong { margin-top: 6px; color: #fff4e7; font: 500 clamp(21px, 1.75vw, 29px)/1.08 Georgia, serif; }
.checkout-lines { display: flex; flex-direction: column; gap: 8px; margin-top: 13px; }
.checkout-line,
.checkout-lines-empty {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid rgba(215, 179, 107, .12);
  border-radius: 13px;
  color: #e9eff1;
  background: rgba(35, 58, 69, .64);
}
.checkout-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 7px; text-align: left; }
.checkout-line strong { overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.checkout-line span { color: #e7b777; font-size: 11px; font-weight: 850; }
.checkout-lines-empty { color: #8e9da3; font-size: 11px; }
.checkout-total { display: flex; align-items: flex-end; justify-content: space-between; padding-top: 18px; border-top: 1px solid rgba(215, 179, 107, .16); }
.checkout-total span { color: #9fadb3; font-size: 11px; font-weight: 850; letter-spacing: .08em; text-transform: uppercase; }
.checkout-total strong { color: #fff4e3; font: 500 clamp(28px, 2.3vw, 38px)/1 Georgia, serif; }
.checkout-payment { min-height: 54px; border: 0; border-radius: 16px; color: #fff; background: linear-gradient(145deg, #cf7945, #a8512c); font: inherit; font-weight: 900; }

.toast { position: fixed; z-index: 20; left: 50%; bottom: 18px; max-width: 430px; padding: 11px 17px; border-radius: 999px; color: #fff5e9; background: rgba(19, 43, 57, .97); box-shadow: 0 14px 32px rgba(0, 0, 0, .38); font-size: 11px; font-weight: 750; opacity: 0; pointer-events: none; transform: translate(-50%, 10px); transition: .18s ease; }
.toast.visible { opacity: 1; transform: translate(-50%, 0); }

@media (max-height: 760px) {
  .app-shell { grid-template-rows: 66px auto minmax(0, 1fr); }
  .brand-mark { width: 76px; }
  .free-slot,
  .reservation-admin,
  .top-new-client { height: 44px; }
  .reservation-admin { width: 100%; }
  .utilities button { width: 40px; }
  .client-card { gap: 8px; padding: 12px; }
  .identity { margin-bottom: 0; }
  /* Ecran peu haut : on gagne de la place sur le titre et la photo, jamais
     sur l'encaissement ni sur les boutons de suivi. */
  .identity h1 { font-size: clamp(21px, 1.8vw, 27px); }
  .identity p { font-size: clamp(12px, .85vw, 14px); }
  .photo-panel { width: clamp(62px, 5vw, 78px); }
  .fact { padding: 9px 11px; }
  .client-body { gap: 8px; }
  .client-col { gap: 6px; }
  .note-box textarea { min-height: clamp(70px, 9vh, 100px); }
  .planning-column { grid-template-rows: minmax(320px, 48%) minmax(0, 1fr); }
}

@media (max-width: 1350px) {
  .header-main { grid-template-columns: 82px minmax(0, 1fr); }
  .date-stack { gap: 7px; }
  .date-stack strong { font-size: 14px; }
  .date-stack small { padding-left: 7px; font-size: 13px; }
  .day-state time { min-width: 58px; padding: 0 8px; font-size: 22px; }
  .connection-state { width: 24px; height: 24px; }
  .quick-actions { gap: 6px; }
  .free-slot { gap: 6px; padding: 4px 6px; }
  .free-slot small { font-size: 7px; }
  /* Le planning garde sa part d'un quart : c'est la demande de David, et elle
     ne depend pas de la taille de l'ecran. On abaisse seulement son plancher
     pour qu'il ne force jamais un debordement. */
  .workspace { grid-template-columns: minmax(210px, 1fr) minmax(0, 3fr); }
  .appointment { grid-template-columns: 52px 8px minmax(0, 1fr) 78px; gap: 5px; }
  .service-grid { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
}

/*
 * Responsive universel : la composition dépend de l'espace disponible,
 * jamais d'un modèle de téléphone. Les valeurs fluides restent bornées
 * pour préserver la lisibilité sur mobile comme sur très grand écran.
 */
@media (max-width: 1050px), (max-height: 600px) and (max-width: 1400px) {
  :root {
    --gutter: clamp(8px, 2.2vw, 16px);
    --gap: clamp(8px, 2vw, 14px);
    --radius: clamp(16px, 4vw, 24px);
  }

  html,
  body {
    height: auto;
    overflow-y: auto;
  }

  .app-shell {
    grid-template-rows: auto auto auto;
    width: 100%;
    height: auto;
    min-height: 100dvh;
  }

  .topbar,
  .workspace {
    grid-template-columns: minmax(0, 1fr);
  }

  .topbar {
    position: sticky;
    top: 0;
    gap: clamp(6px, 1.4vw, 10px);
    padding-top: 6px;
    padding-bottom: 7px;
  }

  .header-main {
    grid-template-columns: clamp(58px, 10vw, 78px) minmax(0, 1fr);
    min-height: clamp(54px, 9vw, 68px);
  }

  .brand-mark {
    width: clamp(54px, 9vw, 70px);
    border-width: 2px;
    transform: none;
  }

  .day-state {
    grid-template-columns: minmax(0, 1fr) auto 30px;
  }

  .date-stack {
    justify-content: flex-start;
    gap: clamp(6px, 1.6vw, 14px);
  }

  .date-stack strong { font-size: clamp(13px, 2.5vw, 19px); }
  .date-stack small { padding-left: clamp(6px, 1.4vw, 12px); font-size: clamp(12px, 2.3vw, 17px); }
  .day-state time { min-width: 58px; padding: 0 clamp(6px, 1.4vw, 12px); font-size: clamp(20px, 4vw, 27px); }

  .quick-actions {
    grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
    gap: clamp(5px, 1.4vw, 9px);
  }

  .free-slot,
  .reservation-admin,
  .top-new-client {
    height: clamp(44px, 8vw, 54px);
    border-radius: clamp(12px, 2.6vw, 16px);
  }

  .utilities button { width: clamp(38px, 7vw, 46px); }

  .workspace {
    gap: var(--gap);
    padding-top: var(--gap);
    padding-bottom: max(var(--gutter), env(safe-area-inset-bottom));
  }

  .planning-column {
    order: -1;
    grid-template-rows:
      clamp(330px, 78vw, 460px)
      clamp(360px, 58dvh, 620px);
    height: auto;
  }

  .calendar-card { min-height: clamp(330px, 78vw, 460px); }
  .calendar-head h2 { font-size: clamp(26px, 7cqi, 38px); }
  .calendar-titles p { font-size: clamp(15px, 4.2cqi, 21px); }
  .month-buttons button { width: clamp(40px, 10cqi, 50px); font-size: clamp(25px, 7cqi, 30px); }
  .weekdays span { font-size: clamp(10px, 2.8cqi, 14px); }
  .weekdays b { font-size: clamp(12px, 3.3cqi, 16px); }
  .weekdays small { font-size: clamp(9px, 2.6cqi, 13px); }
  .dates button { width: clamp(34px, 10.5cqi, 48px); border-radius: clamp(9px, 2.7cqi, 12px); }
  .dates .civil-day { font-size: clamp(14px, 4cqi, 18px); }
  .dates .hebrew-day { font-size: clamp(9px, 2.8cqi, 13px); }

  .agenda-card { min-height: clamp(360px, 58dvh, 620px); }
  .appointment {
    flex-basis: clamp(60px, 11cqi, 68px);
    grid-template-columns: clamp(46px, 12cqi, 58px) 8px minmax(0, 1fr) clamp(70px, 18cqi, 86px);
  }
  .appointment time { font-size: clamp(15px, 4cqi, 19px); }
  .who strong { font-size: clamp(14px, 3.8cqi, 18px); }
  .who small { font-size: clamp(10px, 2.8cqi, 13px); }
  .appointment .meta { font-size: clamp(10px, 2.6cqi, 12px); }
  .appointment > b { font-size: clamp(9px, 2.4cqi, 11px); }

  /*
   * En colonne unique, c'est la PAGE qui défile. La fiche cesse donc de
   * défiler de son côté — deux ascenseurs imbriqués sont pénibles au doigt —
   * et l'encaissement devient collant : il reste au bas de l'écran pendant
   * qu'on fait défiler la coupe et les notes.
   */
  /*
   * ⚠️  On garde EXACTEMENT la mécanique du bureau : une grille de quatre
   *     rangées dont une seule défile, et une hauteur bornée. Un premier essai
   *     reposait sur `position: sticky` pour la barre d'encaissement ; il a été
   *     abandonné après mesure — le collage ne s'établissait qu'à partir d'une
   *     certaine profondeur de défilement, donc le bouton n'était PAS toujours
   *     visible. Une hauteur bornée donne le même résultat de façon
   *     déterministe : l'encaissement est la dernière rangée d'une carte qui ne
   *     dépasse jamais l'écran, il est donc toujours à l'image.
   *
   *     `dvh` et non `vh` : sur téléphone, la barre d'adresse fait varier la
   *     hauteur visible, et `vh` la surestime.
   */
  /*
   * En colonne unique, la fiche n'a plus assez de largeur pour deux colonnes :
   * elles s'empilent, et c'est la PAGE qui defile — un seul ascenseur, pas
   * deux imbriques. La contrainte « tout a l'ecran » ne vaut que sur le poste
   * du salon, ou David travaille reellement.
   */
  .client-card {
    height: auto;
    min-height: 0;
    max-height: none;
  }

  .client-body { grid-template-columns: minmax(0, 1fr); }
  .note-box { flex: none; }
  .note-box textarea { min-height: clamp(90px, 24cqi, 150px); }
  .haircut-box { flex: none; }
  .haircut-box textarea { min-height: clamp(56px, 15cqi, 90px); }

  .identity h1 { font-size: clamp(26px, 5.4cqi, 38px); }
  .identity p { font-size: clamp(14px, 3cqi, 18px); }
  .photo-panel { width: clamp(72px, 17cqi, 104px); }
}

@media (max-width: 820px) {
  .checkout-body { grid-template-columns: 1fr; overflow-y: auto; }
  .service-catalog { overflow: visible; }
  .checkout-summary { border-top: 1px solid rgba(215, 179, 107, .15); border-left: 0; }
}

@media (max-width: 700px) {
  .client-card { min-height: 0; padding: clamp(10px, 3cqi, 16px); }

  /* Les deux renseignements passent l'un sous l'autre plutôt que d'être
     comprimés côte à côte. */
  .fact-row { grid-template-columns: minmax(0, 1fr); }
  .note-box textarea { min-height: clamp(100px, 26cqi, 160px); }

  /* Les menus de la coupe passent au-dessus de leur libellé : à cette
     largeur, deux colonnes laisseraient des menus de 90 px. */
  .haircut-grid { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .haircut-grid label { margin-top: 4px; }

  .checkout-overlay {
    place-items: start center;
    overflow-y: auto;
  }
  .checkout-panel {
    max-height: none;
    margin-top: max(8px, env(safe-area-inset-top));
    margin-bottom: max(8px, env(safe-area-inset-bottom));
  }
  .checkout-body { max-height: none; }
}

@media (max-width: 470px) {
  .topbar { position: relative; }
  .header-main { grid-template-columns: 52px minmax(0, 1fr); }
  .brand-mark { width: 48px; }
  .day-state { grid-template-columns: minmax(0, 1fr) auto 24px; }
  .date-stack { align-items: flex-start; flex-direction: column; gap: 2px; }
  .date-stack small { padding-left: 0; border-left: 0; }
  .day-state time { min-width: 52px; padding: 0 5px; font-size: clamp(18px, 5.5vw, 23px); }
  .connection-state { width: 22px; height: 22px; }

  .quick-actions { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .utilities { grid-column: 1 / -1; justify-self: end; }
  .free-slot { padding: 4px; }
  .clock { width: 24px; }
  .free-slot strong { font-size: clamp(14px, 4.2vw, 17px); }
  .reservation-copy strong { font-size: clamp(13px, 4vw, 16px); }
  .calendar-access-icon { width: 24px; height: 23px; }
  .new-person-icon { transform: scale(.88); }

  .calendar-card { padding: clamp(9px, 3vw, 13px); }
  .calendar-head { align-items: center; }
  .month-buttons { gap: 4px; }
  .month-buttons button { width: clamp(36px, 11cqi, 44px); }
  .weekdays span { gap: 2px; }

  .appointment {
    grid-template-columns: 46px 7px minmax(0, 1fr) 66px;
    gap: 4px;
    padding-right: 3px;
    padding-left: 3px;
  }
  .appointment > b { padding: 5px 4px; }

  .toast {
    width: calc(100% - 20px);
    max-width: none;
    text-align: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ==========================================================
   Socle technique V1.0 — connexion et états de données
   ========================================================== */

[hidden] { display: none !important; }

button:disabled {
  cursor: not-allowed;
  opacity: 0.48;
}

.login-gate {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(circle at 20% 10%, rgba(205, 145, 74, 0.13), transparent 36%),
    linear-gradient(145deg, #081016, #101e27 58%, #0b151c);
}

.login-card {
  width: min(430px, 100%);
  padding: 30px;
  color: #edf5f7;
  background: rgba(18, 32, 41, 0.96);
  border: 1px solid rgba(218, 167, 93, 0.26);
  border-radius: 24px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.38);
}

.login-card img {
  display: block;
  width: 88px;
  height: 88px;
  margin: 0 auto 18px;
  object-fit: contain;
}

.login-card h1 {
  margin: 6px 0 8px;
  font-size: clamp(1.7rem, 5vw, 2.25rem);
}

.login-card p { color: #aebec5; }

.login-card label {
  display: block;
  margin: 22px 0 8px;
  color: #dce7ea;
  font-weight: 700;
}

.login-card input {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 12px;
  font: inherit;
}

.login-card input:focus {
  outline: 2px solid #d49a58;
  outline-offset: 2px;
}

.login-card button {
  width: 100%;
  min-height: 50px;
  margin-top: 14px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 12px;
  font: inherit;
  font-weight: 900;
}

/* Repli vers le mot de passe partagé : volontairement discret. C'est une
   sortie de secours, pas le chemin normal.
   ⚠️  Le sélecteur DOIT être `.login-card .login-mode-toggle` (spécificité
   0,2,0) et non `.login-mode-toggle` seul (0,1,0) : la règle `.login-card
   button` ci-dessus vaut 0,1,1 et l'emporterait, affichant ce lien comme un
   gros bouton doré. Défaut réellement constaté à la revue visuelle. */
.login-card .login-mode-toggle {
  margin-top: 10px;
  padding: 6px 0;
  min-height: 0;
  color: #8ea3ac;
  background: none;
  border: 0;
  font-size: 0.9rem;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.login-card .login-mode-toggle:hover,
.login-card .login-mode-toggle:focus-visible {
  color: #e8c79a;
}

.login-card .login-mode-toggle:disabled {
  opacity: 0.5;
  cursor: default;
}

.login-status {
  min-height: 1.4em;
  margin: 14px 0 0;
  text-align: center;
}

/* Lien de retour de la page de réinitialisation. Même précaution de
   spécificité que ci-dessus, mais c'est ici un <a> : il échappe à la règle
   `.login-card button`. On l'aligne visuellement sur le lien de repli. */
.login-card .reset-back {
  display: block;
  margin-top: 14px;
  color: #8ea3ac;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: center;
}

.login-card .reset-back:hover,
.login-card .reset-back:focus-visible { color: #e8c79a; }

/* ---- B4 / B6 — les trois boutons de suivi ---- */
.progress-row {
  display: flex;
  flex: none;
  gap: 7px;
  margin-top: 0;
  flex-wrap: wrap;
  /* `align-items` explicite : sans lui, les boutons héritent de `stretch` et
     s'étirent sur toute la hauteur disponible dès que le parent est haut. */
  align-items: center;
}

.progress-row button {
  flex: 1 1 0;
  min-width: 86px;
  /* `height` fixe et non `min-height` : dans un conteneur étiré, `min-height`
     n'empêche pas de grandir. Défaut constaté à la revue visuelle du 30/07,
     où les boutons faisaient 210 px de haut. */
  height: 40px;
  padding: 0 10px;
  color: #cddbe1;
  background: rgba(9, 19, 26, 0.7);
  border: 1px solid #3c5764;
  border-radius: 10px;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.progress-row button:hover:not(:disabled) { border-color: #d49a58; color: #f0e2cd; }
.progress-row button:disabled { opacity: 0.45; cursor: default; }

/* Deux exceptions, deux couleurs distinctes : un retard n'est pas une absence,
   et David doit les distinguer d'un coup d'oeil sans lire le libelle. */
.progress-row button.is-active { color: #10171b; border-color: transparent; }

/* En retard : ambre — le client est venu. */
.progress-row button[data-progress="late"].is-active {
  background: linear-gradient(135deg, #f0c479, #cf9a3f);
}

/* Absent : rouge — le client n'est pas venu. */
.progress-row button[data-progress="no_show"].is-active {
  background: linear-gradient(135deg, #f0a58f, #c9705a);
}

/* ---- B5 — la coupe en menus ---- */
.haircut-box {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  padding: clamp(10px, .7vw, 13px);
  background: rgba(9, 19, 26, 0.45);
  border: 1px solid rgba(60, 87, 100, 0.7);
  border-radius: 14px;
}

.haircut-box > span {
  display: block;
  margin-bottom: 8px;
  color: #d0a86a;
  font-size: 0.82rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.haircut-previous { flex: none; margin: 0 0 8px; color: #9db0b8; font-size: 0.8rem; line-height: 1.35; }

/* Deux colonnes : le libellé et son menu. `minmax(0, 1fr)` est indispensable —
   sans lui, un libellé long ferait déborder la carte au lieu de la comprimer. */
/* DEUX paires « libellé + menu » par ligne : cinq menus empilés faisaient
   perdre près de 150 px de hauteur, que David refuse de payer en défilement. */
.haircut-grid {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 6px 9px;
  align-items: center;
}

.haircut-grid label {
  margin: 0;
  color: #cddbe1;
  font-size: 0.88rem;
  font-weight: 700;
}

.haircut-grid select {
  width: 100%;
  min-height: 38px;
  padding: 0 8px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 9px;
  font: inherit;
}

.haircut-grid select:focus { outline: 2px solid #d49a58; outline-offset: 1px; }
.haircut-grid select:disabled { opacity: 0.5; }

.haircut-box textarea {
  flex: 1 1 0;
  width: 100%;
  min-height: 40px;
  margin-top: 8px;
  padding: 7px 9px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 10px;
  font: inherit;
  resize: vertical;
}

.haircut-box textarea:disabled { opacity: 0.5; }

.haircut-actions { display: flex; flex: none; gap: 10px; align-items: center; margin-top: 8px; }
.haircut-actions .haircut-status { flex: 1 1 auto; min-height: 0; margin: 0; text-align: left; }

.save-haircut {
  flex: none;
  min-height: 38px;
  padding: 0 14px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 10px;
  font: inherit;
  font-weight: 900;
  cursor: pointer;
}

.save-haircut:disabled { opacity: 0.5; cursor: default; }

.haircut-status { color: #9db0b8; font-size: 0.8rem; }

.haircut-status.is-error { color: #ffaaa2; }

/* ---- B7 — tarifs et services ---- */
.pricing-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(4, 9, 13, .72);
}

.pricing-overlay[hidden] { display: none; }

.pricing-dialog {
  display: flex;
  flex-direction: column;
  width: min(880px, 100%);
  max-height: min(88dvh, 820px);
  padding: 22px;
  color: #edf5f7;
  background: rgba(18, 32, 41, .98);
  border: 1px solid rgba(218, 167, 93, .26);
  border-radius: 20px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .45);
}

.pricing-head { display: flex; gap: 14px; align-items: flex-start; justify-content: space-between; }
.pricing-head h2 { margin: 0; font-size: 1.35rem; }
.pricing-hint { margin: 4px 0 0; color: #9db0b8; font-size: .84rem; }

.pricing-head-actions { display: flex; flex: none; gap: 8px; align-items: center; }

/* Ciblé sur la croix, PAS sur « .pricing-head button » : la règle carrée de
   34 px écraserait le bouton « Ajouter » posé juste à côté. */
#pricing-close {
  flex: none;
  width: 34px; height: 34px;
  padding: 0;
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 10px;
  color: #eadfd0;
  background: rgba(20, 39, 49, .88);
  font-size: 21px; line-height: 1;
  cursor: pointer;
}

.pricing-add {
  flex: none;
  min-height: 34px;
  padding: 0 14px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 10px;
  font: inherit; font-weight: 850; font-size: .84rem;
  white-space: nowrap;
  cursor: pointer;
}
.pricing-add.is-open { color: #eadfd0; background: rgba(20, 39, 49, .88); border: 1px solid rgba(215, 179, 107, .28); }

/* Les six colonnes sont définies UNE fois et partagées par l'en-tête et les
   lignes : sans ça, les titres et les champs se décalent dès qu'un nom est
   long. « Sur le site » et « Réservable » sont deux choses distinctes — une
   prestation peut être affichée sans être réservable en ligne. */
.pricing-cols,
.pricing-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 78px 88px 78px 78px 176px;
  gap: 10px;
  align-items: center;
}

.pricing-cols {
  margin: 16px 0 6px;
  padding: 0 2px;
  color: #9eabb1;
  font-size: .7rem; font-weight: 850; letter-spacing: .09em; text-transform: uppercase;
}
.pricing-cols span:nth-child(n+2) { text-align: center; }

/* C'est CETTE zone qui défile, pas la fenêtre : l'en-tête et les titres de
   colonnes restent à l'écran pendant qu'on parcourt la liste.
   `scrollbar-gutter: stable` réserve la place de la barre en permanence — sans
   ça, les colonnes sautaient de 15 px dès que la liste devenait assez courte
   pour ne plus défiler. La compensation exacte est posée en JS, parce que la
   largeur d'une barre de défilement dépend du système. */
.pricing-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; padding-right: 4px; }

.pricing-row {
  padding: 9px 2px;
  border-top: 1px solid rgba(215, 179, 107, .1);
}
.pricing-row.is-inactive { opacity: .55; }

.pricing-name { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.pricing-name strong { overflow-wrap: anywhere; font-size: .95rem; }
.pricing-name small { color: #9db0b8; font-size: .78rem; }

/* Le nom est un bouton : c'est par lui qu'on renomme et qu'on duplique. Il
   garde l'allure d'un texte — un bouton de plus par ligne aurait encombré une
   liste qu'on lit vingt fois par jour. Le soulignement au survol dit qu'il
   est cliquable. */
.pricing-name-btn {
  padding: 0;
  color: inherit;
  background: none;
  border: 0;
  font: inherit; font-weight: 700; font-size: .95rem;
  text-align: start;
  overflow-wrap: anywhere;
  cursor: pointer;
}
.pricing-name-btn:hover { color: #f2c486; text-decoration: underline; }
.pricing-name-btn:focus-visible { outline: 2px solid #d49a58; outline-offset: 2px; border-radius: 4px; }

.pricing-new-title { margin: 0 0 12px; color: #e8c48d; font-size: .95rem; font-weight: 850; }

.pricing-row input[type="number"] {
  width: 100%;
  min-height: 36px;
  padding: 0 8px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 9px;
  font: inherit;
  text-align: center;
}
.pricing-row input[type="number"]:focus { outline: 2px solid #d49a58; outline-offset: 1px; }
.pricing-row input[type="number"]:disabled { opacity: .45; }

/* Chaque case est enveloppée d'un libellé. Sur grand écran le titre de colonne
   suffit et le libellé reste caché ; sur téléphone les colonnes disparaissent,
   et c'est lui qui dit ce que la case commande. */
.pricing-check { display: flex; gap: 6px; align-items: center; justify-content: center; min-width: 0; cursor: pointer; }
.pricing-check span { display: none; color: #9db0b8; font-size: .78rem; }
.pricing-check input[type="checkbox"] { width: 20px; height: 20px; accent-color: #c98d4f; cursor: pointer; }
.pricing-check input[type="checkbox"]:disabled { cursor: default; opacity: .4; }

.pricing-save {
  min-height: 36px;
  padding: 0 10px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 9px;
  font: inherit; font-weight: 850; font-size: .84rem;
  cursor: pointer;
}
.pricing-save:disabled { color: #cddbe1; background: none; border: 1px solid #3c5764; cursor: default; opacity: .6; }

/* Les deux actions de la ligne. « Retirer » est volontairement discret :
   c'est « Enregistrer » qu'on cherche vingt fois par jour, pas l'autre. */
.pricing-actions { display: flex; gap: 8px; align-items: center; justify-content: flex-end; }

.pricing-remove,
.pricing-ghost {
  min-height: 36px;
  padding: 0 10px;
  color: #cddbe1;
  background: none;
  border: 1px solid #3c5764;
  border-radius: 9px;
  font: inherit; font-weight: 700; font-size: .8rem;
  white-space: nowrap;
  cursor: pointer;
}
.pricing-remove:hover { color: #ffb4ac; border-color: #7c4a45; }

/* Effacer pour de bon. Rouge franc, parce que c'est la seule action de tout
   le Hub qui ne se rattrape pas. */
.pricing-danger {
  min-height: 36px;
  padding: 0 12px;
  color: #ffd9d4;
  background: rgba(96, 34, 30, .55);
  border: 1px solid #8d4f49;
  border-radius: 9px;
  font: inherit; font-weight: 800; font-size: .8rem;
  white-space: nowrap;
  cursor: pointer;
}
.pricing-danger:hover { background: rgba(126, 42, 36, .75); }

/* ---- Création d'une prestation ---- */
.pricing-new {
  margin: 14px 0 2px;
  padding: 14px;
  background: rgba(9, 19, 26, .7);
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 14px;
}
.pricing-new[hidden] { display: none; }

.pricing-new-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}
.pricing-new-grid label,
.pricing-new-check { display: flex; flex-direction: column; gap: 4px; color: #9eabb1; font-size: .74rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; }

.pricing-new input[type="text"],
.pricing-new input[type="number"] {
  min-height: 38px;
  padding: 0 10px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 9px;
  font: inherit; font-weight: 400; letter-spacing: normal; text-transform: none;
}
.pricing-new input:focus { outline: 2px solid #d49a58; outline-offset: 1px; }
.pricing-new input:disabled { opacity: .45; }

.pricing-new-check { flex-direction: row; align-items: center; gap: 8px; margin-top: 12px; text-transform: none; letter-spacing: normal; font-size: .84rem; font-weight: 600; color: #cddbe1; cursor: pointer; }
.pricing-new-check input { width: 18px; height: 18px; accent-color: #c98d4f; cursor: pointer; }

.pricing-new-actions { display: flex; gap: 8px; margin-top: 14px; }

.pricing-create {
  min-height: 38px;
  padding: 0 16px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 9px;
  font: inherit; font-weight: 850; font-size: .86rem;
  cursor: pointer;
}
.pricing-create:disabled { color: #cddbe1; background: none; border: 1px solid #3c5764; cursor: default; opacity: .6; }

.pricing-new-note { margin: 12px 0 0; color: #9db0b8; font-size: .8rem; line-height: 1.45; }
.pricing-new-note strong { color: #e8c48d; }

/* ---- Services retirés ---- */
.pricing-retired { flex: none; margin-top: 10px; border-top: 1px solid rgba(215, 179, 107, .14); padding-top: 10px; }
.pricing-retired[hidden] { display: none; }

.pricing-retired summary {
  padding: 4px 2px;
  color: #9eabb1;
  font-size: .8rem; font-weight: 800; letter-spacing: .05em;
  cursor: pointer;
  list-style: none;
}
.pricing-retired summary::-webkit-details-marker { display: none; }
.pricing-retired summary::before { content: '▸ '; color: #c98d4f; }
.pricing-retired[open] summary::before { content: '▾ '; }
.pricing-retired summary:hover { color: #e0e9ec; }

.pricing-retired-list { max-height: 190px; overflow-y: auto; margin-top: 6px; padding-right: 4px; }

.pricing-retired-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 9px 2px;
  border-top: 1px solid rgba(215, 179, 107, .08);
}
.pricing-retired-row .pricing-name strong { color: #b9c6cc; font-weight: 600; }

/* Pourquoi ce service ne peut pas être effacé : dit en clair, à sa place. */
.pricing-kept { margin: 2px 0 0; color: #8fa0a7; font-size: .74rem; }

.pricing-status { min-height: 1.3em; margin: 12px 0 0; color: #9db0b8; font-size: .86rem; }
.pricing-status.is-error { color: #ffaaa2; }
.pricing-empty { margin: 18px 0; color: #9db0b8; text-align: center; }

@media (max-width: 700px) {
  /* Les titres de colonnes n'ont plus de sens quand les champs s'empilent :
     ce sont les libellés des cases qui prennent le relais. */
  .pricing-cols { display: none; }

  .pricing-row {
    grid-template-columns: 88px 92px minmax(0, 1fr);
    grid-template-areas:
      "nom   nom   nom"
      "duree prix  act"
      "site  site  resa";
    row-gap: 8px;
  }
  .pricing-name     { grid-area: nom; }
  .pricing-duration { grid-area: duree; }
  .pricing-price    { grid-area: prix; }
  .pricing-actions  { grid-area: act; }
  .pricing-check-visible  { grid-area: site; }
  .pricing-check-bookable { grid-area: resa; }
  .pricing-check { justify-content: flex-start; }
  .pricing-check span { display: inline; }

  .pricing-new-grid { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); }
}

/* ---- Changement de mot de passe (depuis la roue) ---- */
.password-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(4, 9, 13, 0.72);
}

.password-overlay[hidden] { display: none; }

.password-dialog {
  width: min(420px, 100%);
  padding: 26px;
  color: #edf5f7;
  background: rgba(18, 32, 41, 0.98);
  border: 1px solid rgba(218, 167, 93, 0.26);
  border-radius: 20px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.45);
}

.password-dialog h2 { margin: 0 0 4px; font-size: 1.35rem; }

.password-dialog #password-account {
  margin: 0 0 6px;
  color: #d0a86a;
  font-size: 0.92rem;
  word-break: break-all;
}

.password-dialog label {
  display: block;
  margin: 16px 0 6px;
  color: #dce7ea;
  font-weight: 700;
}

.password-dialog input {
  width: 100%;
  min-height: 48px;
  padding: 0 13px;
  color: #fff;
  background: #09131a;
  border: 1px solid #39505b;
  border-radius: 11px;
  font: inherit;
}

.password-dialog input:focus { outline: 2px solid #d49a58; outline-offset: 2px; }

.password-hint { margin: 12px 0 0; color: #8ea3ac; font-size: 0.86rem; }

.password-status { min-height: 1.3em; margin: 8px 0 0; font-size: 0.92rem; }
.password-status.is-error { color: #ffaaa2; }

.password-actions { display: flex; gap: 10px; margin-top: 16px; }

.password-actions button {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  /* Bordure transparente plutôt que `0` : sans elle, le bouton secondaire —
     qui en porte une — serait 2 px plus large. Même modèle de boîte des deux
     côtés, donc deux boutons rigoureusement identiques. */
  border: 1px solid transparent;
  border-radius: 11px;
  font: inherit;
  font-weight: 900;
}

.password-actions button.is-secondary {
  color: #cddbe1;
  background: none;
  border-color: #3c5764;
  font-weight: 700;
}

.password-actions button:disabled { opacity: 0.55; }

.login-status.is-error { color: #ffaaa2; }

.appointments-empty {
  display: grid;
  place-items: center;
  min-height: 126px;
  padding: 20px;
  color: #9eb0b7;
  text-align: center;
  border: 1px dashed rgba(138, 164, 174, 0.25);
  border-radius: 14px;
}

.appointments-empty.is-loading::before {
  content: '';
  width: 22px;
  height: 22px;
  margin-bottom: 10px;
  border: 3px solid rgba(255, 255, 255, 0.15);
  border-top-color: #d9a15f;
  border-radius: 50%;
  animation: hub-spin 0.8s linear infinite;
}

.appointments-empty.is-error { color: #ffb9b2; }

.dates button:disabled {
  cursor: not-allowed;
  opacity: 1;
}

@keyframes hub-spin { to { transform: rotate(360deg); } }
@keyframes hub-breathe {
  0%, 100% { box-shadow: 0 0 0 2px rgba(85, 181, 138, .08); opacity: .72; }
  50% { box-shadow: 0 0 0 7px rgba(85, 181, 138, .18); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .appointments-empty.is-loading::before { animation: none; }
  .appointment.is-in-progress .dot { animation: none; }
  .live-dot.is-in-progress { animation: none; }
}

/* ===========================================================================
   C1 — PANNEAU AGENDA (31/07/2026)

   L'agenda s'ouvre par-dessus le Hub au lieu de le remplacer. Meme famille
   visuelle que les trois panneaux existants (tarifs, mot de passe,
   encaissement), mais nettement plus grand : ce n'est pas une boite de
   dialogue, c'est une application entiere.

   Piege de mise en page deja paye le 30/07 : dans un conteneur flex, un
   enfant refuse de retrecir sous sa taille de contenu tant qu'on ne lui pose
   pas `min-height: 0`. Sans cette ligne, le cadre pousserait l'en-tete hors
   de l'ecran au lieu de se limiter a la place restante.
   =========================================================================== */

.agenda-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;              /* au-dessus des tarifs (60) : c'est le plus grand */
  display: grid;
  place-items: center;
  padding: clamp(8px, 1.4vw, 24px);
  background: rgba(4, 9, 13, .78);
}

.agenda-overlay[hidden] { display: none; }

.agenda-dialog {
  display: flex;
  flex-direction: column;
  width: min(1680px, 100%);
  height: min(96dvh, 1100px);   /* `height`, pas `max-height` : le cadre doit
                                   remplir, pas se contenter d'un minimum. */
  overflow: hidden;
  color: #edf5f7;
  background: rgba(18, 32, 41, .98);
  border: 1px solid rgba(218, 167, 93, .26);
  border-radius: 20px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .45);
}

.agenda-panel-head {
  display: flex;
  flex: none;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid rgba(215, 179, 107, .18);
}

.agenda-panel-head h2 { margin: 0; font-size: 1.2rem; }

.agenda-panel-actions { display: flex; flex: none; gap: 8px; align-items: center; }

.agenda-panel-actions button {
  flex: none;
  width: 34px; height: 34px;
  padding: 0;
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 10px;
  color: #eadfd0;
  background: rgba(20, 39, 49, .88);
  font-size: 19px; line-height: 1;
  cursor: pointer;
}
.agenda-panel-actions button:hover { background: rgba(28, 52, 64, .95); }
.agenda-panel-actions button:disabled { cursor: progress; opacity: .55; }

#agenda-panel-close { font-size: 21px; }

.agenda-panel-status {
  flex: none;
  margin: 0;
  padding: 8px 18px;
  color: #9db0b8;
  font-size: .84rem;
}
.agenda-panel-status[hidden] { display: none; }
.agenda-panel-status.is-error { color: #ffb9b2; }

#agenda-frame {
  flex: 1 1 auto;
  min-height: 0;            /* sans cette ligne, l'en-tete sort de l'ecran */
  width: 100%;
  border: 0;
  background: #0b141a;
}

/* Telephone et petite tablette : le panneau prend tout, les arrondis n'ont
   plus de sens et volent de la place a l'agenda. */
@media (max-width: 760px) {
  .agenda-overlay { padding: 0; }
  .agenda-dialog {
    width: 100%;
    height: 100dvh;
    border: 0;
    border-radius: 0;
  }
}
/* Le repli n'apparait qu'en cas d'echec. Sans style propre il sortirait en
   gris systeme au milieu d'un panneau sombre. */
#agenda-panel-fallback {
  margin-left: 10px;
  padding: 4px 12px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 8px;
  font: inherit; font-weight: 800; font-size: .82rem;
  cursor: pointer;
}
#agenda-panel-fallback[hidden] { display: none; }

/* ===========================================================================
   B3-a — L'ECRAN OPTIONS (31/07/2026)

   Il ne connait aucun reglage : il stylise des TYPES (interrupteur, liste,
   nombre) et des GROUPES. Un reglage ajoute en base demain sera mis en page
   par ces regles sans qu on y touche.
   =========================================================================== */

.settings-overlay {
  position: fixed;
  inset: 0;
  z-index: 65;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(4, 9, 13, .72);
}
.settings-overlay[hidden] { display: none; }

.settings-dialog {
  display: flex;
  flex-direction: column;
  width: min(620px, 100%);
  max-height: min(88dvh, 780px);
  color: #edf5f7;
  background: rgba(18, 32, 41, .98);
  border: 1px solid rgba(218, 167, 93, .26);
  border-radius: 20px;
  box-shadow: 0 26px 70px rgba(0, 0, 0, .45);
}

.settings-head {
  display: flex; flex: none;
  align-items: center; justify-content: space-between;
  padding: 18px 22px 14px;
  border-bottom: 1px solid rgba(215, 179, 107, .18);
}
.settings-head h2 { margin: 0; font-size: 1.3rem; }
#settings-close {
  flex: none;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 10px;
  color: #eadfd0; background: rgba(20, 39, 49, .88);
  font-size: 21px; line-height: 1; cursor: pointer;
}

.settings-body {
  flex: 1 1 auto;
  min-height: 0;              /* meme piege qu en C1 : sans lui, le pied sort */
  overflow-y: auto;
  padding: 6px 22px 12px;
}

/* --- un groupe --- */
.settings-group { padding: 12px 0; border-bottom: 1px solid rgba(215, 179, 107, .1); }
.settings-group:last-child { border-bottom: 0; }
.settings-group > summary,
.settings-group-title {
  margin: 0 0 6px;
  color: #d7b36b;
  font-size: .78rem; font-weight: 800;
  letter-spacing: .09em; text-transform: uppercase;
}
.settings-group > summary { cursor: pointer; list-style: none; }
.settings-group > summary::-webkit-details-marker { display: none; }
.settings-group > summary::before { content: '▸ '; }
.settings-group[open] > summary::before { content: '▾ '; }

/* --- une ligne de reglage --- */
.setting-row {
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;           /* meme hauteur pour tous les types */
  padding: 4px 0;
}
.setting-label { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.setting-label > span { font-size: .95rem; }
.setting-label > small { color: #9db0b8; font-size: .78rem; }

.setting-control { display: flex; flex: none; gap: 8px; align-items: center; }
.setting-control select,
.setting-control input[type="number"],
.setting-control input[type="text"] {
  min-height: 34px;
  padding: 0 10px;
  color: #edf5f7;
  background: rgba(11, 20, 26, .9);
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 9px;
  font: inherit; font-size: .88rem;
}
.setting-control input[type="number"] { width: 86px; }
.setting-control input[type="text"]   { width: 190px; }
.setting-unit { color: #9db0b8; font-size: .82rem; }

/* --- l interrupteur --- */
.setting-switch { position: relative; display: inline-flex; flex: none; }
.setting-switch input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.setting-switch i {
  display: block;
  width: 50px; height: 28px;
  background: rgba(11, 20, 26, .9);
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 999px;
  transition: background .18s ease, border-color .18s ease;
}
.setting-switch i::after {
  content: '';
  position: absolute; top: 4px; left: 4px;
  width: 20px; height: 20px;
  background: #9db0b8;
  border-radius: 50%;
  transition: transform .18s ease, background .18s ease;
}
.setting-switch input:checked + i { background: rgba(85, 181, 138, .28); border-color: rgba(85, 181, 138, .5); }
.setting-switch input:checked + i::after { transform: translateX(22px); background: #55b58a; }
.setting-switch input:focus-visible + i { outline: 2px solid #d7b36b; outline-offset: 2px; }

/* --- pied --- */
.settings-foot {
  display: flex; flex: none;
  gap: 14px; align-items: center; justify-content: space-between;
  padding: 14px 22px 18px;
  border-top: 1px solid rgba(215, 179, 107, .18);
}
.settings-status { margin: 0; color: #9db0b8; font-size: .84rem; }
.settings-status.is-error { color: #ffb9b2; }
.settings-save {
  flex: none;
  min-height: 38px; padding: 0 20px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0; border-radius: 10px;
  font: inherit; font-weight: 850;
  cursor: pointer;
}
.settings-save:disabled { cursor: default; opacity: .45; }

@media (max-width: 620px) {
  .settings-overlay { padding: 0; }
  .settings-dialog { width: 100%; height: 100dvh; max-height: none; border: 0; border-radius: 0; }
  .setting-row { flex-direction: column; align-items: flex-start; gap: 6px; }
  .setting-control { width: 100%; }
  .setting-control select { flex: 1 1 auto; }
}

/* ===========================================================================
   C2 — LE PLANNING QUI SUIT L HEURE (31/07/2026)
   =========================================================================== */

/* Le retard, signale tout seul. Une bande a gauche et un fond tres discret :
   la ligne doit attirer l oeil sans hurler, et surtout sans se confondre avec
   la selection ni avec le rendez-vous en cours. */
.appointment.is-late {
  background: rgba(214, 154, 67, .14);
  box-shadow: inset 3px 0 var(--amber);
}
.appointment.is-late .dot { background: var(--amber); }
.appointment.is-late:hover { background: rgba(214, 154, 67, .22); }

/* Le rendez-vous en cours reste prioritaire sur le retard : il est selectionne,
   donc David sait deja ou il en est. */
.appointment.is-in-progress.is-late {
  background: rgba(50, 101, 83, .32);
  box-shadow: inset 3px 0 var(--status-in-progress);
}

/* « Maintenant » — flotte au-dessus de la liste, en bas. N apparait QUE si le
   suivi est suspendu. Position absolue dans la carte, qui devient le repere. */
.agenda-card { position: relative; }

.back-to-now {
  position: absolute;
  right: 14px;
  bottom: 12px;
  z-index: 2;
  min-height: 32px;
  padding: 0 15px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .38);
  font: inherit; font-weight: 850; font-size: .8rem;
  white-space: nowrap;
  cursor: pointer;
}
.back-to-now[hidden] { display: none; }
.back-to-now:hover { filter: brightness(1.06); }
.back-to-now:focus-visible { outline: 2px solid #fff8ee; outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .back-to-now { box-shadow: 0 4px 12px rgba(0, 0, 0, .38); }
}

/* C5 — LE BANDEAU DU BILAN.
   Une ligne au bas de la colonne du planning, discrète, qui EST le bouton.
   Ce n'est pas un écran de plus (règle R5) : c'est une rangée de plus dans une
   colonne qui existe, et le détail s'ouvre dans l'overlay de la famille. */
.day-summary-bar {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 34px;
  margin-top: 8px;
  padding: 0 11px;
  border: 1px solid rgba(215, 179, 107, .22);
  border-radius: 10px;
  color: #d9cfc2;
  background: rgba(255, 255, 255, .04);
  font: inherit;
  font-size: .78rem;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}
.day-summary-bar[hidden] { display: none; }
.day-summary-bar:hover { border-color: rgba(215, 179, 107, .42); background: rgba(255, 255, 255, .07); }
.day-summary-bar:focus-visible { outline: 2px solid #fff8ee; outline-offset: 2px; }
/* La ligne peut être longue un jour chargé : elle se coupe proprement plutôt
   que de pousser la flèche hors du bandeau. */
.day-summary-bar .dsb-line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.day-summary-bar .dsb-more { flex: 0 0 auto; color: #efbd91; font-weight: 900; }

/* Les cases du bilan reprennent celles de la fiche client : même dessin, même
   comportement pour « en attente ». Une seule différence, la note explicative. */
#day-overlay-body .cf-stats { margin: 0 0 8px; }
#day-overlay-body .cf-stat { flex: 1 1 92px; padding: 8px 9px; border-radius: 10px; background: rgba(215, 179, 107, .1); text-align: center; }
#day-overlay-body .cf-stat b { display: block; color: #fff5e8; font-size: 20px; font-weight: 900; }
#day-overlay-body .cf-stat span { display: block; margin-top: 2px; color: #b3bdc2; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; }
#day-overlay-body .cf-stat small { display: block; margin-top: 3px; color: #8f9ca3; font-size: 10px; }
#day-overlay-body .cf-stat.is-pending b { color: #8f9ca3; }
#day-overlay-body .cf-box li { display: flex; gap: 10px; align-items: baseline; justify-content: space-between; }
#day-overlay-body .cf-box li small { display: block; margin: 0; color: #b3bdc2; }
#day-overlay-body .cf-contact { margin: 0 0 8px; color: #b3bdc2; font-size: 13px; }
#day-overlay-body .cf-empty { margin: 0 0 8px; color: #8f9ca3; font-size: 12px; font-style: italic; }

/* =====================================================================
   C13 — « Ce que la mesure vous apprend » (03/08/2026)

   Aucun overlay nouveau : on habille la famille `settings-overlay` déjà
   posée. Seules changent la largeur (c'est un texte qu'on lit, pas un
   formulaire qu'on remplit) et la mise en forme des listes.
   ===================================================================== */

/* ⚠️  LARGEUR CHOISIE POUR LA LECTURE, PAS POUR REMPLIR L'ÉCRAN.
   Premier jet à 780 px : vu en capture, les paragraphes s'arrêtaient au
   deux tiers pendant que l'encadré, lui, allait au bout — l'écran avait
   l'air cassé alors que chaque bloc était « correct » pris seul. À 640 px,
   tout partage la même mesure (~80 caractères), les bords s'alignent, et
   la ligne reste lisible. Un texte trop large ne se lit pas : ce n'est pas
   un tableau, c'est une page. */
.analytics-dialog { width: min(640px, 100%); max-height: min(90dvh, 900px); }

/* ⚠️  AUCUNE `max-width` sur les blocs de texte. C'est la largeur du
   dialogue (640 px) qui fixe la mesure, une fois pour toutes. Des limites
   par bloc — 64ch ici, 68ch là, 72ch ailleurs — donnaient trois bords
   droits différents dans la même page. */
.analytics-sub {
  margin: 12px 0 0;
  color: #9db0b8;
  font-size: .82rem;
  line-height: 1.55;
}

/* Même dessin que la croix des Options — la règle est ciblée par
   identifiant, elle ne se propage pas toute seule. */
#analytics-close {
  flex: none;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid rgba(215, 179, 107, .2);
  border-radius: 10px;
  color: #eadfd0; background: rgba(20, 39, 49, .88);
  font-size: 21px; line-height: 1; cursor: pointer;
}
#analytics-close:focus-visible { outline: 2px solid #fff8ee; outline-offset: 2px; }

.analytics-body { padding-bottom: 20px; }

/* L'accroche : ce qu'on lit si on ne lit qu'un paragraphe. */
.analytics-lead {
  margin: 12px 0 4px;
  padding: 12px 14px;
  color: #e7eef1;
  font-size: .9rem;
  line-height: 1.6;
  background: rgba(215, 179, 107, .09);
  border-left: 3px solid rgba(215, 179, 107, .5);
  border-radius: 0 10px 10px 0;
}
.analytics-lead strong { color: #f0d3a4; }

.analytics-h3 {
  margin: 26px 0 4px;
  padding-bottom: 6px;
  color: #d7b36b;
  font-size: .82rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .06em;
  border-bottom: 1px solid rgba(215, 179, 107, .16);
}
/* La pastille dit d'un coup d'œil si la section décrit ce qui marche, ce
   qui pourrait se faire, ou ce qui ne se fera pas. Le mot reste dans le
   titre : la couleur seule ne se lit pas pour tout le monde. */
.analytics-h3::before { margin-right: 7px; }
.analytics-h3.is-yes::before   { content: '✅'; }
.analytics-h3.is-maybe::before { content: '🧭'; }
.analytics-h3.is-no::before    { content: '⛔'; }

.analytics-note {
  margin: 8px 0 0;
  color: #9db0b8;
  font-size: .8rem;
  line-height: 1.55;
}
.analytics-foot { margin-top: 14px; font-style: italic; }

.analytics-list { margin: 12px 0 0; padding: 0; list-style: none; }

.analytics-list li {
  padding: 11px 0;
  border-bottom: 1px solid rgba(215, 179, 107, .09);
}
.analytics-list li:last-child { border-bottom: 0; }

.analytics-q {
  display: block;
  color: #fff5e8;
  font-size: .92rem; font-weight: 700;
  line-height: 1.45;
}
.analytics-a {
  display: block;
  margin-top: 4px;
  color: #b3bdc2;
  font-size: .84rem;
  line-height: 1.6;
}
.analytics-a strong { color: #e6d3b0; }
.analytics-a em { color: #cdd7db; font-style: italic; }

/* Section « jamais mesuré » : le trait passe au rouge sourd, pour qu'on
   voie sans lire qu'on a changé de registre. */
.analytics-list.is-no li { border-bottom-color: rgba(226, 122, 108, .14); }
.analytics-list.is-no .analytics-q { color: #f0c7bf; }

.analytics-tag {
  display: inline-block;
  margin-left: 7px;
  padding: 1px 7px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border-radius: 999px;
  font-size: .64rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .05em;
  vertical-align: middle;
}
.analytics-tag.is-off {
  color: #f5e2de;
  background: rgba(226, 122, 108, .26);
  border: 1px solid rgba(226, 122, 108, .4);
}

.analytics-link-row { margin: 14px 0 0; }
.analytics-link {
  display: inline-block;
  min-height: 44px;              /* cible tactile : le Hub sert aussi au doigt */
  padding: 11px 18px;
  color: #10171b;
  background: linear-gradient(135deg, #f2c486, #c98d4f);
  border-radius: 12px;
  font-size: .88rem; font-weight: 800;
  text-decoration: none;
}
.analytics-link:hover { filter: brightness(1.06); }
.analytics-link:focus-visible { outline: 2px solid #fff8ee; outline-offset: 2px; }

/* Sur téléphone, la boîte occupe tout l'écran : un texte long dans une
   fenêtre de 300 px avec des marges de 22 px n'est plus lisible. */
@media (max-width: 560px) {
  .analytics-dialog { max-height: 94dvh; }
  .analytics-sub { font-size: .78rem; }
  .analytics-q { font-size: .88rem; }
  .analytics-a { font-size: .81rem; }
}

/* ===========================================================================
   CA-3 — L'ÉCRAN DE PAIEMENT

   Il passe DEVANT le panier (z-index 65 contre 60) : le panier reste dessous,
   visible en flou, parce que David doit pouvoir revenir en arrière sans que
   son choix de prestations disparaisse.

   ⚠️  AUCUNE COULEUR EN DUR (règle D15) : tout vient des variables de thème
       déclarées en tête de cette feuille. Un repreneur rhabille cet écran en
       changeant `--gold`, `--copper`, `--red`, `--green` — pas en ouvrant ce
       bloc.

   Les cibles sont grandes (56 px de haut, flèches de 46 px) : cet écran se
   pilote au doigt, sur le poste tactile du salon, souvent en tenant autre
   chose de l'autre main.
   =========================================================================== */
.pay-overlay {
  position: fixed;
  z-index: 65;
  inset: 0;
  display: grid;
  place-items: center;
  padding: clamp(12px, 2.2vw, 34px);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(12px);
}
.pay-dialog {
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 1vw, 16px);
  width: min(620px, 100%);
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
  padding: clamp(16px, 1.8vw, 26px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  background: var(--panel);
  box-shadow: var(--shadow);
}
.pay-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.pay-head h2 { margin: 0; color: var(--gold); font: 500 clamp(19px, 1.6vw, 26px)/1.1 Georgia, serif; }
.pay-client { margin: 4px 0 0; color: var(--muted); font-size: 12px; font-weight: 750; }
.pay-close {
  min-width: 44px; min-height: 44px;
  border: 1px solid var(--line); border-radius: 14px;
  color: var(--text); background: transparent; font-size: 20px; cursor: pointer;
}

/* L'état du geste : neutre, refusé, ou passé. Le refus est ROUGE et le mot
   affiché est le code du serveur tant qu'aucun libellé n'est en base. */
.pay-status { min-height: 18px; margin: 0; color: var(--muted); font-size: 12px; font-weight: 750; }
.pay-status.is-refus { color: var(--red); }
.pay-status.is-ok { color: var(--green); }

/* CA-3e — REPRISE APRÈS COUPURE.
   Il n'apparaît qu'après une panne réseau, et il doit alors se voir sans être
   cherché : c'est la seule chose à faire à ce moment-là. Bordure ambre, comme
   la confirmation Bit — un état d'attente, pas un refus. */
.pay-retry {
  min-height: 64px;
  border: 2px solid var(--amber);
  background: transparent;
  color: var(--amber);
  font-size: 16px;
}

.pay-step { display: flex; flex-direction: column; gap: clamp(10px, 1vw, 16px); }

/* Les trois chiffres qui viennent du serveur. Ils ne sont JAMAIS calculés
   ici : total, TVA et reste dû sortent tels quels de la réponse JSON. */
.pay-figures { display: grid; gap: 8px; margin: 0; padding: 14px; border: 1px solid var(--line); border-radius: 16px; }
.pay-figures > div { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.pay-figures dt { color: var(--muted); font-size: 11px; font-weight: 850; letter-spacing: .06em; text-transform: uppercase; }
.pay-figures dd { margin: 0; color: var(--text); font: 500 clamp(17px, 1.4vw, 23px)/1 Georgia, serif; }
.pay-figures > div:last-child dd { color: var(--gold); }

.pay-payments { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.pay-payments li { display: flex; justify-content: space-between; gap: 10px; color: var(--muted); font-size: 12px; font-weight: 750; }

/* Les trois règlements. Pas de quatrième : ni chèque, ni virement. */
.pay-modes { display: flex; flex-direction: column; gap: 8px; }
.pay-mode-buttons { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.pay-mode-buttons button {
  min-height: 56px;
  border: 1px solid var(--line); border-radius: 16px;
  color: var(--text); background: transparent;
  font: inherit; font-size: 13px; font-weight: 850; cursor: pointer;
}
.pay-mode-buttons button.is-selected { border-color: var(--copper); color: var(--copper); }
.pay-mode-buttons button:disabled { opacity: .4; cursor: default; }

/* Les flèches. Unités, dizaines, centaines — jamais de saisie au clavier :
   le pourboire est en shekels entiers, et le serveur refuse le reste. */
.pay-stepper {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px 12px;
  padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 16px;
}
.pay-stepper-label { color: var(--muted); font-size: 11px; font-weight: 850; letter-spacing: .06em; text-transform: uppercase; }
.pay-stepper-value { color: var(--text); font: 500 clamp(19px, 1.5vw, 26px)/1 Georgia, serif; text-align: right; }
.pay-arrows { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.pay-arrows > div { display: grid; gap: 6px; }
.pay-arrows button {
  min-height: 46px;
  border: 1px solid var(--line); border-radius: 14px;
  color: var(--text); background: transparent;
  font: inherit; font-size: 15px; font-weight: 850; cursor: pointer;
}
.pay-arrows button:disabled { opacity: .4; cursor: default; }
.pay-arrows span { color: var(--muted); font-size: 10px; font-weight: 850; text-align: center; }

.pay-rendu { margin: 0; padding: 12px 14px; border: 1px solid var(--green); border-radius: 16px; color: var(--green); font-size: 14px; font-weight: 850; }

.pay-bit { display: flex; flex-direction: column; gap: 10px; padding: 14px; border: 1px solid var(--amber); border-radius: 16px; }
.pay-bit p { margin: 0; color: var(--amber); font-size: 13px; font-weight: 850; }
.pay-bit-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.pay-bit-actions button { min-height: 52px; border: 1px solid var(--line); border-radius: 14px; color: var(--text); background: transparent; font: inherit; font-weight: 850; cursor: pointer; }

/* ---------------------------------------------------------------------------
   A-8 — le cadre de paiement par carte

   370 × 455 px : ce n'est pas un choix de mise en page, c'est la dimension
   que le fournisseur donne pour son cadre. Le conteneur ne l'étire ni ne le
   comprime — un cadre de paiement redimensionné cache ses propres boutons.
   --------------------------------------------------------------------------- */
.pay-carte { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 14px; border: 1px solid var(--copper); border-radius: 16px; }
.pay-carte-titre { margin: 0; color: var(--copper); font-size: 13px; font-weight: 850; text-align: center; }
.pay-carte iframe { width: 370px; height: 455px; max-width: 100%; border: 0; border-radius: 12px; background: #fff; }
.pay-carte-note { margin: 0; color: var(--muted); font-size: 12px; text-align: center; }
.pay-carte-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; width: 100%; }
.pay-carte-actions button { min-height: 52px; border: 1px solid var(--line); border-radius: 14px; color: var(--text); background: transparent; font: inherit; font-weight: 850; cursor: pointer; }
.pay-carte-actions button:disabled { opacity: .45; cursor: default; }

.pay-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.pay-actions button { flex: 1 1 140px; min-height: 52px; border: 1px solid var(--line); border-radius: 16px; color: var(--text); background: transparent; font: inherit; font-weight: 850; cursor: pointer; }
.pay-main { min-height: 60px; border: 0; border-radius: 18px; color: var(--text); background: linear-gradient(145deg, var(--copper), var(--copper-dark)); font: inherit; font-size: 15px; font-weight: 900; cursor: pointer; }
.pay-actions button:disabled, .pay-main:disabled { opacity: .45; cursor: default; }
#pay-cancel-sale { border-color: var(--red); color: var(--red); }

/* ===========================================================================
   CA-3e — LES DEUX CHAMPS D'ESPÈCES, ET L'ÉCRAN DE CONFIRMATION

   Deux défauts vus sur la dalle le 06/08/2026 : « Montant » et « Montant
   reçu » se ressemblaient trop pour qu'on sache lequel déclare ce qu'on
   encaisse, et la fin d'un geste ne se lisait que dans une ligne de 12 px en
   haut de la fenêtre. Ce bloc répond aux deux.
   =========================================================================== */

/* Le champ SECONDAIRE — « Montant reçu » — ne sert qu'au rendu de monnaie. Il
   est visuellement en retrait du champ principal (« Montant réglé »), qui est
   le seul dont la valeur part au serveur. */
.pay-stepper-secondaire { border-style: dashed; opacity: .92; }
.pay-stepper-note {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--muted);
  font-size: 11px;
  font-weight: 750;
}

/* L'écran de confirmation : il se lit à un mètre, debout, sans lunettes. */
.pay-recap { gap: clamp(12px, 1.2vw, 20px); }
.pay-recap-title {
  margin: 0;
  color: var(--gold);
  font: 500 clamp(26px, 3vw, 40px)/1.1 Georgia, serif;
  text-align: center;
}
.pay-recap.is-payee .pay-recap-title { color: var(--green); }
.pay-recap.is-annulee .pay-recap-title { color: var(--red); }
.pay-recap.is-partielle .pay-recap-title { color: var(--amber); }

.pay-recap-detail { display: flex; flex-direction: column; gap: clamp(10px, 1vw, 16px); }

.pay-recap-lines, .pay-recap-payments {
  display: flex; flex-direction: column; gap: 8px;
  margin: 0; padding: 0; list-style: none;
}
.pay-recap-lines li, .pay-recap-payments li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  color: var(--text); font-size: clamp(15px, 1.2vw, 19px); font-weight: 750;
}
/* Une réduction se lit tout de suite comme une réduction : elle vient du
   serveur en ligne de vente négative, l'écran ne fait que la teinter. */
.pay-recap-lines li.is-reduction { color: var(--copper); }
.pay-recap-payments em { color: var(--muted); font-size: 12px; font-style: normal; font-weight: 750; }

/* Le reste dû : le seul chiffre de cet écran qui dise « ce n'est pas fini ».
   Il ne ressemble à rien d'autre, et c'est exprès. */
.pay-recap-reste {
  margin: 0;
  padding: 14px 16px;
  border: 2px solid var(--amber);
  border-radius: 16px;
  color: var(--amber);
  font-size: clamp(18px, 1.8vw, 26px);
  font-weight: 900;
  text-align: center;
}

/* La sortie de l'écran de confirmation. Elle est LARGE : la petite croix du
   bandeau ne doit jamais être la seule façon d'en finir. */
.pay-recap-close { min-height: 72px; font-size: 17px; }
