/**
 * item #332 (18e vague, retour Chloé) — "Admin prestataire : modernise
 * l'espace en terme de design" : même traitement que l'espace client
 * (item #326, 17e vague — ombres légères, coins arrondis, transitions,
 * états au survol/focus) mais appliqué ici aux briques COMMUNES à toutes
 * les pages du dashboard prestataire (.tpd-card, .tpd-btn, les champs de
 * formulaire, .tpd-stat-card, les lignes rendez-vous/prestations, le menu
 * de la sidebar) plutôt que de reprendre une à une chacune des ~25 pages
 * (view-*.php) qui les réutilisent — ces briques étant partagées, le
 * même bloc de règles suffit à moderniser l'ensemble du dashboard d'un
 * coup, de façon cohérente. Pas de changement de structure HTML/de
 * palette : uniquement de la profondeur (ombres), de la douceur
 * (transitions) et des états interactifs plus lisibles.
 */
:root {
	/* Aligned to the "Mon profil" mockup so every page in the prestataire
	   admin shares one visual language, not two that merely resemble each
	   other. */
	--tpd-ink: #111111;
	--tpd-paper: #FFFFFF;
	--tpd-sand: #FAF8F5;
	--tpd-line: #E7DBC6;
	--tpd-muted: #6F6A62;
	--tpd-accent: #A08D6B;
	--tpd-danger: #B3554A;
	--tpd-radius: 14px;
	/* item #332 (18e vague) — ombre légère partagée par .tpd-card et
	   .tpd-stat-card (repos), plus une variante un peu plus marquée pour le
	   survol/focus des éléments interactifs. */
	--tpd-shadow: 0 1px 2px rgba(17,17,17,0.04), 0 2px 8px rgba(17,17,17,0.04);
	--tpd-shadow-hover: 0 4px 14px rgba(17,17,17,0.08);
}

* { box-sizing: border-box; }

html, body {
	margin: 0;
	padding: 0;
	background: var(--tpd-sand);
	color: var(--tpd-ink);
	font-family: 'Work Sans', Arial, sans-serif;
	font-size: 15px;
	line-height: 1.5;
}

h1, h2, h3 { font-family: 'Bodoni Moda', Georgia, serif; font-weight: 600; margin: 0; }

.tpd-shell {
	display: flex;
	min-height: 100vh;
}

/* Sidebar */
.tpd-sidebar {
	width: 240px;
	flex-shrink: 0;
	/* item #133 — "couleur du bandeau du menu" (Réglages > Apparence),
	   independent from --tpd-ink (which stays the main text color used all
	   over the rest of the dashboard) — see TPD_Profile::menu_color() and
	   shell.php's inline override. Falls back to --tpd-ink, unchanged, when
	   no custom menu color has been set. */
	background: var(--tpd-sidebar-bg, var(--tpd-ink));
	color: var(--tpd-paper);
	display: flex;
	flex-direction: column;
	/* item 4 (27e vague, retour Chloé) — "réduit un peu la taille de la
	   barre du haut sur tous les appareils" : padding vertical réduit de
	   28px à 20px (28px → 20px ci-dessous ; voir aussi le margin-bottom de
	   .tpd-sidebar-bar juste plus bas, et l'équivalent mobile dans le
	   @media 900px, mêmes proportions). */
	padding: 20px 20px;
	position: sticky;
	top: 0;
	height: 100vh;
	overflow: hidden; /* only .tpd-nav scrolls — brand and footer always stay put */
}
/* item #316 (15e vague, retour Chloé) — la cloche de notifications vit à
   côté du logo/nom (voir .tpd-bell-wrap plus bas) : .tpd-sidebar-bar n'avait
   jusqu'ici de règle flex que dans le @media mobile (elle n'avait besoin de
   rien d'autre, une seule .tpd-brand dedans) — sur desktop c'était un simple
   bloc, .tpd-brand y prenait toute la largeur. Règle de base ajoutée pour
   que brand + cloche + (hamburger, masqué sur desktop) restent sur une
   ligne à toutes les tailles d'écran ; margin-bottom déplacé de .tpd-brand
   (seul usage de cette classe dans tout le plugin, voir shell.php) vers ce
   conteneur pour garder le même espacement avant .tpd-nav qu'avant. */
/* item 4 (27e vague, retour Chloé) — margin-bottom réduit de 40px à 26px,
   même logique que le padding de .tpd-sidebar ci-dessus : cette règle
   n'est pas redéfinie dans le @media mobile (voir juste plus bas), donc la
   réduction s'applique déjà "sur tous les appareils" sans rien dupliquer. */
.tpd-sidebar-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 26px; }
/* item #324 (17e vague, retour Chloé) — "sur mobile la cloche doit être
   placée à côté de l'icône du menu" : regroupe la cloche et le hamburger
   mobile en un seul enfant flex de .tpd-sidebar-bar (voir shell.php), pour
   que le space-between ci-dessus s'applique seulement entre le nom de
   l'activité et ce groupe — plus jamais un espace égal entre les 3, qui
   isolait la cloche au milieu de la barre au lieu de la coller au hamburger. */
.tpd-sidebar-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.tpd-brand { display: flex; align-items: center; gap: 10px; flex-shrink: 0; min-width: 0; }
.tpd-brand-mark { color: var(--tpd-accent); font-size: 18px; }
.tpd-brand-icon { width: 20px; height: 20px; object-fit: contain; border-radius: 5px; flex-shrink: 0; vertical-align: middle; }
/* item #132 — Chloé : "favicon sur /mon-espace dans le menu à mettre en
   blanc côté prestataires". Le fond de la barre latérale est sombre
   (--tpd-ink, voir .tpd-sidebar) ; filter: brightness(0) invert(1)
   transforme n'importe quelle icône (même en couleur) en silhouette
   blanche pour rester visible dessus. Uniquement dans la barre latérale —
   sur les pages Inscription/Connexion (fond clair), l'icône garde ses
   couleurs d'origine. */
.tpd-sidebar .tpd-brand-icon { filter: brightness(0) invert(1); }
/* item #316 (15e vague, retour Chloé) — même traitement que
   .tpd-loyalty-card-brand (item #299, même souci) : un nom d'activité un
   peu long ne doit pas pousser la cloche/le hamburger hors de la barre
   maintenant que .tpd-brand a min-width:0 (voir plus haut). */
.tpd-brand-name { font-family: 'Bodoni Moda', Georgia, serif; font-size: 16px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tpd-nav {
	display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; overflow-y: auto;
	/* item #115 — Chloé : "dans le menu je veux pas qu'on vois le curseur
	   pour descendre" — la barre de défilement du navigateur restait
	   visible en permanence sur la sidebar sombre. Le menu défile toujours
	   (overflow-y: auto ci-dessus, inchangé), seule la barre elle-même est
	   masquée. */
	scrollbar-width: none; /* Firefox */
	-ms-overflow-style: none; /* anciens Edge/IE */
}
.tpd-nav::-webkit-scrollbar { display: none; width: 0; height: 0; } /* Chrome/Safari/Edge */
.tpd-nav-item {
	color: rgba(255,255,255,0.75);
	text-decoration: none;
	padding: 11px 14px;
	border-radius: 6px;
	font-size: 14px;
	display: flex;
	align-items: center;
	justify-content: space-between;
	/* item #332 (18e vague) — transition douce plutôt qu'un changement de
	   fond instantané au survol/à l'activation. */
	transition: background 0.15s ease, color 0.15s ease;
}
.tpd-nav-item:hover { background: rgba(255,255,255,0.06); color: #fff; }
.tpd-nav-item.is-active { background: rgba(255,255,255,0.1); color: #fff; font-weight: 600; }
/* item #108 — "Messages" unread count, as a real badge instead of the old
   plain "(3)" text appended to the label — ".tpd-nav-item" is already
   flex/space-between, so this just needs to look like one; matches
   .tpd-thread-unread-badge inside the message list itself. */
.tpd-nav-badge {
	background: var(--tpd-danger);
	color: #fff;
	border-radius: 20px;
	padding: 1px 8px;
	font-size: 11px;
	font-weight: 600;
	flex-shrink: 0;
}
/* retour Chloé — "le badge de notification doit être rouge à côté du
   feature Avis au lieu de par exemple Avis (1)" : même pastille que
   .tpd-nav-badge juste au-dessus (même couleur, var(--tpd-danger)), mais
   un simple point sans chiffre — voir $tpd_nav_dot_keys dans
   class-tpd-router.php / shell.php. Même esprit que .tpd-bottom-nav-dot
   plus bas (barre mobile), en inline plutôt qu'en position:absolute
   puisqu'ici elle vit dans la même ligne flex que le reste du lien. */
.tpd-nav-badge-dot {
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--tpd-danger);
	flex-shrink: 0;
}
.tpd-nav-external { opacity: 0.5; font-size: 12px; }

/**
 * item #316 (15e vague, retour Chloé) — cloche de notifications, voir
 * shell.php + TPD_Notifications + dashboard.js pour le toggle du panneau.
 * .tpd-bell-wrap est positionné (relative) pour que .tpd-bell-panel
 * s'ancre dessous en absolute ; flex-shrink:0 pour ne jamais se faire
 * écraser par un nom d'activité long (voir .tpd-brand min-width:0 plus
 * haut).
 */
.tpd-bell-wrap { position: relative; flex-shrink: 0; }
.tpd-bell-btn {
	position: relative;
	width: 32px;
	height: 32px;
	border-radius: 50%;
	border: none;
	background: rgba(255,255,255,0.08);
	color: #fff;
	font-size: 15px;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	transition: background 0.15s ease; /* item #332 (18e vague) */
}
.tpd-bell-btn:hover { background: rgba(255,255,255,0.16); }
.tpd-bell-badge {
	position: absolute;
	top: -3px;
	right: -3px;
	background: var(--tpd-danger);
	color: #fff;
	border-radius: 20px;
	min-width: 16px;
	height: 16px;
	padding: 0 4px;
	font-size: 10px;
	font-weight: 700;
	line-height: 16px;
	text-align: center;
}
/**
 * item #317 (16e vague, retour Chloé) — "la cloche [...] n'affiche pas
 * l'ensemble du panneau [...] c'est coupé je vois pas tout" (photo 2) :
 * .tpd-bell-panel était en position:absolute, ancré via .tpd-bell-wrap
 * (position:relative). Le vrai problème n'était pas sa largeur/position en
 * elles-mêmes, mais que .tpd-sidebar (son ancêtre) a overflow:hidden (voir
 * plus haut, "seul .tpd-nav défile") — hidden coupe TOUT descendant qui
 * déborde de sa boîte, y compris un absolute qui s'étend hors de la
 * sidebar, ce qui tronquait le panneau dès qu'il dépassait la largeur ou la
 * hauteur de la sidebar (systématique sur mobile, la sidebar étant étroite).
 * Passé en position:fixed — non affecté par l'overflow:hidden d'un ancêtre
 * (sidebar n'a ni transform ni filter, donc ne crée pas de "containing
 * block" pour fixed) — et positionné dynamiquement par dashboard.js
 * (top/left calculés depuis la position réelle du bouton cloche, resserrés
 * pour ne jamais sortir de l'écran) plutôt qu'en CSS pur, puisque fixed ne
 * peut plus s'ancrer à .tpd-bell-wrap via top:100%.
 */
/**
 * 61e vague, retour Chloé — "Dans les notifications retire le ? je ne sais
 * pas à quoi ça correspond" : capture d'écran montrant la bulle d'aide "?"
 * de la Statistiques sous-jacente (TPD_Stats::help_icon(), voir son
 * docblock) visible AU-DESSUS du panneau de notifications ouvert par
 * dessus. Le panneau est en position:fixed avec z-index:500 — déjà plus
 * élevé que le z-index:20 de ces bulles d'aide — mais un ancêtre quelque
 * part dans la page crée visiblement son propre contexte d'empilement qui
 * déjoue cette comparaison simple. Plutôt que de retracer toute la chaîne
 * (fragile, déjà documentée comme source de bugs similaires au 30e vague),
 * z-index du panneau et du petit menu "⋮" par notification remontés à un
 * palier nettement supérieur à tout le reste de l'interface (même ordre de
 * grandeur que .tpd-modal-overlay, z-index:1000 plus bas) — garantit que
 * plus rien ne peut jamais s'afficher par-dessus, quelle que soit la cause
 * exacte du contexte d'empilement en cause.
 */
.tpd-bell-panel {
	position: fixed;
	width: 320px;
	max-width: calc(100vw - 24px);
	max-height: 70vh;
	overflow-y: auto;
	background: #fff;
	color: var(--tpd-ink);
	border-radius: 12px;
	box-shadow: 0 12px 32px rgba(0,0,0,0.25);
	z-index: 1600;
	padding: 8px;
}
.tpd-bell-panel-header { font-weight: 600; font-size: 14px; padding: 8px 10px 10px; }
.tpd-bell-empty { padding: 6px 10px 12px; font-size: 13px; color: #888; margin: 0; }
.tpd-bell-item {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 10px;
	border-radius: 8px;
	text-decoration: none;
	color: var(--tpd-ink);
}
a.tpd-bell-item:hover { background: var(--tpd-paper, #FBF9F6); }
.tpd-bell-item-label { font-size: 13.5px; font-weight: 500; }
.tpd-bell-item-body { font-size: 12.5px; color: #777; }
.tpd-bell-item-tag {
	align-self: flex-start;
	background: var(--tpd-accent);
	color: #fff;
	font-size: 10px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	border-radius: 20px;
	padding: 2px 8px;
	margin-bottom: 2px;
}
.tpd-bell-dismiss {
	display: block;
	text-align: center;
	font-size: 12.5px;
	color: var(--tpd-accent);
	text-decoration: underline;
	padding: 10px;
	margin-top: 4px;
	border-top: 1px solid #eee;
}
/**
 * item #7/#8 (22e vague, retour Chloé) — refonte façon monespacesante.fr :
 * point coloré = non lu, menu "⋮" (Supprimer/Marquer comme non lu) — voir
 * TPD_Notification_Log et le rendu dans shell.php.
 */
.tpd-bell-item-event { flex-direction: row; align-items: flex-start; gap: 8px; padding: 8px 6px 8px 10px; }
.tpd-bell-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--tpd-accent); flex-shrink: 0; margin-top: 6px; }
.tpd-bell-dot.is-read { background: transparent; }
.tpd-bell-item-content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; text-decoration: none; color: var(--tpd-ink); padding: 2px 4px; border-radius: 6px; }
.tpd-bell-item-content:hover { background: var(--tpd-paper, #FBF9F6); }
.tpd-bell-item-time { font-size: 11px; color: #999; }
.tpd-bell-menu-wrap { position: relative; flex-shrink: 0; }
.tpd-bell-menu-toggle { background: none; border: none; cursor: pointer; color: #999; font-size: 16px; line-height: 1; padding: 4px 6px; border-radius: 6px; }
.tpd-bell-menu-toggle:hover { color: var(--tpd-ink); background: var(--tpd-paper, #FBF9F6); }
/* 61e vague — même correctif que .tpd-bell-panel juste au-dessus (voir son docblock) : le menu "⋮" d'une notification vit À L'INTÉRIEUR du panneau, donc doit rester au-dessus de tout lui aussi. */
.tpd-bell-menu { position: absolute; right: 0; top: 100%; background: #fff; border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.18); min-width: 180px; z-index: 1601; padding: 4px; }
.tpd-bell-menu[hidden] { display: none; }
.tpd-bell-menu a { display: block; padding: 8px 10px; font-size: 12.5px; color: var(--tpd-ink); text-decoration: none; border-radius: 6px; white-space: nowrap; }
.tpd-bell-menu a:hover { background: var(--tpd-paper, #FBF9F6); }
.tpd-bell-menu a.tpd-bell-menu-danger { color: #9A3B3B; }
/* Même pastille que .tpd-nav-badge, juste une couleur différente (accent au
   lieu de danger/rouge) pour qu'une alerte "Nouveau" (annonce produit, pas
   grave) ne se confonde jamais visuellement avec un vrai compteur "à
   traiter" (message non lu, ticket en attente). */
.tpd-nav-badge-new { background: var(--tpd-accent); }

.tpd-sidebar-footer { display: flex; flex-direction: column; gap: 10px; padding-top: 16px; border-top: 1px solid rgba(255,255,255,0.15); flex-shrink: 0; }
.tpd-logout { color: rgba(255,255,255,0.6); font-size: 13px; text-decoration: none; }
.tpd-logout:hover { color: #fff; }

/* item #116 — Chloé : "le bouton + ajouter une option doit être beige" —
   c'était un contour en pointillés transparent, maintenant rempli de la
   couleur beige/accent de la marque (var(--tpd-accent)) au repos, pas
   seulement au survol. */
.tpd-add-option-cta {
	display: flex; align-items: center; justify-content: center; gap: 4px;
	border: 1px solid var(--tpd-accent);
	border-radius: 8px;
	padding: 9px 14px;
	background: var(--tpd-accent);
	color: var(--tpd-ink);
	font-size: 13px;
	font-weight: 600;
	text-decoration: none;
}
/* item #133 — bug signalé par Chloé : ces couleurs de survol étaient une
   teinte fixe (#8D7A5C, un dérivé assombri de l'ancien --tpd-accent par
   défaut) au lieu de suivre --tpd-accent — donc dès qu'une prestataire
   personnalisait sa couleur de CTA (Réglages > Apparence), le survol du
   bouton "+ Ajouter une option" retombait toujours sur l'ancienne couleur
   d'origine au lieu de rester cohérent avec la sienne. filter: brightness()
   assombrit LA couleur réellement affichée (var(--tpd-accent), quelle
   qu'elle soit) au lieu de coder une teinte en dur. */
.tpd-add-option-cta:hover, .tpd-add-option-cta.is-active { filter: brightness(0.88); color: var(--tpd-ink); }

/* Main content */
/**
 * 30e vague, retour Chloé — "Statistiques : la page n'est pas responsive
 * car je vois que l'on peut swipe vers la droite" : confirmé en mesurant
 * document.documentElement.scrollWidth dans un navigateur headless — sur
 * mobile, cette page à elle seule dépassait la largeur de l'écran d'environ
 * 200px, alors que RIEN ne débordait visuellement. Coupable identifié :
 * .tpd-stats-help-tip (l'infobulle des bulles d'aide "?", très nombreuses
 * sur cet écran — 5 KPI + 6 titres de carte), qui reste `position:absolute;
 * width:max-content; max-width:240px` et centrée par `transform:
 * translateX(-50%)` MÊME quand elle est invisible (opacity:0;
 * visibility:hidden — jamais display:none) : dès que la bulle "?" est près
 * du bord droit d'un écran étroit, cette boîte invisible dépasse quand même
 * du viewport et agrandit la zone défilable de la page, d'où le swipe vers
 * une zone vide. overflow-x:hidden ici (jamais sur html/body, qui
 * casserait le position:sticky de .tpd-sidebar sur desktop — .tpd-main
 * n'a lui-même aucun contenu en sticky) neutralise ce débordement fantôme,
 * quelle que soit sa source, sans rien changer au rendu visible : tout ce
 * qui doit rester visible tient déjà dans la largeur de l'écran grâce aux
 * précédents audits responsive (28e/29e vagues).
 */
.tpd-main { flex: 1; padding: 40px 48px; max-width: 1100px; overflow-x: hidden; }
/* item #190 (5e lot, retour Chloé) — "agrandir les blocs graphiques
   Rendez-vous/Revenu dans le temps en largeur pour éviter que les dates
   soient trop collées" : les 2 graphiques temporels étaient déjà en pleine
   largeur de .tpd-main (item #172) mais .tpd-main lui-même plafonnait à
   1100px, ce qui reste étroit avec jusqu'à 5 repères de date + jusqu'à ~90
   points sur une plage personnalisée longue. On élargit SEULEMENT la page
   Statistiques (.tpd-stats-report présent) plutôt que .tpd-main partout,
   pour ne pas changer la largeur des autres écrans de Mon Espace. */
.tpd-main:has(.tpd-stats-report) { max-width: 1360px; }
/**
 * 30e vague, retour Chloé — "Calendrier : pour le format mois est-ce
 * possible d'agrandir le calendrier ?" Même technique que juste au-dessus
 * pour Statistiques (item #190) : on élargit .tpd-main UNIQUEMENT quand la
 * grille du mois (.tpd-month-grid) est présente, jamais les vues Semaine/
 * Jour (pas demandées ici) ni le reste de Mon Espace. Les cellules du mois
 * elles-mêmes sont aussi agrandies juste plus bas (.tpd-month-cell) pour
 * que ce surplus de largeur profite vraiment à la lisibilité des rendez-
 * vous du jour, pas seulement à des marges vides.
 */
.tpd-main:has(.tpd-month-grid) { max-width: 1440px; }

.tpd-page-header { margin-bottom: 28px; }
/* item 5 (28e vague, retour Chloé) — "les textes d'explications sont
   écrits avec une majuscule à chaque début de mot [...] écris toutes ces
   descriptions normalement" : le texte source (voir view-qr.php et les
   ~8 autres vues qui utilisent .tpd-page-subtitle) était déjà en casse de
   phrase normale — c'est "text-transform: capitalize" ci-dessous qui
   forçait visuellement une majuscule sur CHAQUE mot ("Générez Un QR Code
   Pour..."), sans qu'aucun texte source n'ait jamais été écrit ainsi.
   Retiré : la casse affichée est maintenant exactement celle du texte
   source, sur toutes les pages qui utilisent cette classe. */
.tpd-page-subtitle { color: var(--tpd-muted); margin: 4px 0 0; }
/* 37e vague, retour Chloé — page Formations : espace avant les onglets
   "Ajouter une formation"/"Inscriptions" qui suivent (voir
   view-trainings.php) ; classe dédiée pour rester scopé à cette page. */
.tpd-page-subtitle-spaced { margin-bottom: 16px; }

.tpd-notice {
	background: #E4F2E4;
	color: #2E6B2E;
	padding: 10px 16px;
	border-radius: 6px;
	font-size: 14px;
	margin-bottom: 20px;
	display: inline-block;
}
.tpd-notice-error { background: #F7E6E3; color: var(--tpd-danger); }
/* item #235 (9e vague, retour Chloé) — variante "avertissement" (ambre),
   distincte du succès (vert) et de l'erreur (rouge) : utilisée par
   view-travel-fee.php pour signaler une option activée mais mal configurée,
   pas une erreur de soumission. */
.tpd-notice-warning { background: #FBF0DD; color: #8A5A00; }

/* Stat cards */
.tpd-stat-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 16px;
	margin-bottom: 40px;
}
.tpd-stat-card {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 10px;
	padding: 20px;
	display: flex;
	flex-direction: column;
	gap: 4px;
	/* item #332 (18e vague) — légère ombre de repos (au lieu d'un simple
	   contour plat) pour donner un peu de profondeur aux chiffres-clés du
	   tableau de bord, cohérent avec .tpd-card ci-dessous. */
	box-shadow: var(--tpd-shadow);
	transition: box-shadow 0.15s ease;
}
.tpd-stat-card:hover { box-shadow: var(--tpd-shadow-hover); }
.tpd-stat-card.is-alert { border-color: var(--tpd-accent); }
.tpd-stat-value { font-family: 'Bodoni Moda', Georgia, serif; font-size: 30px; }
.tpd-stat-label { font-size: 13px; color: var(--tpd-muted); }

/* Sections */
.tpd-section { margin-bottom: 40px; }
.tpd-section-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 16px; }
.tpd-link { color: var(--tpd-accent); text-decoration: none; font-size: 14px; }
.tpd-empty-note { color: var(--tpd-muted); font-size: 14px; }
/* item #213 (7e vague) — petit texte d'aide sous un champ de formulaire,
   ex. "De"/"À" de Suppléments (voir templates/view-surcharges.php). */
.tpd-field-hint { color: var(--tpd-muted); font-size: 12.5px; margin: -6px 0 12px; line-height: 1.4; }

/* Appointment rows (dashboard) */
.tpd-appt-list, .tpd-appt-table { display: flex; flex-direction: column; gap: 8px; }
.tpd-appt-row, .tpd-appt-table-row {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	padding: 14px 18px;
	display: flex;
	align-items: center;
	gap: 16px;
	/* item #332 (18e vague) — même traitement "carte" léger que .tpd-card/
	   .tpd-stat-card, pour que les listes (rendez-vous, clients fidèles)
	   ne détonnent pas visuellement à côté du reste du dashboard. */
	box-shadow: var(--tpd-shadow);
	transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.tpd-appt-row:hover, .tpd-appt-table-row:hover { border-color: var(--tpd-accent); box-shadow: var(--tpd-shadow-hover); }
.tpd-appt-time { font-weight: 600; width: 50px; flex-shrink: 0; }
/**
 * item #312 (15e vague, retour Chloé) — "fidélité (les textes se
 * chevauchent)" : .tpd-appt-row sert aussi aux lignes "Meilleurs clients
 * fidèles" (nom du client + badge "N visites" + bouton "Récompense
 * utilisée"), et repasse déjà correctement à la ligne sur mobile (item
 * #294). Mais .tpd-appt-main — contrairement à son équivalent
 * .tpd-service-main (Prestations, "min-width: 0" déjà en place) — n'avait
 * pas cette protection : un nom client un peu long forçait sa propre
 * largeur de contenu minimale plutôt que de pouvoir rétrécir/passer à la
 * ligne comme prévu, repoussant le badge/bouton hors de la carte fidélité
 * sur un écran étroit. Alignée sur .tpd-service-main pour la même raison.
 */
.tpd-appt-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tpd-appt-meta { font-size: 13px; color: var(--tpd-muted); }

.tpd-appt-table-date { display: flex; flex-direction: column; align-items: center; width: 54px; flex-shrink: 0; }
.tpd-appt-table-day { font-size: 12px; color: var(--tpd-muted); }
.tpd-appt-table-hour { font-weight: 600; }
/**
 * 30e vague, retour Chloé — "le nom des prestations dans les blocs
 * doivent être sur la même ligne (sur mobile)" : sans min-width:0, ce
 * flex item (comme .tpd-appt-main avant sa propre correction, item #312,
 * 15e vague — voir plus haut) ne pouvait pas rétrécir sous sa largeur de
 * contenu minimale, et le nom de la prestation retombait sur 2-3 lignes
 * en poussant/écrasant les badges et boutons d'action voisins.
 *
 * 31e vague, retour Chloé — "le nom des prestations n'est plus totalement
 * visible dans les blocs, il est tronqué (sur mobile), il ne faut pas que
 * ce soit tronqué" : le traitement "un seul titre, tronqué avec ellipsis"
 * ci-dessus (repris de .tpd-service-main/strong, page Prestations) cachait
 * une partie du nom, ce qui n'était pas ce qu'elle voulait — retiré.
 * min-width:0 reste (nécessaire pour que le bloc puisse rétrécir sans
 * pousser ses voisins) mais le titre peut de nouveau s'enrouler sur
 * plusieurs lignes ; overflow-wrap:anywhere (même pattern que
 * .tpd-table-row .tpd-appt-meta plus haut) évite qu'un mot/nombre très
 * long à lui seul ne déborde horizontalement.
 */
.tpd-appt-table-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tpd-appt-table-main > strong { display: block; max-width: 100%; overflow-wrap: anywhere; }
.tpd-appt-actions { display: flex; gap: 6px; }
.tpd-appt-actions form { display: inline; }

/* v1.9.2 — Chloé: "…" row menu (Détails / Modifier / Effacer) on
   Rendez-vous. Small dependency-free dropdown — dashboard.js toggles
   `.is-open` on click and closes on outside click / Escape. */
.tpd-row-menu { position: relative; flex-shrink: 0; }
.tpd-row-menu-toggle {
	background: none;
	border: none;
	cursor: pointer;
	font-size: 20px;
	line-height: 1;
	color: var(--tpd-muted);
	padding: 4px 8px;
	border-radius: 6px;
	transition: background 0.15s ease, color 0.15s ease; /* item #332 (18e vague) */
}
.tpd-row-menu-toggle:hover { background: var(--tpd-sand); color: var(--tpd-ink); }
.tpd-row-menu-list {
	position: absolute;
	right: 0;
	top: calc(100% + 4px);
	z-index: 20;
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	box-shadow: 0 6px 20px rgba(0,0,0,0.12);
	min-width: 160px;
	padding: 6px;
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.tpd-row-menu:not(.is-open) .tpd-row-menu-list { display: none; }
.tpd-row-menu-list a,
.tpd-row-menu-list button {
	display: block;
	width: 100%;
	text-align: left;
	background: none;
	border: none;
	cursor: pointer;
	font: inherit;
	font-size: 13px;
	color: var(--tpd-ink);
	text-decoration: none;
	padding: 8px 10px;
	border-radius: 6px;
}
.tpd-row-menu-list a:hover,
.tpd-row-menu-list button:hover { background: var(--tpd-sand); }
.tpd-row-menu-list .tpd-row-menu-danger { color: var(--tpd-danger); }

/* item (87e vague, retour Chloé, capture à l'appui) — "centre le texte du
   badge acompte remboursé" : .tpd-badge (un <span>) restait display:inline
   par défaut — un simple text-align:center n'y aurait rien changé, un
   élément inline ne définit pas son propre contexte d'alignement pour ses
   lignes, qui suivent le text-align du bloc englobant (ici la cellule du
   tableau Rendez-vous, alignée à gauche). Passé en inline-block : invisible
   sur un badge qui tient sur une seule ligne (ex. "Confirmé"), mais centre
   enfin les deux lignes d'un libellé plus long qui passe à la ligne dans une
   colonne étroite (ex. "Acompte Remboursé", jusque-là aligné à gauche). */
.tpd-badge { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 12px; text-transform: capitalize; text-align: center; background: var(--tpd-sand); color: var(--tpd-muted); }
.tpd-badge-pending { background: #FDF0D5; color: #8A6D1D; }
.tpd-badge-confirmed { background: #E4F2E4; color: #2E6B2E; }
.tpd-badge-cancelled { background: #F6DEDE; color: #9A3B3B; }
.tpd-badge-completed { background: #E4E4E4; color: #444; }
/* v1.9.5 — Chloé (item #83) : "redimensionne la balise places" (Formations)
   — .tpd-badge donne déjà la bonne taille compacte, ces deux modificateurs
   n'ajoutent qu'un rappel visuel "complet". */
.tpd-badge-seats { text-transform: none; margin-left: 4px; }
.tpd-badge-seats-full { background: #F6DEDE; color: #9A3B3B; }

/* item #114 — badge "Principal" (Équipe). */
.tpd-badge-primary { text-transform: none; background: var(--tpd-accent); color: #fff; margin-left: 4px; }

/* Quick actions */
.tpd-quick-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.tpd-quick-action {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	padding: 14px 18px;
	text-decoration: none;
	color: var(--tpd-ink);
	font-size: 14px;
	box-shadow: var(--tpd-shadow); /* item #332 (18e vague) */
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.tpd-quick-action:hover { border-color: var(--tpd-accent); box-shadow: var(--tpd-shadow-hover); }

/* Filter bar */
.tpd-filter-bar { display: flex; gap: 12px; align-items: center; margin-bottom: 24px; flex-wrap: wrap; }
.tpd-filter-bar label { font-size: 13px; color: var(--tpd-muted); display: flex; align-items: center; gap: 6px; }
/* 30e vague, retour Chloé — "Du"/"Au" (Rendez-vous, Paiements) regroupés
   dans ce conteneur (voir les templates) : un seul item flex pour
   .tpd-filter-bar, qui passe donc à la ligne EN BLOC sur mobile plutôt que
   de laisser "Du" et "Au" se séparer chacun sur sa propre ligne — voir
   l'ajustement de largeur dans le @media (max-width: 900px) plus bas. */
.tpd-filter-date-range { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
/* Même habillage que les champs des cartes (.tpd-card input/select/textarea) —
   avant ce correctif, select n'était pas listé ici : les dropdowns des filtres
   (Rendez-vous, Calendrier, Paiements) gardaient l'apparence native du
   navigateur pendant que tous les autres champs avaient déjà le style carte. */
.tpd-filter-bar input,
.tpd-filter-bar select {
	border: 1px solid var(--tpd-line);
	border-radius: 6px;
	padding: 7px 10px;
	font: inherit;
	color: var(--tpd-ink);
	background: var(--tpd-paper);
}
.tpd-filter-bar select {
	appearance: none;
	-webkit-appearance: none;
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236F6A62' stroke-width='1.5' fill='none' fill-rule='evenodd'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 10px center;
	padding-right: 28px;
}

/* Two-column layout (services) */
.tpd-two-col { display: flex; gap: 28px; align-items: flex-start; }
/*
 * Bug report Chloé (54e vague) — "les blocs de formations sont mal
 * positionnés" sur Mon Espace > Formations (panneau "Modifier la
 * formation" à droite) : c'est la même famille de bug déjà réparée
 * ailleurs dans ce fichier (item #165, ".tpd-field-row label",
 * ".tpd-phone-field input"...) mais jamais appliquée ICI, au niveau
 * racine de ".tpd-two-col" — ".tpd-col-main" (flex:2) n'avait pas de
 * "min-width: 0". Sans ça, un enfant flex garde pour minimum sa largeur
 * de CONTENU (min-content) au lieu de 0 : dès que la liste de gauche
 * contient une ligne assez chargée (ex. formation avec plusieurs badges
 * "0/5 places" + "Paiement en 4x (PayPal)" + "CPF" + "Qualiopi" sur une
 * seule ligne, .tpd-appt-meta étant en white-space:nowrap), ce
 * min-content dépasse la part que ".tpd-col-main" devrait normalement
 * occuper — ".tpd-col-main" refuse alors de rétrécir, et pousse
 * ".tpd-col-side" (le panneau de droite, lui borné à 300px min) hors du
 * cadre visible de ".tpd-main" (qui a overflow-x:hidden, voir plus haut)
 * : le panneau "Modifier la formation" se retrouve coupé au milieu de
 * son contenu, exactement le symptôme décrit. Le nouveau badge "Paiement
 * en 4x (PayPal)" ajouté au 53e vague (plus long que l'ancien texte
 * Alma) a fait déborder ce seuil, ce qui explique pourquoi ce bug est
 * apparu maintenant. "min-width: 0" ici (reproduit et vérifié avec un
 * rendu réel de la page à plusieurs largeurs d'écran) laisse
 * ".tpd-col-main" rétrécir normalement — sa propre liste sait déjà gérer
 * l'espace restreint via l'ellipsis (.tpd-service-main/.tpd-appt-meta,
 * plus haut) — et ".tpd-col-side" retrouve enfin sa juste part de
 * largeur au lieu d'être repoussé hors champ.
 */
.tpd-col-main { flex: 2; min-width: 0; }
.tpd-col-side { flex: 1; min-width: 300px; }

/* Nouvelle demande de Chloé : glisser-déposer scopé par catégorie — un
   sous-bloc par catégorie (+ "Sans catégorie"), voir view-services.php. */
#tpd-service-order-wrapper { display: flex; flex-direction: column; gap: 22px; }
.tpd-service-category-heading { margin: 0 0 8px; font-size: 14px; font-weight: 600; color: var(--tpd-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.tpd-service-list { display: flex; flex-direction: column; gap: 8px; }
.tpd-service-row {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	padding: 14px 18px;
	display: flex;
	align-items: center;
	gap: 14px;
	text-decoration: none;
	color: var(--tpd-ink);
	min-width: 0;
	max-width: 100%;
	box-sizing: border-box;
	/* item #332 (18e vague) — transition douce ; le survol lui-même
	   (border-color) existait déjà juste en dessous. */
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.tpd-service-row:hover { border-color: var(--tpd-accent); box-shadow: var(--tpd-shadow-hover); }
.tpd-service-color { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.tpd-service-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.tpd-service-main strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.tpd-service-main .tpd-appt-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }
.tpd-service-price { font-weight: 600; flex-shrink: 0; white-space: nowrap; }

/* Prestations: drag handle wrapper, categories, radio groups, color palette */
.tpd-service-row-wrap { display: flex; align-items: center; gap: 6px; }
.tpd-service-row-wrap .tpd-service-row { flex: 1; }
.tpd-service-row-wrap.is-dragging { opacity: 0.4; }
.tpd-service-row-wrap .tpd-order-handle { cursor: grab; color: var(--tpd-muted); flex-shrink: 0; }
.tpd-service-row-wrap > form { flex-shrink: 0; }

.tpd-category-list { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.tpd-category-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--tpd-sand); border-radius: 20px; padding: 6px 12px; font-size: 13px; }
.tpd-category-chip.is-dragging { opacity: 0.4; }
.tpd-category-chip .tpd-order-handle { cursor: grab; }
.tpd-category-chip form { display: inline; }
/* v1.9.2 — Chloé: catégorie-filter chips on Clients (tpd_cat). Same chip
   look, but as clickable filter links rather than a static tag list. */
.tpd-category-chip-link { color: var(--tpd-ink); text-decoration: none; cursor: pointer; border: 1px solid transparent; }
.tpd-category-chip-link:hover { border-color: var(--tpd-accent); }
.tpd-category-chip-link.is-active { background: var(--tpd-accent); color: #fff; }
.tpd-chip-remove { background: none; border: none; cursor: pointer; color: var(--tpd-muted); font-size: 14px; line-height: 1; padding: 0; }
/* v1.9.1 — Chloé: the "+ Ajouter" category button could end up squeezed
   almost out of view next to its text input on a narrow screen (same
   overflow trap as `.tpd-field-row` in the booking widget: the input had
   no minimum width of its own, so it happily shrank to make room, but
   only up to a point before the row simply ran wider than its card and
   pushed the button toward — or past — the edge). `flex-wrap` plus a
   sane input floor let the button drop to its own line instead. */
/* v1.9.2 — Chloé: "la balise nouvelle catégorie est trop grande". Root
   cause: `.tpd-card form { flex-direction: column }` (further down this
   file) is MORE specific than plain `.tpd-inline-form` (class+element vs.
   just a class) and this form always lives inside a `.tpd-card`, so it
   always won — flipping the form to a column flex container. With the
   main axis now vertical, the input's `flex: 1 1 160px` applied its
   160px flex-basis to HEIGHT instead of width, rendering a 160px-tall
   box instead of a normal text field. `.tpd-card .tpd-inline-form` below
   is specific enough to actually beat `.tpd-card form` and keep this one
   form row-direction regardless of where it's nested. */
.tpd-inline-form,
.tpd-card .tpd-inline-form { display: flex; flex-direction: row; flex-wrap: wrap; gap: 8px; }
.tpd-inline-form input { flex: 1 1 160px; min-width: 160px; height: auto; border: 1px solid var(--tpd-line); border-radius: 6px; padding: 8px 10px; font: inherit; }

.tpd-radio-label { font-size: 13px; color: var(--tpd-muted); display: block; margin: 4px 0 6px; }
.tpd-radio-group { display: flex; gap: 16px; margin-bottom: 4px; }
.tpd-radio-option { display: flex; align-items: center; gap: 6px; font-size: 14px; }

.tpd-color-palette { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.tpd-color-swatch { position: relative; width: 30px; height: 30px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; display: block; }
.tpd-color-swatch input[type="radio"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.tpd-color-swatch.is-selected { outline: 2px solid var(--tpd-ink); outline-offset: 2px; }
.tpd-color-swatch-custom { background: conic-gradient(red, yellow, lime, cyan, blue, magenta, red); display: flex; align-items: center; justify-content: center; }
.tpd-color-swatch-custom input[type="color"] { width: 20px; height: 20px; border: 2px solid #fff; border-radius: 50%; padding: 0; cursor: pointer; position: static; opacity: 1; }

.tpd-card {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: var(--tpd-radius);
	padding: 26px;
	/* item #332 (18e vague) — ombre légère de repos, cohérente avec
	   .tpd-stat-card/.tpd-appt-row ci-dessus — pas de survol ici : une
	   ".tpd-card" n'est pas elle-même cliquable (seul son contenu l'est). */
	box-shadow: var(--tpd-shadow);
}
.tpd-card h3 { font-size: 17px; margin-bottom: 16px; }

/*
 * item #12 (22e vague, retour Chloé) — "chevron pour replier/déplier les
 * réglages" (Programme fidélité, voir view-loyalty.php). <details>/<summary>
 * natif : le triangle natif du navigateur est masqué (list-style:none +
 * ::-webkit-details-marker) au profit d'un chevron dessiné en CSS
 * (::after, rotation 90° quand [open]), même principe que .tzb-espace-details
 * côté espace client (item #308) mais avec un chevron plutôt qu'un "▸"/"▾"
 * texte, plus cohérent avec le reste de l'iconographie de Mon Espace.
 */
.tpd-collapse { cursor: default; }
.tpd-collapse-summary { cursor: pointer; list-style: none; display: flex; align-items: center; justify-content: space-between; margin-bottom: 0; }
.tpd-collapse-summary::-webkit-details-marker { display: none; }
.tpd-collapse-summary::after {
	content: '';
	width: 9px;
	height: 9px;
	border-right: 2px solid var(--tpd-muted);
	border-bottom: 2px solid var(--tpd-muted);
	transform: rotate(45deg);
	transition: transform .15s ease;
	flex-shrink: 0;
	margin-left: 12px;
}
.tpd-collapse[open] .tpd-collapse-summary { margin-bottom: 16px; }
.tpd-collapse[open] .tpd-collapse-summary::after { transform: rotate(-135deg); }
.tpd-collapse-summary h3 { margin-bottom: 0 !important; }
.tpd-collapse-body { display: flex; flex-direction: column; gap: 12px; }
.tpd-card form { display: flex; flex-direction: column; gap: 12px; }
/**
 * 48e vague, retour Chloé — "rends le bloc de paramètres design et lisible
 * côté prestataires" : regroupe visuellement les longs formulaires (ex.
 * Mon Espace > Formations) en sections nommées plutôt qu'une pile plate de
 * champs — chaque section garde le même style de champ que ".tpd-card"
 * ci-dessus, seul un séparateur + un petit titre les distinguent.
 */
.tpd-form-section { display: flex; flex-direction: column; gap: 12px; padding-top: 20px; border-top: 1px solid var(--tpd-line); }
.tpd-form-section:first-child { padding-top: 0; border-top: none; }
.tpd-form-section-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--tpd-accent); margin: 0; }
.tpd-card label { font-size: 13px; color: var(--tpd-muted); display: flex; flex-direction: column; gap: 4px; }
.tpd-card input, .tpd-card select, .tpd-card textarea {
	border: 1px solid var(--tpd-line);
	border-radius: 6px;
	padding: 9px 12px;
	font: inherit;
	color: var(--tpd-ink);
	background: var(--tpd-paper);
	/* item #332 (18e vague) — un focus visible (anneau ton sur ton avec
	   --tpd-accent) au lieu du simple contour bleu par défaut du
	   navigateur, comme déjà fait côté espace client (item #326). */
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
	/* 68e vague, retour Chloé — "la balise [mot de passe] n'est pas de la
	   même taille que la balise identifiant ou e-mail" : Safari (desktop ET
	   iOS) applique par défaut un habillage natif différent aux champs
	   input[type=password] qu'aux autres champs texte (léger changement de
	   gabarit/hauteur), invisible sur Chrome — d'où le décalage constaté
	   uniquement par Chloé (utilisatrice iPhone). -webkit-appearance:none
	   neutralise cet habillage natif pour que TOUS les champs de ce bloc
	   (identifiant, e-mail, mot de passe) suivent exactement les mêmes
	   règles ci-dessus, sans exception de navigateur. */
	-webkit-appearance: none;
	appearance: none;
}
.tpd-card input:focus, .tpd-card select:focus, .tpd-card textarea:focus {
	outline: none;
	border-color: var(--tpd-accent);
	box-shadow: 0 0 0 3px rgba(160,141,107,0.18);
}
.tpd-card select {
	appearance: none;
	-webkit-appearance: none;
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%236F6A62' stroke-width='1.5' fill='none' fill-rule='evenodd'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 12px center;
	padding-right: 30px;
}
/* item #128 — Chloé: "la couleur doit être visible" — .tpd-card input's
   9px/12px padding + var(--tpd-paper) background above (needed for text/
   number/etc. fields) leaves an <input type="color"> almost no room to
   paint its own native swatch, and paints over what little shows through
   with the card's paper background — every plain color picker in the
   dashboard (Mes couleurs, Personnaliser un bloc, Fidélité, prestation
   sur mesure) looked like a blank box instead of a color swatch. Zero
   padding + no forced background restores the browser's native swatch;
   a fixed size keeps it from collapsing to almost nothing while still
   lining up with the other fields in a .tpd-field-row. */
.tpd-card input[type="color"] {
	padding: 0;
	background: none;
	width: 46px;
	height: 38px;
	cursor: pointer;
}
/**
 * 76e vague, retour Chloé — "quand les prestations sont sélectionnées il
 * ne voit pas que c'est coché [...] c'est pareil dans l'ajout et
 * modification de prestation pour la tarification et la sélection de
 * thème" (3 captures : case "Les plus populaires" de Bloc Prestations,
 * "Prix fixe"/"Sur devis" de Tarification, cartes Thème). Les trois sont
 * de simples <input type="checkbox">/<input type="radio"> natifs,
 * descendants d'un .tpd-card — ils héritaient donc malgré eux de la règle
 * ".tpd-card input { [...] appearance:none; -webkit-appearance:none; }"
 * juste au-dessus (ajoutée au 68e lot pour une tout autre raison : la
 * hauteur du champ mot de passe sur Safari, voir son docblock). Sur une
 * case à cocher/un bouton radio, appearance:none supprime le rendu natif
 * (coche/point) SANS qu'aucune règle ne le redessine ensuite — contrairement
 * aux champs texte/mot de passe, où seul l'habillage (bordure/fond) change.
 * Résultat : une case dont l'état change bel et bien (voir .is-selected sur
 * .tpd-theme-card, ou la valeur cochée réellement enregistrée pour les 2
 * autres) mais qui a l'air strictement identique cochée ou non — d'où le
 * "je ne vois pas que c'est coché" de Chloé.
 *
 * Correctif volontairement CIBLÉ sur ces 3 contrôles précis (sélecteurs
 * dédiés .tpd-featured-service-checkbox / .tpd-pricing-mode / .tpd-theme-card
 * input) plutôt qu'un ".tpd-card input[type=checkbox]/[type=radio]" général :
 * .tpd-card héberge aussi .tpd-toggle-switch (interrupteurs), .tpd-color-swatch
 * et .tpd-header-layout-option, qui masquent eux aussi leur <input> natif
 * (appearance:none + opacity:0 + position:absolute) mais dessinent LEUR
 * PROPRE indicateur personnalisé à côté — une règle générale par attribut de
 * type aurait une spécificité plus forte que ces ".classe input" existants
 * et aurait cassé ces interrupteurs/pastilles en leur rendant leur case
 * native visible par-dessus l'indicateur personnalisé. Même principe que le
 * correctif input[type="color"] juste au-dessus (sortir un type précis de la
 * règle générale), mais par sélecteur dédié pour ne toucher QUE les 3
 * contrôles concernés.
 *
 * Correctif (suite), retour Chloé — "je veux des checkboxes des vrai cases
 * à cocher pour ces deux parties" (captures : toujours cassé sur "Les plus
 * populaires" et Tarification, mais plus sur Thème). Cause : erreur de
 * spécificité CSS ci-dessous à la première passe — ".tpd-featured-service-checkbox"
 * et ".tpd-pricing-mode" seules (une classe = spécificité 0,1,0) sont en
 * réalité MOINS spécifiques que ".tpd-card input" (classe+élément = 0,1,1,
 * voir plus haut), qui continuait donc à l'emporter et à leur appliquer
 * appearance:none malgré cette règle. Seul ".tpd-theme-card input[type=radio]"
 * (0,2,1, plus spécifique) avait réellement pris effet — d'où la correction
 * partielle. Les deux sélecteurs corrigés ci-dessous en les faisant pointer
 * sur l'élément <input> lui-même (input.classe = classe+élément = 0,1,1
 * *descendant de* .tpd-card répété = 0,2,1) pour l'emporter sans ambiguïté,
 * quel que soit l'ordre des règles dans ce fichier. accent-color ajouté en
 * plus : une case/un bouton radio natif sans lui reste correct mais minuscule
 * et gris très discret sur la plupart des navigateurs — accent-color les
 * dessine dans la couleur de la marque (--tpd-accent) une fois cochés, pour
 * un rendu qui se voit clairement comme "une vraie case à cocher".
 */
/**
 * 77e vague, retour Chloé — "j'ai le même soucis avec cette partie dans
 * formations repère si d'autres pages sont concernées" (capture : "Ces
 * frais sont..." de Formations > Frais supplémentaires). Passage en revue
 * de TOUTES les cases à cocher/boutons radio natifs du dashboard (tous les
 * fichiers templates/view-*.php) pour ne plus avoir à corriger ça page par
 * page à chaque signalement :
 * - Déjà protégés, PAS concernés : tous les .tpd-toggle-row/.tpd-toggle-switch
 *   (interrupteurs à bascule), .tpd-day-checkbox (sélecteurs de jours/équipe
 *   en "pastilles" — jours de la semaine, équipe assignée à une prestation/
 *   formation), .tpd-color-swatch, .tpd-palette-swatch-input et
 *   .tpd-star-rating — ces 6 composants cachent déjà eux-mêmes leur <input>
 *   natif (opacity:0/position:absolute) et dessinent LEUR PROPRE indicateur
 *   (fond, pastille, étoile...) : aucun rapport avec le bug ci-dessus.
 * - RÉELLEMENT concernés (mêmes symptômes, même cause que .tpd-pricing-mode/
 *   .tpd-featured-service-checkbox/.tpd-theme-card ci-dessus) et corrigés
 *   ici : "Ces frais sont..." (Formations, signalé par Chloé — nouvelle
 *   classe .tpd-visible-radio, voir view-trainings.php), "Seul(e)"/"À
 *   plusieurs" (Prestations > réservation groupée — .tpd-booking-mode,
 *   oublié lors du premier correctif alors qu'il partage EXACTEMENT le même
 *   balisage .tpd-radio-option que .tpd-pricing-mode juste à côté dans le
 *   même formulaire), "Emplacement de la photo" (Mon site > À propos —
 *   nouvelle classe .tpd-visible-radio, voir view-minisite.php) et "Retirer
 *   la photo" (Fidélité — nouvelle classe .tpd-visible-checkbox, voir
 *   view-loyalty.php).
 */
.tpd-card input.tpd-featured-service-checkbox,
.tpd-card input.tpd-pricing-mode,
.tpd-card input.tpd-booking-mode,
.tpd-card input.tpd-visible-radio,
.tpd-card input.tpd-visible-checkbox,
.tpd-theme-card input[type="radio"] {
	appearance: auto;
	-webkit-appearance: auto;
	-moz-appearance: auto;
	border: none;
	padding: 0;
	background: none;
	border-radius: 0;
	width: 18px;
	height: 18px;
	accent-color: var(--tpd-accent);
	cursor: pointer;
	flex-shrink: 0;
}
.tpd-card textarea { min-height: 60px; resize: vertical; }
.tpd-field-row { display: flex; gap: 12px; }
/* item #165 (retour Chloé) — "les balises fin date et heures et places [...]
   sortent du bloc" : le fix #124/#127 ci-dessous (flex-wrap sur
   .tpd-field-row-inline) supposait que le navigateur descend le min-content
   de ce flex-wrap imbriqué jusqu'au label parent — un comportement de
   dimensionnement de flexbox imbriqué qui varie trop d'un navigateur à
   l'autre pour qu'on puisse compter dessus. "min-width: 0" ici force le
   label (et donc tout ce qu'il contient) à accepter de rétrécir sous la
   largeur de la carte plutôt que de déborder — le fix standard et fiable
   pour un enfant flex trop large ; le flex-wrap imbriqué ne sert plus alors
   qu'à décider OÙ l'heure repasse sous la date. */
.tpd-field-row label { flex: 1; min-width: 0; }
/* item #124/#127 — date + heure côte à côte À L'INTÉRIEUR d'une étiquette
   (Formations > Début/Fin), pas empilées comme le reste d'un ".tpd-card
   label" (flex column). Un <input type="date"/"time"> natif refuse de
   rétrécir sous ~110-130px selon le navigateur (le contenu interne —
   segments jour/mois/année, icône — a un plancher que "min-width: 0" ne
   peut pas forcer) : dans la colonne étroite ".tpd-col-side"
   (min-width: 300px, moins le padding de la carte), les deux forcés côte
   à côte pouvaient dépasser le cadre de la carte (item #127 : "des
   balises sortent du cadre"). flex-wrap laisse l'heure repasser sous la
   date dès que la place manque, plutôt que de déborder — cette classe
   reste volontairement séparée de ".tpd-field-row" : elle ne repasse
   jamais en COLONNE via la media query plus bas (Début/Fin, eux, en ont
   besoin), elle s'adapte seule via ce wrap. */
.tpd-field-row-inline { display: flex; flex-wrap: wrap; gap: 8px; }
.tpd-field-row-inline input { flex: 1 1 110px; min-width: 0; }
.tpd-form-note { font-size: 12px; color: var(--tpd-muted); margin-top: 14px; }
.tpd-form-note a { color: var(--tpd-accent); }

/**
 * item #313 (15e vague, retour Chloé) — "Bloc ajout/modification de
 * prestations [...] mets les titres en gras (nom, catégorie, description…)".
 * Scopé à ".tpd-service-form" (nouvelle classe posée sur le <form> du
 * bloc ajout/modification de view-services.php) plutôt qu'à ".tpd-card
 * label" directement : cette dernière est partagée par TOUS les
 * formulaires du dashboard (Fidélité, Suppléments, Codes promo, Équipe,
 * Formations…), que Chloé n'a pas demandé à changer — un ".tpd-card
 * label { font-weight }" global aurait alourdi visuellement des pages non
 * concernées par ce retour.
 */
.tpd-service-form label,
.tpd-service-form .tpd-radio-label { font-weight: 700; }
/* item #313 — la plupart des champs vivent DANS leur <label> (voir
   ".tpd-card input/select/textarea { font: inherit }" plus haut, qui
   inclut donc aussi font-weight) : sans ce correctif, le gras du libellé
   ci-dessus se répercutait aussi sur le texte SAISI dans le champ
   (valeur, option choisie…), ce qui n'a jamais été demandé — seuls les
   titres doivent passer en gras, pas leur contenu. */
.tpd-service-form input,
.tpd-service-form select,
.tpd-service-form textarea { font-weight: 400; }
/**
 * item #313 — pendant du fix ci-dessus : les 3 textes d'aide en
 * `<span class="description">` de ce même formulaire (Note importante,
 * Consigne cliente, Déplacement à domicile) n'avaient jamais eu de règle
 * CSS du tout — contrairement à `.tpd-form-note`, utilisé partout
 * ailleurs pour ce même rôle de texte d'aide. Ils s'affichaient donc en
 * texte "normal" pleine taille/couleur, aussi visibles que les champs
 * eux-mêmes : tout sauf "impeccable" une fois les libellés mis en gras
 * ci-dessus, l'écart de hiérarchie devenant encore plus visible. Même
 * habillage que .tpd-form-note pour une hiérarchie cohérente.
 */
.tpd-service-form .description { display: block; font-size: 12px; font-weight: 400; color: var(--tpd-muted); margin-top: 4px; }

/* item #102 — "Mes couleurs" advanced fields (CTA/titre): a "Personnaliser"
   checkbox next to the color swatch, same label stack as the plain color
   fields above (.tpd-card label already gives the column layout/gap).
   32e vague, retour Chloé — "Palette personnalisée : revois l'affichage des
   réglages des options proposées car tout se chevauche" : ce bloc restait un
   ".tpd-field-row" tout court (display:flex SANS wrap, chaque <label> à
   flex:1 — voir plus haut) — pensé à l'origine pour 3 champs (item #102, qui
   se répartissaient bien la largeur d'une ligne). Passé à 16 champs au fil
   des vagues suivantes (item #421, 31e vague) sans jamais revoir cette
   règle, chaque étiquette était écrasée à ~1/16e de la largeur de la carte,
   d'où le chevauchement. Règle dédiée ici (grille responsive plutôt qu'une
   ligne unique) SANS toucher ".tpd-field-row" lui-même, réutilisé tel quel
   ailleurs sur des lignes à 2-3 champs qui doivent garder leur comportement
   actuel. */
.tpd-advanced-colors-note { margin-top: 18px; }
.tpd-advanced-colors-row {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( 170px, 1fr ) );
	gap: 16px 14px;
}
.tpd-advanced-colors-row.tpd-field-row .tpd-color-toggle-label {
	flex: initial; /* neutralise le flex:1 de ".tpd-field-row label" : la grille ci-dessus gère déjà la largeur de chaque case. */
	display: flex;
	flex-direction: column;
	gap: 6px;
}
.tpd-color-toggle-head { display: flex; align-items: center; gap: 6px; }
.tpd-color-toggle-head input[type="checkbox"] { margin: 0; }
/* Toutes les cases "Mes couleurs" avancées partagent .tpd-color-toggle-label
   — cible générique par input[type=color] plutôt qu'une classe par champ
   (.tpd-color-cta_bg, .tpd-color-cta_text...) : les 13 champs ajoutés au
   31e vague (item #421) n'avaient jamais reçu cette même mise en opacité
   quand désactivés, contrairement aux 3 champs d'origine. */
.tpd-color-toggle-label input[type="color"] { opacity: 1; transition: opacity 0.15s ease; }
.tpd-color-toggle-label input[type="color"]:disabled { opacity: 0.35; cursor: not-allowed; }
/* 36e vague, retour Chloé — item 4 : titres de groupe (En-tête, Photo héro,
   Les plus populaires...) au-dessus de chaque grille de couleurs avancées. */
.tpd-advanced-colors-group-title { margin: 20px 0 8px; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--tpd-muted); }
.tpd-advanced-colors-group-title:first-of-type { margin-top: 10px; }

/* item #107 — "Téléphone" fields: flag + dial-code <select> in front of the
   number, same pattern as Templiz Booking's own phone field. ".tpd-card
   input, .tpd-card select" above already styles both pieces individually —
   this just lays them out side by side and caps the select's width. */
.tpd-phone-field { display: flex; gap: 8px; }
/**
 * item #350 (84e vague, retour Chloé) — "Indicatif téléphone à moitié
 * visible, corrige cela" : à 96px max-width et SANS overflow/ellipsis, le
 * texte de l'indicatif choisi ("+225 Côte d'Ivoire" et consorts) se faisait
 * couper brutalement par le navigateur dès qu'il dépassait cette largeur —
 * exactement le même bug déjà réparé côté Templiz Booking (voir
 * .tzb-phone-field .tzb-phone-dial dans booking-widget.css, 61e/62e vague) :
 * même largeur (188px) et même filet de sécurité overflow/ellipsis repris
 * ici à l'identique.
 */
.tpd-phone-field .tpd-phone-dial { flex: 0 0 auto; width: auto; max-width: 188px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.tpd-phone-field input { flex: 1; min-width: 0; }

/* v1.9.2 — Chloé: "regarde la balise valeur" (Code promo, and the same
   Type/Valeur pair on Prestations > Acompte). A live %/€ suffix next to
   the "Valeur" field so it's never ambiguous which unit is expected —
   synced to the Type dropdown by dashboard.js (.tpd-value-type-select). */
.tpd-value-input-wrap { position: relative; display: block; }
.tpd-value-input-wrap input { width: 100%; padding-right: 30px; }
.tpd-value-suffix {
	position: absolute;
	right: 10px;
	top: 50%;
	transform: translateY(-50%);
	font-size: 13px;
	color: var(--tpd-muted);
	pointer-events: none;
}

/* item #112/#123 — Chloé: "la balise au pour les dates est trop proche du
   bloc" (Codes promo, "Valide du ... au ..."). The first attempt widened
   this label's own text-to-input gap to 12px — but ".tpd-field-row" lays
   "Valide du" and "au" out side by side with align-items stretch, so
   giving only ONE of the two labels a taller internal gap made their date
   inputs drift out of vertical alignment with each other (the exact
   misalignment item #123 flagged). Reverted to the shared 4px gap so both
   inputs line up again. The actual breathing room "au" needed only shows
   up once the row wraps to a single column on narrow screens (below) —
   there, a margin-top pushes the whole "au" label away from "Valide
   du"'s date box above it without touching the row's own alignment. */

/* Buttons */
.tpd-btn {
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	padding: 10px 20px;
	border-radius: 999px;
	border: 1px solid var(--tpd-ink);
	background: var(--tpd-ink);
	color: var(--tpd-paper);
	cursor: pointer;
	text-decoration: none;
	display: inline-block;
	/* item #332 (18e vague) — légère variation d'opacité au survol/à
	   l'activation, plutôt qu'un bouton totalement statique. */
	transition: opacity 0.15s ease, box-shadow 0.15s ease;
}
.tpd-btn:hover { opacity: 0.88; }
.tpd-btn:active { opacity: 1; }
.tpd-btn-ghost { background: transparent; color: var(--tpd-ink); border-color: var(--tpd-line); }
.tpd-btn-ghost:hover { opacity: 1; border-color: var(--tpd-accent); color: var(--tpd-accent); }
.tpd-btn-small { padding: 6px 12px; font-size: 13px; }
.tpd-btn-danger { border-color: var(--tpd-danger); background: transparent; color: var(--tpd-danger); }

/* item (104e vague, retour Chloé) — bouton + statut "Informations
   complémentaires" de chaque demande de devis reçue (voir view-quotes.php,
   onglet "Demandes reçues") : .tpd-quote-terms-status passe de rouge
   (--tpd-danger, à compléter) à vert (is-filled, posé par dashboard.js une
   fois la fenêtre contextuelle #tpd-quote-terms-modal validée) — pas de
   variable --tpd-success dans cette palette, #4F7A5C repris tel quel du
   vert déjà utilisé côté Templiz Devis (provider.css, --green) pour rester
   cohérent visuellement entre les deux plugins. */
.tpd-quote-terms-trigger { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 2px 0 4px; }
.tpd-quote-terms-status { font-size: 12px; font-weight: 600; color: var(--tpd-danger); }
.tpd-quote-terms-status.is-filled { color: #4F7A5C; }

/**
 * 129e vague, retour Chloé — "Date proposée"/"Heure proposée" du
 * formulaire de réponse à une demande de devis (view-quotes.php) : message
 * d'aide/d'erreur (dashboard.js, voir .tpd-quote-field-msg) + liste des
 * créneaux réellement disponibles pour le professionnel choisi, affichée
 * juste sous le champ heure (voir .tpd-quote-time-slots). Même famille
 * visuelle que .tpd-form-note (texte d'aide neutre) ci-dessus, --tpd-danger
 * uniquement quand le message signale un refus (date hors horizon ou
 * indisponible — dashboard.js n'ajoute alors la classe que dynamiquement
 * via le style inline couleur, pour ne pas dupliquer une variante de
 * classe par état).
 */
.tpd-quote-field-msg { display: block; font-size: 11.5px; color: var(--tpd-danger); margin-top: 3px; min-height: 14px; }
.tpd-quote-time-slots { display: block; width: 100%; margin-top: 4px; font-size: 13px; }
.tpd-quote-time-slots:empty { display: none; }
.tpd-btn-danger:hover { opacity: 1; background: var(--tpd-danger); color: #fff; }
.tpd-btn-primary { width: 100%; margin-top: 6px; }
.tpd-btn.is-disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }

.tpd-empty-state { padding: 60px; text-align: center; color: var(--tpd-muted); }

/* Messages (v1.9.0 — Chloé item #5: messagerie client ↔ prestataire) */
.tpd-thread-row { text-decoration: none; color: inherit; position: relative; }
.tpd-thread-row:hover { border-color: var(--tpd-accent); }
.tpd-thread-unread-badge {
	background: var(--tpd-danger);
	color: #fff;
	border-radius: 20px;
	padding: 1px 8px;
	font-size: 11px;
	font-weight: 600;
	margin-left: 8px;
}
.tpd-thread-preview { color: var(--tpd-muted); font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tpd-thread-time { font-size: 12px; color: var(--tpd-muted); flex-shrink: 0; }
/* v1.9.3 — Chloé (item #77) : icône trombone quand le dernier message d'une
   conversation a une pièce jointe. */
.tpd-thread-attachment-icon { margin-left: 4px; font-size: 12px; opacity: 0.8; }

.tpd-messages-thread { display: flex; flex-direction: column; gap: 10px; margin: 18px 0; max-height: 480px; overflow-y: auto; }
/* Nouvelle demande de Chloé : "la date est centrée elle doit être tout à
   droite" — voir le commentaire dans view-messages.php : la date vit
   maintenant HORS de la bulle, dans cette ligne pleine largeur (héritée de
   `align-items:stretch` sur .tpd-messages-thread). La bulle garde sa place
   habituelle par expéditeur (cliente à gauche, prestataire à droite) via
   `.tpd-message-row-client`/`-provider` ; la date, elle, se colle TOUJOURS
   au bord droit du panneau entier (`align-self:flex-end`), quel que soit
   l'expéditeur et quelle que soit la largeur de la bulle. */
.tpd-message-row { display: flex; flex-direction: column; width: 100%; }
.tpd-message-row-client { align-items: flex-start; }
.tpd-message-row-provider { align-items: flex-end; }
.tpd-message-bubble { max-width: 70%; padding: 10px 14px; border-radius: 10px; }
/* Audit responsive complet (retour Chloé) — même correctif que
   .tpd-table-row .tpd-appt-meta (25e vague, voir plus bas dans ce fichier) :
   white-space: pre-wrap coupe aux espaces, mais un token sans espace (URL,
   email, mot très long) ne coupait jamais et débordait de la bulle,
   surtout gênant sur un téléphone étroit où max-width: 70% laisse très
   peu de place. */
.tpd-message-bubble p { margin: 0; font-size: 14px; white-space: pre-wrap; overflow-wrap: anywhere; }
.tpd-message-client { background: var(--tpd-sand); border: 1px solid var(--tpd-line); border-bottom-left-radius: 2px; }
.tpd-message-provider { background: var(--tpd-ink); color: var(--tpd-paper); border-bottom-right-radius: 2px; }
.tpd-message-time { align-self: flex-end; margin-top: 2px; font-size: 11px; color: var(--tpd-muted); text-align: right; }
/* v1.9.3 — Chloé (item #77) : pièce jointe affichée dans la bulle + accusés
   de lecture avec horodatage sur les messages de la cliente. */
.tpd-message-attachment { margin: 6px 0 0; }
.tpd-message-attachment img { max-width: 160px; max-height: 160px; border-radius: 8px; display: block; object-fit: cover; }
.tpd-message-read { color: inherit; opacity: 0.85; }
.tpd-message-unread { color: var(--tpd-danger); font-weight: 600; }
.tpd-reply-form textarea {
	width: 100%;
	min-height: 90px;
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	padding: 12px 14px;
	font: inherit;
	resize: vertical;
}

/* Mobile nav toggle (hamburger) — hidden on desktop, where the full
   sidebar is always visible. */
.tpd-mobile-nav-toggle {
	display: none;
	flex-direction: column;
	justify-content: center;
	gap: 4px;
	width: 32px;
	height: 32px;
	background: none;
	border: none;
	cursor: pointer;
	padding: 0;
	flex-shrink: 0;
	-webkit-tap-highlight-color: transparent;
	outline: none;
}
.tpd-mobile-nav-toggle:focus-visible { outline: 2px solid rgba(255,255,255,0.6); outline-offset: 3px; }
.tpd-mobile-nav-toggle span { display: block; width: 100%; height: 1.5px; background: #fff; transition: transform .15s ease, opacity .15s ease; }
.tpd-mobile-nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.tpd-mobile-nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.tpd-mobile-nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/**
 * item 6 (26e vague, retour Chloé) — barre de navigation fixée en bas de
 * l'écran, UNIQUEMENT sur mobile (voir le @media juste en dessous, même
 * seuil que le hamburger ci-dessus). Masquée par défaut ici
 * (display:none), rendue visible seulement dans ce @media — toujours
 * présente dans le HTML (shell.php), jamais retirée du DOM, donc toujours
 * au même endroit peu importe la page affichée.
 *
 * BUG CORRIGÉ (26e vague, retour Chloé « la barre ne s'affiche jamais sur
 * mobile ») : cette règle de base vivait plus bas dans ce fichier (juste
 * après .tpd-help-fab), donc APRÈS le @media qui est censé la rendre
 * visible. À spécificité égale (une seule classe des deux côtés), c'est la
 * règle la plus BASSE dans le fichier qui gagne la cascade, qu'elle soit
 * dans un @media ou non — ce "display:none" écrasait donc systématiquement
 * le "display:flex" du @media, sur tous les écrans y compris en dessous de
 * 900px, et la barre ne pouvait jamais s'afficher, même sur un mobile où
 * le hamburger (juste au-dessus) s'affichait très bien. Même principe que
 * .tpd-mobile-nav-toggle juste au-dessus : la valeur par défaut doit être
 * déclarée AVANT le @media qui la surcharge, jamais après.
 * safe-area-inset-bottom pour ne pas finir sous la barre de gestes d'un
 * iPhone récent (encoche du bas).
 */
.tpd-bottom-nav {
	display: none;
	position: fixed;
	left: 0;
	right: 0;
	bottom: var(--tpd-impersonate-shift, 0px);
	z-index: 600;
	background: var(--tpd-sidebar-bg, var(--tpd-ink));
	border-top: 1px solid rgba(255,255,255,0.12);
	padding-bottom: env(safe-area-inset-bottom, 0);
}
/* item 6 (26e vague) — voir le docblock sur <body> dans shell.php : le
   bandeau "mode support Templiz" (position:fixed, bottom:0, z-index bien
   plus élevé — class-tpd-impersonate.php) couvrirait sinon complètement
   cette barre sur mobile pendant une session d'impersonation. Valeur
   volontairement généreuse : ce bandeau peut passer sur 2-3 lignes sur un
   petit écran (nom d'activité long + son propre lien), mieux vaut un peu
   d'espace vide entre les deux qu'un chevauchement. */
.tpd-body.tpd-is-impersonating { --tpd-impersonate-shift: 108px; }

/* v1.9.1 — Chloé (image 2): on mobile, cramming "Mon profil" / "+ Ajouter
   une option" / "Revoir la visite guidée" / "Se déconnecter" plus the full
   nav into one wrapping/horizontally-scrolling bar left everything
   overlapping and cut off ("Rendez…" running off the edge with no visible
   way to see the rest). Replaced with a proper collapsed menu: a slim bar
   (brand + hamburger) by default, and the hamburger reveals the full nav
   + footer links as a dropdown panel (dashboard.js toggles `.is-nav-open`
   and the button's aria-expanded). */
@media (max-width: 900px) {
	.tpd-shell { flex-direction: column; }
	/* item 4 (27e vague, retour Chloé) — padding vertical réduit de 14px à
	   10px, même proportion que la version desktop juste plus haut dans ce
	   fichier. */
	.tpd-sidebar { width: 100%; height: auto; position: static; padding: 10px 16px; gap: 0; }
	.tpd-sidebar-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
	.tpd-brand { margin-bottom: 0; }
	.tpd-mobile-nav-toggle { display: flex; }
	.tpd-nav, .tpd-sidebar-footer { display: none; }
	.tpd-sidebar.is-nav-open .tpd-nav {
		display: flex;
		flex-direction: column;
		overflow-y: visible;
		width: 100%;
		gap: 2px;
		margin-top: 16px;
		flex: none;
	}
	.tpd-sidebar.is-nav-open .tpd-sidebar-footer {
		display: flex;
		flex-direction: column;
		align-items: stretch;
		width: 100%;
		margin-top: 12px;
	}
	.tpd-nav-item { white-space: normal; }
	/* item 6 (26e vague, retour Chloé) — espace réservé en bas pour que le
	   contenu de chaque page ne finisse pas caché sous la nouvelle barre de
	   navigation fixe (.tpd-bottom-nav, ~64px + l'encoche iOS éventuelle). */
	.tpd-main { padding: 20px 16px calc(64px + env(safe-area-inset-bottom, 0px) + 20px); }
	.tpd-stat-grid { grid-template-columns: repeat(2, 1fr); }
	.tpd-two-col { flex-direction: column; }
	.tpd-col-side { min-width: 0; width: 100%; }
	.tpd-bottom-nav { display: flex; }
	/* item 3 (27e vague) — le bouton d'aide (désormais dans la barre du
	   haut, voir .tpd-help-btn plus bas) n'est plus en position:fixed,
	   donc plus aucun décalage à calculer ici pour éviter la nouvelle
	   barre de navigation — l'ancienne règle .tpd-help-fab a été retirée. */

	/**
	 * item #294 (14e vague, retour Chloé) — audit responsive complet : la
	 * ligne Rendez-vous (.tpd-appt-table-row — date + prestation/client +
	 * 2 badges statut/paiement + jusqu'à 5-6 boutons d'action dans
	 * .tpd-appt-actions) et les lignes .tpd-appt-row réutilisées ailleurs
	 * avec un contenu tout aussi chargé (demande de devis avec son propre
	 * formulaire Prix, avis prestataire en attente avec ses 2 boutons
	 * Publier/Rejeter — voir view-quotes.php et view-avis.php) n'avaient
	 * JAMAIS de flex-wrap, contrairement à leurs cousines .tpd-service-row/
	 * .tpd-table-row (voir plus bas, @media 700px) : tout restait forcé sur
	 * une seule ligne, qui dépassait largement la largeur de l'écran sur
	 * mobile et tablette (jusqu'à ~250px de contenu en trop rien que pour
	 * les boutons d'action sur un iPhone standard). flex-wrap laisse
	 * chaque partie (date, contenu, badges, actions) redescendre à la
	 * ligne dès qu'elle manque de place ; flex-wrap sur .tpd-appt-actions
	 * lui-même permet en plus aux boutons de se répartir sur plusieurs
	 * lignes plutôt que de continuer à déborder une fois sur sa propre
	 * ligne.
	 */
	.tpd-appt-row, .tpd-appt-table-row { flex-wrap: wrap; }
	.tpd-appt-actions { flex-wrap: wrap; }

	/**
	 * item #296 (14e vague, retour Chloé) — audit responsive complet : le
	 * titre "Calendrier" et .tpd-calendar-toolbar (bascule Mois/Semaine/
	 * Jour + bouton "Filtrer") étaient tous les deux dans .tpd-calendar-
	 * header, un flex SANS flex-wrap — seul le contenu interne de
	 * .tpd-calendar-toolbar avait déjà été prévu pour passer à la ligne
	 * (règle juste plus bas dans ce même bloc), pas la ligne titre+toolbar
	 * elle-même. Sur mobile, ces ~4-5 éléments côte à côte dépassaient la
	 * largeur de l'écran avant même d'atteindre le point où le toolbar
	 * interne aurait pu se replier.
	 */
	.tpd-calendar-header { flex-wrap: wrap; gap: 12px; }

	/**
	 * item #298 (14e vague, retour Chloé) — audit responsive complet :
	 * l'onglet Réglages (7 onglets, dont "Automatisations avancées" et
	 * "Apparence de Mon Espace") utilise .tpd-subnav SANS le modificateur
	 * .tpd-subnav-wrap déjà utilisé par Mon Mini-Site (qui a, lui aussi,
	 * beaucoup d'onglets) — cette page-là débordait donc horizontalement
	 * sur tablette/mobile alors que Mon Mini-Site ne le faisait pas. Plutôt
	 * que d'ajouter la classe -wrap partout où un sous-menu existe (et
	 * risquer d'oublier un futur écran), .tpd-subnav lui-même passe à la
	 * ligne sous ce seuil — sans effet sur desktop, où ces onglets tiennent
	 * déjà sur une seule ligne.
	 */
	.tpd-subnav { flex-wrap: wrap; }
}

@media (max-width: 480px) {
	.tpd-stat-grid { grid-template-columns: 1fr; }
}

/* Calendar header + legend */
.tpd-calendar-header { display: flex; justify-content: space-between; align-items: center; }
.tpd-calendar-nav { display: flex; align-items: center; gap: 12px; }
.tpd-calendar-month-label { font-family: 'Bodoni Moda', Georgia, serif; font-size: 18px; text-transform: capitalize; min-width: 160px; text-align: center; }
.tpd-calendar-legend { display: flex; gap: 16px; flex-wrap: wrap; margin: 16px 0 20px; }
.tpd-legend-item { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--tpd-muted); }
.tpd-legend-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }

/* Month grid */
.tpd-month-grid {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	gap: 8px;
}
.tpd-month-weekday { font-size: 12px; text-transform: uppercase; color: var(--tpd-muted); text-align: center; padding-bottom: 6px; }
/**
 * 30e vague, retour Chloé — "agrandir le calendrier" (format mois) :
 * min-height 100px → 140px et padding 8px → 10px, pour que davantage de
 * rendez-vous restent visibles par jour sans passer par "+N autres", en
 * profitant de la largeur supplémentaire donnée à .tpd-main juste plus
 * haut dans ce fichier. Uniquement sur desktop — le @media 900px un peu
 * plus bas redéfinit toujours sa propre hauteur compacte pour mobile.
 */
.tpd-month-cell {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	min-height: 140px;
	padding: 10px;
	display: flex;
	flex-direction: column;
	gap: 4px;
	/**
	 * 57e vague, retour Chloé — vérifié à l'écran en ajoutant la pastille
	 * de formation (voir .tpd-month-training plus bas) : .tpd-month-grid
	 * est en display:grid avec des colonnes 1fr, et .tpd-month-cell est
	 * donc un élément de grille dont la largeur "min-content" par défaut
	 * (min-width: auto) ne rétrécit JAMAIS sous celle de son contenu le
	 * plus large — un nom de formation long ("Initiation maquillage
	 * professionnel avec certification") élargissait silencieusement toute
	 * la colonne (et donc les 6 autres cellules de la même colonne sur
	 * tout le mois) au lieu d'être tronqué par l'ellipse déjà prévue (voir
	 * .tpd-month-training). Même bug de fond que .tpd-col-main corrigé au
	 * 54e vague (voir dashboard.css), ici côté grille CSS plutôt que
	 * flexbox — la correction est la même : forcer min-width à 0 sur
	 * l'élément qui doit pouvoir rétrécir.
	 */
	min-width: 0;
}
.tpd-month-cell.is-empty { background: transparent; border: none; }
.tpd-month-cell.is-today { border-color: var(--tpd-accent); }
.tpd-month-daynum { font-size: 12px; color: var(--tpd-muted); }
.tpd-month-cell.is-today .tpd-month-daynum { color: var(--tpd-accent); font-weight: 700; }
.tpd-month-events { display: flex; flex-direction: column; gap: 3px; }
/**
 * 57e vague, retour Chloé — "les formations [...] apparaitre sur le
 * calendrier des prestataires s'il y a des inscriptions" : même gabarit
 * visuel qu'un .tpd-month-event (pastille pleine couleur, texte blanc),
 * placée AU-DESSUS de .tpd-month-events pour rester visible même si la
 * journée est déjà pleine de rendez-vous.
 *
 * 62e vague, retour Chloé — depuis le 60e vague .tpd-month-training est
 * cliquable (voir son docblock juste en dessous) ; depuis ce 62e vague,
 * .tpd-day-training-banner (vue Jour, plus bas) a SES PROPRES règles
 * plutôt que réutiliser telles quelles celles de .tpd-month-training — même
 * esprit (pastille pleine couleur) mais rapproché du gabarit .tpd-day-event
 * de cette vue précise (voir son docblock).
 */
/**
 * min-width: 0 sur les deux — vérifié à l'écran, sans ça le texte long
 * d'une formation ("Initiation maquillage professionnel avec
 * certification"…) ne se tronquait PAS et débordait de la cellule :
 * .tpd-month-cell est un flex-column, et un enfant flex garde par défaut
 * sa largeur "min-content" (ne rétrécit jamais sous la largeur de son
 * contenu) tant qu'on ne lui dit pas explicitement le contraire — même
 * bug de fond que .tpd-col-main corrigé au 54e vague (voir dashboard.css,
 * juste avant .tpd-col-side), ici sur un tout autre élément.
 */
.tpd-month-trainings { display: flex; flex-direction: column; gap: 3px; margin-bottom: 2px; min-width: 0; }
/**
 * 60e vague, retour Chloé — "dans le calendrier quand les prestataires
 * cliquent sur l'une des formations ça doit ouvrir la fenêtre contextuelle
 * avec le détail comme pour les rendez-vous" : .tpd-month-training était
 * jusqu'ici un <span>/<div> non cliquable (voir le commentaire au-dessus,
 * désormais obsolète) — c'est maintenant un <button> (voir view-calendar.php
 * + le nouveau bloc .tpd-open-training-modal dans dashboard.js), avec le
 * même reset de style natif de bouton que .tpd-month-event un peu plus bas.
 *
 * 62e vague, retour Chloé — "l'affichage des formations en mois / semaine /
 * jour doivent apparaître dans le même style que ceux des rendez-vous" :
 * jusqu'ici une seule ligne tronquée ("🎓 Nom"), contre 2 lignes pour
 * .tpd-month-event (heure + prestation, puis cliente + coché) — même
 * gabarit flex-column désormais, et le markup (view-calendar.php) réutilise
 * littéralement .tpd-month-event-line1/-line2 pour les 2 lignes (icône +
 * nom de formation, puis X / Y inscrit(e)s) plutôt que dupliquer les
 * mêmes règles overflow/ellipsis sous un autre nom.
 */
.tpd-month-training {
	display: flex;
	flex-direction: column;
	gap: 1px;
	appearance: none;
	-webkit-appearance: none;
	font: inherit;
	text-align: left;
	border: none;
	cursor: pointer;
	color: #fff;
	font-size: 11px;
	line-height: 1.3;
	padding: 3px 6px;
	border-radius: 4px;
	min-width: 0;
}
/**
 * 62e vague, retour Chloé — même raisonnement que .tpd-month-training
 * ci-dessus pour la vue Semaine : .tpd-week-event (carte fond sable +
 * liseré coloré, voir plus bas) y est le "même style" que les rendez-vous
 * de CETTE vue précise — jusqu'ici la pastille de formation y réutilisait
 * .tpd-month-training (pastille pleine couleur), détonnant à côté des
 * cartes sable des rendez-vous. Même propriétés que .tpd-week-event, pour
 * que la formation se fonde visuellement dans la même colonne.
 */
.tpd-week-training {
	display: flex;
	flex-direction: column;
	gap: 1px;
	width: 100%;
	text-align: left;
	appearance: none;
	-webkit-appearance: none;
	font: inherit;
	background: var( --tpd-sand );
	border: none;
	border-left: 3px solid var( --tpd-accent );
	border-radius: 4px;
	padding: 6px 8px;
	margin-bottom: 6px;
	font-size: 11px;
	cursor: pointer;
	color: var( --tpd-ink );
}
.tpd-week-training-name { font-weight: 600; }
.tpd-week-training-seats { color: var( --tpd-muted ); }
/**
 * 62e vague, retour Chloé — vue Jour : le bandeau réutilisait déjà
 * .tpd-month-training (voir son docblock) mais restait une seule ligne
 * centrée sans l'info inscrit(e)s qu'affiche maintenant .tpd-day-event pour
 * un rendez-vous (heure + cliente). Gabarit/texte rapprochés de
 * .tpd-day-event (même font-size/padding/border-radius) plutôt que les
 * valeurs plus compactes de la pastille Mois, tout en gardant le bandeau
 * centré et pleine largeur (une formation occupe toute la colonne du
 * membre ce jour-là, pas un créneau précis à positionner sur la grille
 * horaire comme un rendez-vous).
 */
.tpd-day-training-banner {
	display: flex;
	flex-direction: column;
	gap: 1px;
	margin-bottom: 8px;
	text-align: center;
	font-size: 12px;
	padding: 4px 8px;
	border-radius: 6px;
}
.tpd-day-training-banner strong { display: block; }
.tpd-day-training-banner span { opacity: 0.9; font-size: 11px; }
/* v1.9.1 — Chloé (photo 3): richer appointment cards — time + prestation,
   client name with a confirmed checkmark — instead of one crammed,
   truncated line. Still a plain <button>, so the usual resets apply. */
.tpd-month-event {
	appearance: none;
	-webkit-appearance: none;
	font: inherit;
	text-align: left;
	display: flex;
	flex-direction: column;
	gap: 1px;
	color: #fff;
	font-size: 11px;
	line-height: 1.3;
	padding: 3px 6px;
	border: none;
	border-radius: 4px;
	cursor: pointer;
}
.tpd-month-event-line1, .tpd-month-event-line2 {
	display: flex;
	align-items: center;
	gap: 4px;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}
.tpd-month-event-time { font-weight: 700; flex-shrink: 0; }
.tpd-month-event-service { overflow: hidden; text-overflow: ellipsis; opacity: 0.95; }
.tpd-month-event-line2 { opacity: 0.9; }
.tpd-month-event-check { flex-shrink: 0; }
/* 62e vague, retour Chloé — item 7 : voir le docblock dans view-calendar.php
   — délibérément PAS .tpd-month-event-service (masquée sur mobile juste en
   dessous), le nom de la formation restant l'info principale de sa pastille. */
.tpd-month-training-name { overflow: hidden; text-overflow: ellipsis; }
.tpd-month-more { font-size: 11px; color: var(--tpd-muted); text-decoration: none; }

@media (max-width: 900px) {
	.tpd-month-grid { grid-template-columns: repeat(7, minmax(36px, 1fr)); gap: 3px; }
	.tpd-month-cell { min-height: 60px; padding: 4px; font-size: 11px; }
	/* v1.9.1 — was `display: none`, which hid every appointment from the
	   month view on mobile/tablet with no way to tell a day had any at all
	   (short of noticing the day was in `.tpd-month-more`'s "+N", which
	   itself only ever appeared past 3 appointments on the same day).
	   Trimmed down to the essentials — time + client, no service name or
	   checkmark, which don't fit a 60px-tall cell — rather than hidden. */
	.tpd-month-event { font-size: 9px; padding: 2px 4px; gap: 0; }
	.tpd-month-event-service, .tpd-month-event-check { display: none; }
	/* 62e vague — même compacité mobile que .tpd-month-event ci-dessus pour
	   .tpd-month-training (voir son docblock plus haut) : la ligne 2
	   (X / Y inscrit(e)s) est une info secondaire comme .tpd-month-event-line2,
	   on la masque aussi pour laisser la place au nom de la formation
	   (jamais masqué, voir .tpd-month-training-name) dans une pastille de
	   60px de haut. */
	.tpd-month-training { font-size: 9px; padding: 2px 4px; gap: 0; }
	.tpd-month-training .tpd-month-event-line2 { display: none; }
}

/* Extras repeater / duration picker / days picker */
.tpd-subsection { border-top: 1px solid var(--tpd-line); margin-top: 6px; padding-top: 14px; }
.tpd-subsection h4 { font-size: 14px; margin: 0 0 4px; }

/* 32e vague, retour Chloé — "la fenêtre ajouter ou modifier une prestation
   doit être présentable [...] ne doit pas paraître trop encombrée" : titres
   de groupe insérés entre les champs existants du formulaire Prestations
   (voir view-services.php), même habillage que .tpd-subsection ci-dessus
   (déjà utilisé pour "Caractéristiques"/"Services supplémentaires") pour
   rester cohérent, mais sur un simple <h4> autonome plutôt qu'un wrapper —
   aucun champ n'a été déplacé dans un nouveau conteneur, seuls ces titres
   ont été ajoutés, donc aucun risque de casser la structure existante. */
.tpd-modal-section-title { border-top: 1px solid var(--tpd-line); margin: 20px 0 6px; padding-top: 16px; font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--tpd-muted); }
.tpd-extra-row { display: grid; grid-template-columns: 1fr 70px 190px auto; gap: 6px; margin-bottom: 8px; align-items: center; }
.tpd-extra-row input { border: 1px solid var(--tpd-line); border-radius: 6px; padding: 8px 10px; font: inherit; }
/**
 * 58e vague, retour Chloé — "la durée des services supplémentaires doit
 * être en heure et minutes" : la 3e colonne de .tpd-extra-row (autrefois un
 * simple champ minutes de 70px) contient maintenant le même sélecteur
 * heures+minutes que la durée principale (.tpd-duration-picker), avec 2
 * champs au lieu d'1 — colonne élargie à 190px pour l'accueillir.
 *
 * Premier essai à 150px de colonne / 42px de champs : repéré au rendu réel
 * (capture d'écran) que les chiffres à 2 chiffres ("30", "15"...) étaient
 * tronqués — un input number garde ses flèches +/- quelle que soit sa
 * largeur, un champ trop étroit ne laisse quasiment plus de place au texte.
 * Corrigé en reprenant exactement la même largeur de champ (60px) que le
 * sélecteur heures+minutes de la durée PRINCIPALE juste au-dessus dans ce
 * formulaire (.tpd-duration-picker input, déjà un motif éprouvé) plutôt que
 * d'inventer une largeur plus étroite — et élargi la colonne en conséquence
 * pour l'accueillir sans la retasser.
 */
.tpd-extra-row .tpd-extra-duration.tpd-duration-picker input { width: 60px; }
/**
 * item #297 (14e vague, retour Chloé) — audit responsive complet :
 * ".tpd-variant-row" (répéteur "Caractéristiques" de Prestations, item
 * #137 — libellé + prix par caractéristique) n'avait encore AUCUNE règle
 * CSS dans ce fichier, contrairement à son répéteur jumeau .tpd-extra-row
 * juste au-dessus — ses champs restaient donc en flux HTML par défaut
 * (input/button en display:inline-block, largeur native du navigateur),
 * ce qui débordait déjà à l'étroit dans .tpd-modal-form sur desktop et
 * plus encore sur mobile. Même grille que .tpd-extra-row, adaptée à ses 2
 * champs (libellé + prix) au lieu de 3.
 */
.tpd-variant-row { display: grid; grid-template-columns: 1fr 90px auto; gap: 6px; margin-bottom: 8px; align-items: center; }
.tpd-variant-row input { border: 1px solid var(--tpd-line); border-radius: 6px; padding: 8px 10px; font: inherit; }

.tpd-duration-picker { display: flex; align-items: center; gap: 6px; }
.tpd-duration-picker input { width: 60px; }
.tpd-duration-picker span { font-size: 13px; color: var(--tpd-muted); }

.tpd-days-picker { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
/* v1.9.3 — Chloé (item #80): "revoir le visuel du sélecteur de jours" —
   c'était une case à cocher + texte dans un simple cadre, sans distinction
   visuelle claire entre jour sélectionné et non sélectionné. Redessiné en
   pastilles cliquables : la case reste dans le DOM (accessibilité, la
   soumission du formulaire ne change pas) mais n'est plus affichée — c'est
   tout le libellé .tpd-day-checkbox qui se remplit quand elle est cochée. */
.tpd-day-checkbox {
	display: flex; align-items: center; justify-content: center;
	min-width: 42px;
	font-size: 12px; font-weight: 600;
	border: 1px solid var(--tpd-line);
	border-radius: 999px;
	padding: 7px 10px;
	cursor: pointer;
	user-select: none;
	background: var(--tpd-paper);
	color: var(--tpd-ink);
	transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.tpd-day-checkbox input { position: absolute; opacity: 0; width: 0; height: 0; }
.tpd-day-checkbox:hover { border-color: var(--tpd-accent); }
.tpd-day-checkbox:has(input:checked) { background: var(--tpd-ink); color: #fff; border-color: var(--tpd-ink); }

/**
 * item #255 (10e vague, retour Chloé) — "ajoute un bouton un interrupteur
 * à bascule (toggle switch) pour activer ou désactiver l'option [...]".
 * Réglages > Déplacement utilisait jusque-là .tpd-day-checkbox pour ce
 * réglage on/off, mais ce composant a été pensé pour les pastilles de
 * jours de la semaine (largeur mini, forme pilule) — appliqué seul à un
 * unique réglage, il donne un bouton pleine largeur plutôt qu'un vrai
 * interrupteur (voir la photo jointe). Nouveau composant dédié ici,
 * réutilisable pour tout futur réglage on/off du même type.
 */
/**
 * item #273 (12e vague, retour Chloé) — "Les Interrupteurs à bascule [...]
 * sont centrés place les à gauche" : .tpd-card label { flex-direction:
 * column } (voir plus haut, pensé pour les champs texte classiques
 * "libellé au-dessus du champ") a une spécificité CSS PLUS FORTE que
 * .tpd-toggle-row seul (classe+élément vs classe seule) — chaque
 * interrupteur (toujours un <label class="tpd-toggle-row">, voir
 * view-settings.php/view-team.php/etc.) héritait donc malgré lui de
 * flex-direction:column, empilant interrupteur + texte au lieu de les
 * mettre côte à côte, et le align-items:center d'origine centrait alors
 * horizontalement cette pile au lieu d'aligner les deux éléments à gauche
 * sur une même ligne. Sélecteur "label.tpd-toggle-row" ci-dessous : même
 * spécificité que ".tpd-card label" (classe+élément), qui l'emporte étant
 * déclaré après dans ce fichier — flex-direction:row explicite pour ne
 * plus dépendre de cet ordre de déclaration.
 */
label.tpd-toggle-row { display: flex; flex-direction: row; align-items: center; justify-content: flex-start; gap: 12px; }
.tpd-toggle-switch { position: relative; display: inline-block; width: 42px; height: 24px; flex-shrink: 0; }
/**
 * item #274 (12e vague, retour Chloé) — "le checkbox apparaît sous le
 * toggle switch" (signalé côté panneau de réservation, même correctif
 * appliqué ici par cohérence) : appearance:none manquant sur la case
 * masquée — certains navigateurs/modes d'accessibilité (contraste élevé,
 * forced-colors) ignorent opacity:0 sur les contrôles de formulaire
 * natifs. appearance:none la supprime pour de bon ; z-index explicite en
 * plus, par sécurité, pour garantir que .tpd-toggle-switch-track reste
 * au-dessus.
 */
.tpd-toggle-switch input {
	position: absolute; inset: 0; width: 100%; height: 100%; margin: 0;
	opacity: 0; cursor: pointer; z-index: 2;
	appearance: none; -webkit-appearance: none; -moz-appearance: none;
}
.tpd-toggle-switch-track {
	position: absolute; inset: 0; z-index: 1;
	background: var(--tpd-line);
	border-radius: 999px;
	transition: background .15s ease;
}
.tpd-toggle-switch-track::before {
	content: "";
	position: absolute; top: 3px; left: 3px;
	width: 18px; height: 18px;
	background: #fff;
	border-radius: 50%;
	box-shadow: 0 1px 2px rgba(0,0,0,0.25);
	transition: transform .15s ease;
}
.tpd-toggle-switch input:checked + .tpd-toggle-switch-track { background: var(--tpd-ink); }
.tpd-toggle-switch input:checked + .tpd-toggle-switch-track::before { transform: translateX(18px); }
.tpd-toggle-switch input:focus-visible + .tpd-toggle-switch-track { outline: 2px solid var(--tpd-accent); outline-offset: 2px; }
.tpd-toggle-row-label { font-size: 14px; color: var(--tpd-ink); cursor: pointer; }

.tpd-schedule-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.tpd-schedule-day-label { width: 90px; font-size: 13px; color: var(--tpd-muted); }
.tpd-schedule-row input { border: 1px solid var(--tpd-line); border-radius: 6px; padding: 7px 8px; font: inherit; }

/* Sub-navigation (Réglages tabs) */
.tpd-subnav { display: flex; gap: 8px; margin-bottom: 20px; }
.tpd-subnav-item {
	padding: 8px 16px;
	border-radius: 6px;
	text-decoration: none;
	color: var(--tpd-muted);
	font-size: 14px;
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
}
.tpd-subnav-item.is-active { color: var(--tpd-ink); border-color: var(--tpd-ink); font-weight: 600; }

/* Theme grid (Mon Mini-Site) */
.tpd-theme-grid { display: flex; gap: 10px; flex-wrap: wrap; }
.tpd-theme-card { border: 1px solid var(--tpd-line); border-radius: 8px; padding: 12px 16px; cursor: pointer; font-size: 14px; }
.tpd-theme-card.is-selected { border-color: var(--tpd-accent); background: var(--tpd-sand); }
.tpd-theme-card input { margin-right: 6px; }

.tpd-service-photo { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }
.tpd-appt-extras-note { display: block; font-size: 12px; color: var(--tpd-accent); margin-top: 2px; }

/* item #132 — palette de couleurs "Mon Espace" (Réglages > Apparence) */
.tpd-color-palette { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }
.tpd-color-swatch {
	width: 34px; height: 34px; border-radius: 50%;
	border: 2px solid transparent;
	cursor: pointer;
	padding: 0;
}
.tpd-color-swatch.is-selected { border-color: var(--tpd-ink); box-shadow: 0 0 0 2px var(--tpd-paper) inset; }
#tpd-dashboard-color-input { width: 60px; height: 38px; padding: 2px; border: 1px solid var(--tpd-line); border-radius: 8px; cursor: pointer; }

.tpd-media-picker { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* item #132 — sélecteur de point focal 3×3 (voir partial-media-picker.php) */
.tpd-position-picker { display: grid; grid-template-columns: repeat(3, 22px); grid-template-rows: repeat(3, 22px); gap: 3px; margin-top: 8px; width: max-content; }
.tpd-position-cell { border: 1px solid var(--tpd-line); background: var(--tpd-paper); cursor: pointer; padding: 0; border-radius: 3px; }
.tpd-position-cell:hover { border-color: var(--tpd-accent); }
.tpd-position-cell.is-selected { background: var(--tpd-accent); border-color: var(--tpd-accent); }
.tpd-media-preview img { max-height: 60px; border-radius: 6px; border: 1px solid var(--tpd-line); }

/* Mini-site sub-nav (wraps on many tabs) */
.tpd-subnav-wrap { flex-wrap: wrap; }

/* Gallery multi-picker (Mon Mini-Site > Photos) */
.tpd-gallery-picker-list { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.tpd-gallery-picker-item { position: relative; cursor: grab; }
.tpd-gallery-picker-item.is-dragging { opacity: 0.4; }
.tpd-gallery-picker-item img { width: 80px; height: 80px; object-fit: cover; border-radius: 6px; border: 1px solid var(--tpd-line); }
/* item #128 — video gallery picker (Réseaux sociaux > Galerie vidéo): its
   own classes end-to-end, deliberately NOT sharing .tpd-gallery-picker-list/
   -item with the photo picker above even though the visual result is
   nearly identical — the photo picker's JS finds its list/items purely by
   those class names (document.querySelector, no tab/id scoping), and on
   the Social tab page the photo picker markup itself isn't present at
   all, so sharing the class made the photo picker's own JS silently latch
   onto the video list instead and cap it at the PHOTO limit (4) rather
   than the video one (6) — exactly Chloé's "autorisation max de 4 vidéos"
   report. Independent classes make that impossible regardless of which
   tab's markup happens to be on the page. */
.tpd-video-gallery-picker-list { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.tpd-video-gallery-picker-item { position: relative; cursor: grab; }
.tpd-video-gallery-picker-item.is-dragging { opacity: 0.4; }
.tpd-video-gallery-picker-item video { width: 80px; height: 80px; object-fit: cover; border-radius: 6px; border: 1px solid var(--tpd-line); background: #000; }
.tpd-remove-gallery-item {
	position: absolute; top: -6px; right: -6px;
	width: 20px; height: 20px; border-radius: 50%;
	background: var(--tpd-danger); color: #fff; border: none; cursor: pointer; line-height: 1; font-size: 12px;
}

/* item #129 — sélecteur d'activité (Mon Site > Identité), pastilles
   reprenant le visuel "Créez votre site en 3 étapes" de la page marketing. */
.tpd-activity-picker { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 4px; }
.tpd-activity-pill {
	padding: 8px 14px; border-radius: 20px; border: 1px solid var(--tpd-line);
	background: var(--tpd-paper); color: var(--tpd-ink); font: inherit; cursor: pointer;
}
.tpd-activity-pill.is-selected { border-color: var(--tpd-ink); background: var(--tpd-ink); color: var(--tpd-paper); }
.tpd-activity-pill-other.is-selected { border-color: var(--tpd-accent); background: var(--tpd-accent); }

/* item #129 — pages /inscription/ et /connexion/ (site principal, hors
   Mon Espace : pas de sidebar, personne n'est encore connecté). */
.tpd-auth-body { background: var(--tpd-paper); min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 40px 16px; }
.tpd-auth-wrap { width: 100%; max-width: 480px; }
/* 68e vague, retour Chloé — .tpd-auth-brand est désormais un <a> (le logo
   mène à l'accueil, voir auth-shell.php) plutôt qu'un simple <div> :
   display:block + text-decoration:none + color:inherit annulent le style
   de lien par défaut du navigateur, pour un rendu inchangé visuellement. */
.tpd-auth-brand { display: block; text-align: center; font-family: 'Bodoni Moda', serif; font-size: 20px; margin-bottom: 20px; text-decoration: none; color: inherit; }
/* item #231 (9e vague, retour Chloé) — vrai logo Templiz (wordmark fourni
   par Chloé) sur /connexion/ et /inscription/, à la place de l'icône de
   site 24x24 + texte. Largeur bornée, hauteur automatique pour respecter
   les proportions réelles du fichier (logo large et bas, pas une icône
   carrée). */
.tpd-auth-brand-logo { display: inline-block; max-width: 180px; height: auto; }
.tpd-auth-card h1 { font-size: 22px; }
.tpd-auth-card h3 { margin: 20px 0 8px; font-size: 15px; }
.tpd-auth-card h3:first-of-type { margin-top: 4px; }

/* item #223 (8e vague) — bouton "afficher le mot de passe" sur la page
   /connexion/ custom, même geste visuel que TPD_Login_Design sur
   wp-login.php (voir class-tpd-login-design.php). */
.tpd-pwd-wrap { position: relative; display: block; }
/* 68e vague, retour Chloé — "bug quand je clique sur masquer y a rien" :
   Safari (desktop et surtout iOS/iCloud Trousseau) dessine sa PROPRE icône
   native "mot de passe" dans l'angle droit du champ, au même endroit que
   notre bouton "Afficher/Masquer" — contrairement à l'icône native de
   Chrome/Edge (voir plus bas), celle de Safari ne peut pas être masquée en
   CSS. Les deux se superposaient donc exactement sur iPhone, et le tap
   atterrissait sur l'icône native de Safari plutôt que sur notre bouton,
   qui semblait alors ne réagir à rien. Le bouton est reculé plus loin du
   bord droit (right ↑, padding-right ↑) pour laisser une zone dédiée à
   l'icône native et ne plus jamais se chevaucher avec elle. */
.tpd-pwd-wrap input { padding-right: 76px !important; width: 100%; }
.tpd-pwd-toggle {
	position: absolute; right: 24px; top: 50%; transform: translateY(-50%);
	background: none; border: none; cursor: pointer; padding: 6px 8px;
	color: var(--tpd-muted); font-size: 12.5px; font-weight: 600;
}
.tpd-pwd-toggle:hover { color: var(--tpd-ink); }
/* 50e vague, retour Chloé — même correctif que TPD_Login_Design (wp-login.php,
   voir class-tpd-login-design.php) : neutralise l'icône native "afficher le
   mot de passe" de Chrome/Edge, qui se superposait à notre bouton "Afficher"
   personnalisé. */
.tpd-pwd-wrap input[type="password"]::-ms-reveal,
.tpd-pwd-wrap input[type="password"]::-ms-clear { display: none; }
/* 74e vague, retour Chloé — "l'ensemble des balises de mot de passe sont
   réduites [...] il faut absolument que ça soit comme avant" (captures
   jointes : le champ mot de passe s'affiche bien plus bas/étroit que le
   champ au-dessus) : bug réel, introduit par CETTE règle depuis la 50e
   vague et resté invisible jusqu'ici. ::-webkit-textfield-decoration-
   container n'est PAS une icône décorative isolée : c'est le conteneur
   interne de Chrome/Edge qui porte le TEXTE TAPÉ lui-même (et les éventuels
   contrôles natifs). Le display:none ci-dessus cachait donc aussi le
   contenu réel du champ, qui s'effondrait visuellement à une hauteur quasi
   nulle — exactement ce que montrent les captures. Les règles plus
   récentes et plus précises ajoutées en 70e/71e vague ci-dessous
   (::-webkit-credentials-auto-fill-button et consorts, ::-webkit-caps-
   lock-indicator) ciblent déjà chaque icône native UNE PAR UNE sans
   toucher au conteneur de contenu — elles suffisent à elles seules à
   neutraliser les icônes superposées. Règle supprimée ici (et dans
   class-tpd-login-design.php / class-tzb-client-account.php, même
   historique identique) plutôt que corrigée : elle n'apportait plus rien
   que les règles suivantes ne couvrent déjà, tout en causant ce bug.
*/
/* 70e vague, retour Chloé — "problème d'affichage de mot de passe avec
   toutes les balises" : la correction ci-dessus (50e vague) ne couvrait pas
   la nouvelle icône "clé" (gestionnaire de mots de passe/suggestions
   Chrome-Edge) — ce n'est PAS un enfant du conteneur ::-webkit-textfield-
   decoration-container mais un pseudo-élément séparé, donc il réapparaissait
   par-dessus notre bouton malgré la règle précédente. visibility (pas
   display) + pointer-events pour laisser le clic passer jusqu'à notre
   bouton en dessous, au cas où le navigateur le dessinerait quand même. */
/* 71e vague, retour Chloé — "persiste encore sur mobile" : visibility seul ne
   suffisait pas sur Chrome mobile (l'icône restait affichée malgré tout) —
   display:none ajouté en renfort, et ::-webkit-strong-password-auto-fill-button
   (icône "suggérer un mot de passe") au cas où un champ de connexion serait
   traité par erreur comme un nouveau mot de passe par certains navigateurs. */
.tpd-pwd-wrap input[type="password"]::-webkit-credentials-auto-fill-button,
.tpd-pwd-wrap input[type="password"]::-webkit-contacts-auto-fill-button,
.tpd-pwd-wrap input[type="password"]::-webkit-strong-password-auto-fill-button {
	visibility: hidden;
	display: none !important;
	pointer-events: none;
	position: absolute;
	right: 0;
}
.tpd-pwd-wrap input[type="password"]::-webkit-caps-lock-indicator { display: none; }

.tpd-plan-picker { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.tpd-plan-card {
	display: flex; flex-direction: column; gap: 2px; align-items: center; text-align: center;
	padding: 12px 8px; border-radius: 10px; border: 1px solid var(--tpd-line);
	background: var(--tpd-paper); cursor: pointer;
}
.tpd-plan-card strong { font-size: 14px; }
.tpd-plan-card span { font-size: 12px; color: #888; }
.tpd-plan-card.is-selected { border-color: var(--tpd-ink); background: var(--tpd-ink); }
.tpd-plan-card.is-selected strong, .tpd-plan-card.is-selected span { color: var(--tpd-paper); }
@media (max-width: 480px) { .tpd-plan-picker { grid-template-columns: 1fr 1fr; } }

/* FAQ / testimonials repeaters reused from the Prestations extras look */
.tpd-faq-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; margin-bottom: 10px; }
.tpd-faq-row input, .tpd-faq-row textarea,
.tpd-testimonial-row input, .tpd-testimonial-row select, .tpd-testimonial-row textarea {
	border: 1px solid var(--tpd-line); border-radius: 6px; padding: 8px 10px; font: inherit;
}
.tpd-testimonial-row { display: grid; grid-template-columns: 140px 80px 1fr auto; gap: 8px; margin-bottom: 10px; align-items: start; }

/* item #90 — header/menu layout picker (Mon Site > Disposition), two
   little mockups the prestataire clicks like a radio button. Same
   :has()-driven selected-state pattern as .tpd-palette-swatch above. */
.tpd-header-layout-picker { display: flex; flex-wrap: wrap; gap: 16px; }
.tpd-header-layout-option {
	display: flex;
	flex-direction: column;
	gap: 6px;
	cursor: pointer;
	width: 180px;
}
.tpd-header-layout-option input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; }
.tpd-header-layout-mock {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 6px;
	background: var(--tpd-sand);
	border: 2px solid transparent;
	border-radius: 8px;
	padding: 12px;
}
.tpd-header-layout-option:has(input:checked) .tpd-header-layout-mock { border-color: var(--tpd-ink); }
.tpd-mock-brand { width: 40%; height: 8px; border-radius: 4px; background: var(--tpd-muted); flex-shrink: 0; }
.tpd-mock-links { display: flex; gap: 6px; }
.tpd-mock-links span { width: 20px; height: 6px; border-radius: 3px; background: var(--tpd-line); }
.tpd-header-layout-mock-centered {
	flex-direction: column;
	justify-content: center;
}
.tpd-header-layout-mock-centered .tpd-mock-brand { width: 50%; }
.tpd-header-layout-name { font-size: 13px; font-weight: 600; }
.tpd-header-layout-desc { font-size: 11px; opacity: 0.75; line-height: 1.3; }

/* Drag-and-drop order list (Mon Mini-Site > Disposition) */
.tpd-order-list { list-style: none; margin: 12px 0 0; padding: 0; max-width: 420px; }
.tpd-order-item { background: var(--tpd-paper); border: 1px solid var(--tpd-line); border-radius: 6px; padding: 12px 14px; margin-bottom: 8px; font-size: 14px; }
.tpd-order-item[draggable="true"] { cursor: grab; }
.tpd-order-item.is-dragging { opacity: 0.4; }
.tpd-order-item-fixed { background: var(--tpd-sand); color: var(--tpd-muted); font-style: italic; cursor: default; }
.tpd-order-handle { opacity: 0.5; margin-right: 4px; }
/* 129e vague, retour Chloé — case "visible sur l'Accueil" ajoutée à chaque
   bloc réordonnable (voir view-minisite.php, tab 'layout'). display:flex ici
   n'a aucun effet visuel sur les lignes fixes/sans case (En-tête, Pied de
   page, lignes de "Disposition des pages dans le menu") : un seul enfant,
   déjà aligné à gauche comme avant. */
.tpd-order-item { display: flex; align-items: center; }
.tpd-order-item-visibility { display: flex; align-items: center; gap: 6px; cursor: pointer; font-weight: normal; }

.tpd-minisite-form textarea { min-height: 60px; resize: vertical; }
.tpd-dayoff-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.tpd-dayoff-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; background: var(--tpd-sand); border-radius: 6px; padding: 8px 12px; }
.tpd-dayoff-row form { display: inline; }
.tpd-dayoff-form { display: flex; flex-direction: column; gap: 10px; }

/* Generic data table (Paiements, Clients, Liste d'attente) */
.tpd-count-badge { display: inline-block; background: var(--tpd-accent); color: #fff; font-size: 12px; padding: 2px 9px; border-radius: 20px; margin-left: 8px; vertical-align: middle; }
.tpd-table { display: flex; flex-direction: column; gap: 6px; }
.tpd-table-head {
	display: grid;
	gap: 10px;
	padding: 0 16px 8px;
	font-size: 12px;
	text-transform: uppercase;
	color: var(--tpd-muted);
}
.tpd-table-row {
	display: grid;
	gap: 10px;
	align-items: center;
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: 8px;
	padding: 12px 16px;
	font-size: 13px;
	text-decoration: none;
	color: var(--tpd-ink);
}
.tpd-table-row-link:hover { border-color: var(--tpd-accent); }
/* v1.9.2 — Chloé: "léger décalage" between the Paiements header and its
   rows. Two compounding causes, both about `fr` tracks sharing whatever
   space is "left over" once fixed content is accounted for — and each
   row being its own independent grid, computing that leftover
   differently:
   1) The last column was `auto`, sized per-row by its own action
      buttons ("Acompte payé" + "Marquer payé" + "QR" vs. none on an
      already-paid row, vs. empty on the header) — swapped for a fixed
      width so every row/header reserves the same space for it.
   2) A grid item's automatic minimum width defaults to its content's
      min-content size — an email address has no spaces to break on, so
      a long one (e.g. "wearetempliz@gmail.com") forced that row's
      Client column to a much wider minimum than the header's "Client"
      label needs, stealing space from every column after it. Fixed
      with `min-width: 0` on every cell (lets columns shrink below their
      content's natural width) plus letting the email itself wrap. */
.tpd-table-head > span, .tpd-table-row > span { min-width: 0; }
.tpd-table-row .tpd-appt-meta { overflow-wrap: anywhere; }
/* item 4 (25e vague, retour Chloé) — "Paiements : règle bien l'affiche du
   texte dans chaque colonne il ne faut pas que ça se chevauche" : le
   `min-width: 0` ci-dessus (v1.9.2) empêche déjà une colonne de forcer
   toutes les autres à s'élargir, mais un texte qui n'a AUCUN point de
   coupure ne "wrap" toujours pas — il déborde tel quel hors de sa
   colonne, par-dessus la colonne suivante (Total/Payé/Dû, chacune
   seulement 0.8fr). Deux cas concrets sur cette page :
   1) un montant >= 1000 € formaté en français (number_format_i18n) — ex.
      "1 234,56" — utilise une espace INSÉCABLE comme séparateur de
      milliers : pas de point de coupure, donc débordement direct.
   2) un badge de statut à deux mots ("Acompte payé") dans une colonne
      encore plus étroite.
   `overflow-wrap: anywhere` (déjà utilisé ci-dessus pour les emails,
   .tpd-appt-meta) force le navigateur à couper n'importe où en dernier
   recours plutôt que de laisser déborder — étendu ici à TOUTES les
   cellules de tous les tableaux du dashboard (Paiements/Clients/Liste
   d'attente/Support/Factures), la case n'ayant aucun inconvénient sur un
   texte qui tenait déjà dans sa colonne. */
.tpd-table-head > span, .tpd-table-row > span { overflow-wrap: anywhere; }
/* item 4 (25e vague, retour Chloé) — la dernière colonne "Paiements"
   (actions : "Acompte payé" + "Marquer payé" + "QR" peuvent coexister sur
   une même ligne, ~260px de texte/boutons cumulés dans une colonne fixée
   à 220px) reposait sur le flux inline par défaut (`display:inline` sur
   chaque <form>) : le retour à la ligne entre boutons dépendait d'un
   simple espace texte dans le HTML, donnant un empilement approximatif
   plutôt qu'un vrai design de groupe de boutons. `flex` + `flex-wrap` +
   `gap` rend ce retour à la ligne intentionnel et proprement espacé. */
.tpd-table--payments .tpd-table-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.tpd-table--payments .tpd-table-actions form { display: flex; }
.tpd-table--payments .tpd-table-head, .tpd-table--payments .tpd-table-row { grid-template-columns: 1.2fr 1.4fr 1fr 1fr 0.8fr 0.8fr 0.8fr 1fr 220px; }
.tpd-table--clients .tpd-table-head, .tpd-table--clients .tpd-table-row { grid-template-columns: 1.6fr 1fr 1fr 1fr 0.8fr; }
.tpd-table--waitlist .tpd-table-head, .tpd-table--waitlist .tpd-table-row { grid-template-columns: 1.4fr 1fr 1fr 1fr 0.8fr 50px; }
/* item A (23e vague, retour Chloé) — "Mes demandes" de support (voir
   view-support.php) : mêmes composants .tpd-table/.tpd-table-row que
   Paiements/Clients/Liste d'attente ci-dessus, colonnes Sujet/Catégorie/
   Statut/Dernière mise à jour. */
.tpd-table--support .tpd-table-head, .tpd-table--support .tpd-table-row { grid-template-columns: 2fr 1.2fr 1fr 1fr; }
/* item 8 (24e vague, retour Chloé) — bloc "Factures de paiement" universel
   (toutes formules) sur la page Paiements, voir view-payments.php ;
   colonnes Date/Client/Montant/N° de facture/lien PDF.
   130e vague, retour Chloé (suite) — "laisse les choisir les factures
   concernées ou la période" : colonne case à cocher ajoutée en tête
   (40px, voir le ZIP sélectif dans view-payments.php). */
.tpd-table--payment-invoices .tpd-table-head, .tpd-table--payment-invoices .tpd-table-row { grid-template-columns: 40px 1fr 1.6fr 1fr 1.2fr 130px; }
/**
 * 30e vague, retour Chloé — "Liste d'attente : il y a un bug [...] pour la
 * balise professionnel la liste s'affiche plus haut" : confirmé visuellement
 * (capture d'écran desktop) — .tpd-table-row utilise align-items:center
 * (règle de base plus haut dans ce fichier), qui centre CHAQUE cellule sur
 * la hauteur de la plus haute cellule de sa propre ligne. La colonne
 * "Client" de ce tableau est la seule à afficher 2 lignes (nom, puis email
 * + téléphone) — 3 quand l'email est un peu long et s'enroule. Le nom du
 * "Professionnel" à côté (une seule ligne) se retrouve alors centré sur
 * cette hauteur, donc visuellement décalé vers le haut par rapport au nom
 * du client au lieu de rester sur la même ligne que lui. Aligné en haut
 * pour ce tableau spécifiquement — jamais .tpd-table-row en général, pour
 * ne rien changer aux autres tableaux (Paiements, Clients, etc.), qui
 * n'ont pas ce problème signalé.
 */
.tpd-table--waitlist .tpd-table-row { align-items: start; }
.tpd-badge-paid { background: #E4F2E4; color: #2E6B2E; }
.tpd-badge-unpaid { background: #FDF0D5; color: #8A6D1D; }
.tpd-appt-extras-note { color: var(--tpd-accent); }
.tpd-appt-attachment-link { color: var(--tpd-accent); text-decoration: none; margin-left: 6px; }
.tpd-appt-attachment-link:hover { text-decoration: underline; }
/* item #132 — client-stated cancellation reason + refund-decision badge */
.tpd-appt-cancel-note { display: block; font-size: 12px; color: #B3423C; margin-top: 2px; }
.tpd-badge-muted { background: var(--tpd-line); color: var(--tpd-ink); opacity: 0.75; }

/* Calendar: service color legend + detail modal */
.tpd-modal-overlay {
	position: fixed; inset: 0; background: rgba(20,19,15,0.5);
	display: flex; align-items: center; justify-content: center;
	z-index: 1000;
}
.tpd-modal-overlay[hidden] { display: none; }
.tpd-modal {
	background: var(--tpd-paper);
	border-radius: 10px;
	padding: 28px;
	max-width: 420px;
	width: 90%;
	max-height: 85vh;
	overflow-y: auto;
}
.tpd-modal-close { float: right; background: none; border: none; font-size: 20px; cursor: pointer; color: var(--tpd-muted); }
.tpd-modal h3 { font-family: 'Bodoni Moda', Georgia, serif; margin: 0 0 16px; }
.tpd-modal-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--tpd-line); font-size: 14px; }
/* v1.9.1 — same recurring bug as `.tsb-urgency-contact-menu[hidden]` in
   Site Builder and `.tzb-step[hidden]` in the booking widget: an author
   rule setting `display` unconditionally beats the browser's own
   `[hidden]{display:none}` UA rule, so the `hidden` attribute JS toggles
   on the discount/surcharge/notes rows had no effect — they showed an
   empty "Remise :" / "Supplément :" / "Notes :" line on every appointment,
   not just ones that actually have a discount, surcharge, or notes. */
.tpd-modal-row[hidden] { display: none; }
.tpd-modal-row:last-of-type { border-bottom: none; }
.tpd-modal-row span:first-child { color: var(--tpd-muted); }
/**
 * item #295 (14e vague, retour Chloé) — audit responsive complet :
 * .tpd-modal-row (détail d'un rendez-vous — Contact/Déplacement — ET Mon
 * profil > Informations personnelles/Mon abonnement) est un flex
 * space-between sans aucune protection de débordement sur la valeur — un
 * email ou une adresse un peu longue (une seule "suite" de caractères sans
 * espace) pouvait forcer la ligne plus large que la modale sur un écran de
 * ~375px, débordant hors du cadre au lieu de passer à la ligne. Même
 * traitement que .tpd-table-row .tpd-appt-meta un peu plus haut dans ce
 * fichier (item déjà existant, même cause).
 */
.tpd-modal-row span:last-child { overflow-wrap: anywhere; text-align: right; }
.tpd-modal-row-attachment img { max-width: 120px; max-height: 120px; border-radius: 6px; display: block; }
.tpd-modal-actions { display: flex; gap: 8px; margin-top: 18px; flex-wrap: wrap; }
/* 61e vague — titre de la section "Inscrit(e)s" de la modale formation (voir partial-training-modal.php), même famille que .tpd-modal h3 mais plus discret (sous-titre, pas le titre principal de la modale). */
.tpd-modal-subheading { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--tpd-muted); margin: 16px 0 4px; }

/* Dashboard quick date-range tabs */
.tpd-daterange-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 24px; }
.tpd-daterange-tab {
	padding: 8px 16px;
	border-radius: 6px;
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	color: var(--tpd-muted);
	text-decoration: none;
	font-size: 13px;
}
.tpd-daterange-tab.is-active { background: var(--tpd-ink); color: #fff; border-color: var(--tpd-ink); }

@media (max-width: 900px) {
	.tpd-table-head { display: none; }
	/**
	 * item #312 (15e vague, retour Chloé) — "paiements, fidélité (les
	 * textes se chevauchent)" : sur Paiements, ce retour à une seule
	 * colonne n'avait JAMAIS pu s'appliquer — ".tpd-table--payments
	 * .tpd-table-row" (2 classes, voir plus haut dans ce fichier, hors
	 * media query donc toujours actif) est plus spécifique que le simple
	 * ".tpd-table-row" ci-dessous, et gagne donc TOUJOURS la cascade quel
	 * que soit l'écran : la grille à 9 colonnes (dont une colonne actions
	 * figée à 220px) restait forcée même sur mobile. Combiné à
	 * "min-width: 0" posé sur chaque cellule (voir plus haut, pour
	 * l'email client), les colonnes trop étroites pour leur contenu
	 * (badge de statut, boutons "Acompte payé"/"Marquer payé"/QR) ne
	 * passaient plus à la ligne mais débordaient les unes sur les autres
	 * — d'où le chevauchement de texte. Répéter les 3 sélecteurs
	 * ".tpd-table--*" ici (même spécificité, déclarés après) fait
	 * gagner ce retour à une colonne comme prévu ; corrige au passage le
	 * même bug latent sur Clients et Liste d'attente, qui utilisent la
	 * même mécanique.
	 */
	.tpd-table-row,
	.tpd-table--payments .tpd-table-row,
	.tpd-table--clients .tpd-table-row,
	.tpd-table--waitlist .tpd-table-row,
	.tpd-table--support .tpd-table-row,
	.tpd-table--payment-invoices .tpd-table-row { grid-template-columns: 1fr; gap: 4px; }
	.tpd-table-row span[data-label]::before { content: attr(data-label) ": "; color: var(--tpd-muted); font-size: 11px; }
}

/* Calendar toolbar: view toggle + filter CTA */
.tpd-calendar-toolbar { display: flex; align-items: center; gap: 12px; }
.tpd-view-toggle { display: flex; background: var(--tpd-sand); border-radius: 6px; padding: 3px; }
.tpd-view-toggle-item { padding: 6px 14px; border-radius: 5px; font-size: 13px; text-decoration: none; color: var(--tpd-muted); }
.tpd-view-toggle-item.is-active { background: var(--tpd-paper); color: var(--tpd-ink); box-shadow: 0 1px 2px rgba(0,0,0,0.08); }

/* Week view */
.tpd-week-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
.tpd-week-col { background: var(--tpd-paper); border: 1px solid var(--tpd-line); border-radius: 8px; padding: 10px; min-height: 200px; }
.tpd-week-col.is-today { border-color: var(--tpd-accent); }
.tpd-week-col-header { font-size: 12px; font-weight: 600; margin-bottom: 8px; text-transform: capitalize; }
.tpd-week-empty { font-size: 12px; color: var(--tpd-muted); }
.tpd-week-event {
	display: flex; flex-direction: column; gap: 1px;
	width: 100%; text-align: left;
	background: var(--tpd-sand);
	border: none; border-left: 3px solid var(--tpd-accent);
	border-radius: 4px;
	padding: 6px 8px;
	margin-bottom: 6px;
	font-size: 11px;
	cursor: pointer;
}
.tpd-week-event-service { font-weight: 600; }
.tpd-week-event-client { display: flex; align-items: center; gap: 4px; }
.tpd-week-event-staff { color: var(--tpd-muted); }

/* Day view (timeline) */
.tpd-day-timeline { position: relative; background: var(--tpd-paper); border: 1px solid var(--tpd-line); border-radius: 8px; margin-left: 0; }
.tpd-day-column:first-child .tpd-day-timeline { margin-left: 50px; }
.tpd-day-hour-row { position: absolute; left: 0; width: 100%; height: 60px; border-top: 1px solid var(--tpd-line); }
.tpd-day-column:first-child .tpd-day-hour-row { left: -50px; width: calc(100% + 50px); }
.tpd-day-hour-label { position: absolute; left: 0; top: -8px; font-size: 11px; color: var(--tpd-muted); width: 42px; text-align: right; }
.tpd-day-event {
	position: absolute; left: 8px; right: 8px;
	border: none; border-radius: 6px;
	color: #fff; text-align: left;
	padding: 4px 8px;
	font-size: 12px;
	cursor: pointer;
	overflow: hidden;
}
.tpd-day-event strong { display: block; }
/**
 * 65e vague, retour Chloé — "ajoute le nom de la prestation [...] on voit
 * que l'heure et le nom et prénom du client" : 3e ligne (voir
 * .tpd-day-event-service dans view-calendar.php), même esprit que
 * .tpd-week-event-service ci-dessus (moins pâle que .tpd-month-event-service
 * — ici tout le texte est déjà blanc sur fond coloré, pas noir sur fond
 * pastel) — tronquée avec une ellipse plutôt que de pousser la hauteur du
 * bloc, qui reste calée sur la durée réelle du rendez-vous (un rendez-vous
 * très court peut malgré tout masquer cette ligne par manque de place,
 * `overflow: hidden` sur .tpd-day-event ci-dessus — dégradation discrète,
 * jamais de texte qui déborde du bloc).
 */
.tpd-day-event-service { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: 0.85; font-size: 11px; margin-top: 1px; }

/* Loyalty card */
/* v1.9.4 — Chloé (item #81): "ajoute une photo et une couleur sur la
   carte" — auparavant toujours le même dégradé anthracite fixe, quel que
   soit le site. --tpd-loyalty-card-color est posée en style inline par
   view-loyalty.php (couleur choisie par la prestataire, ou --tpd-ink par
   défaut) ; color-mix() en dérive un dégradé plutôt qu'un aplat brut. Si
   une photo est choisie, view-loyalty.php pose aussi un background-image
   inline (avec un voile sombre pour garder le texte blanc lisible), qui
   prend le dessus sur ce dégradé — les deux personnalisations peuvent donc
   se combiner ou être utilisées seules.
   item #128 — Chloé: "ajoute aussi couleur du texte" — color: #fff était
   fixe, illisible si la couleur de carte choisie est déjà claire.
   --tpd-loyalty-card-text-color, posée en style inline juste à côté de
   --tpd-loyalty-card-color ci-dessus, remplace le blanc figé ; la valeur
   par défaut (#fff) ne change rien pour une carte déjà enregistrée avant
   l'ajout de ce champ. */
/* item #311 (15e vague, retour Chloé) — "la carte fidélité côté client
   doit avoir la même taille que celle côté prestataires" : cette carte vit
   dans .tpd-col-side (flex:1, min-width:300px — largeur variable selon
   l'écran), alors que la carte équivalente de l'espace client (voir
   .tzb-loyalty-card dans templiz-booking/includes/class-tzb-client-
   account.php, structure/polices/tailles volontairement identiques à
   celle-ci) est maintenant plafonnée à 380px. Sans max-width ici, les deux
   cartes resteraient de tailles différentes sur un écran large malgré des
   styles par ailleurs identiques — ajouté pour garantir la même taille des
   deux côtés, quel que soit l'écran. */
.tpd-loyalty-card {
	background: linear-gradient(135deg, var(--tpd-loyalty-card-color, var(--tpd-ink)), color-mix(in srgb, var(--tpd-loyalty-card-color, var(--tpd-ink)) 70%, black));
	color: var(--tpd-loyalty-card-text-color, #fff);
	border-radius: 14px;
	padding: 24px;
	max-width: 380px;
	position: relative;
	overflow: hidden;
}
.tpd-loyalty-card-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 28px; gap: 8px; }
/**
 * item #299 (14e vague, retour Chloé) — audit responsive complet : le nom
 * de l'activité (souvent plus long qu'"Aperçu") + le libellé "Carte
 * fidélité" tenaient sur une seule ligne sans aucune protection — et
 * .tpd-loyalty-card a overflow:hidden (pour ses décors ::before/::after),
 * donc un nom d'activité un peu long se faisait couper net au lieu de
 * passer à la ligne ou de s'afficher en entier, un souci plus visible
 * encore sur la carte réduite en largeur d'un écran mobile. min-width: 0
 * + ellipsis affichent proprement ce qui rentre plutôt qu'une coupe brute
 * en plein milieu d'un mot ; le libellé, court et fixe, ne rétrécit pas.
 */
.tpd-loyalty-card-brand { font-family: 'Bodoni Moda', Georgia, serif; font-size: 15px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tpd-loyalty-card-label { font-size: 11px; opacity: 0.6; text-transform: uppercase; letter-spacing: 0.04em; flex-shrink: 0; }
.tpd-loyalty-card-points { font-family: 'Bodoni Moda', Georgia, serif; font-size: 26px; margin-bottom: 10px; }
.tpd-loyalty-card-points span { font-size: 13px; opacity: 0.7; font-family: 'Work Sans', sans-serif; }
.tpd-loyalty-card-bar { height: 5px; background: rgba(255,255,255,0.15); border-radius: 3px; overflow: hidden; margin-bottom: 14px; }
.tpd-loyalty-card-bar-fill { height: 100%; background: var(--tpd-accent); }
.tpd-loyalty-card-reward { font-size: 12px; opacity: 0.75; margin: 0; }

/* Theme preview mockup */
.tpd-theme-card-wrap { display: flex; flex-direction: column; gap: 6px; }
.tpd-theme-preview-modal { max-width: 480px; }
.tpd-theme-mockup {
	border: 1px solid var(--tpd-line);
	border-radius: 10px;
	overflow: hidden;
	background: var(--mock-paper, #fff);
	color: var(--mock-ink, #14130F);
}
.tpd-theme-mockup-hero { padding: 32px 24px; text-align: center; }
/* v1.9.6 — item #85: was var(--mock-accent) directly — unreadable for
   several palettes (ex. "Jaune") on the white/paper mockup background.
   --mock-accent-text is the same color, contrast-corrected (see
   TSB_Templates::accent_contrast_vars(), mirrored here by dashboard.js). */
.tpd-theme-mockup-kicker { font-size: 12px; color: var(--mock-accent-text, var(--mock-accent, #A08D6B)); display: block; margin-bottom: 8px; }
.tpd-theme-mockup-title { font-family: var(--mock-font-display, 'Bodoni Moda', serif); font-size: 26px; margin: 0 0 8px; }
.tpd-theme-mockup-tagline { font-family: var(--mock-font-body, 'Work Sans', sans-serif); font-size: 13px; opacity: 0.7; margin: 0 0 16px; }
.tpd-theme-mockup-btn { display: inline-block; background: var(--mock-ink, #14130F); color: var(--mock-paper, #fff); padding: 8px 18px; font-size: 12px; border-radius: 4px; }
.tpd-theme-mockup-body { background: var(--mock-sand, #F5F1E8); padding: 16px 24px; }
.tpd-theme-mockup-swatches { display: flex; gap: 8px; margin-bottom: 10px; }
.tpd-theme-mockup-swatch { width: 22px; height: 22px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.1); }
.tpd-theme-mockup-badge {
	display: inline-block;
	background: var(--mock-accent, #A08D6B);
	color: var(--mock-on-accent, #fff);
	padding: 4px 12px;
	border-radius: 999px;
	font-size: 11px;
	margin-bottom: 10px;
}
.tpd-theme-mockup-desc { font-size: 13px; margin: 0; }

/* v1.9.6 — item #85: palette picker — replaces the old plain <select> with
   real color swatches (radio inputs, styled via :has() like the day-picker
   chips elsewhere in this file) so choosing a palette is itself visual. */
.tpd-palette-field { display: flex; flex-direction: column; gap: 6px; flex: 1; }
.tpd-palette-picker { display: flex; flex-wrap: wrap; gap: 10px; }
.tpd-palette-swatch {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	cursor: pointer;
	width: 64px;
}
.tpd-palette-swatch-input { position: absolute; opacity: 0; width: 0; height: 0; }
.tpd-palette-swatch-dot {
	width: 36px;
	height: 36px;
	border-radius: 50%;
	border: 2px solid transparent;
	box-shadow: 0 0 0 1px var(--tpd-line);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 16px;
}
.tpd-palette-swatch:has(.tpd-palette-swatch-input:checked) .tpd-palette-swatch-dot {
	border-color: var(--tpd-ink);
	box-shadow: 0 0 0 1px var(--tpd-ink);
}
.tpd-palette-swatch-dot-custom { background: var(--tpd-sand); }
.tpd-palette-swatch-label { font-size: 11px; text-align: center; line-height: 1.2; opacity: 0.8; }

/* v1.9.6 — item #86: custom colors/fonts + live preview, directly in Mon
   Espace (previously wp-admin only, out of reach for a prestataire). */
.tpd-contrast-warning { color: var(--tpd-danger); font-size: 13px; margin: 10px 0 0; }
.tpd-live-preview-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.tpd-live-preview-status { font-size: 12px; color: var(--tpd-muted); min-height: 1em; }
.tpd-live-preview-iframe {
	width: 100%;
	height: 640px;
	border: 1px solid var(--tpd-line);
	border-radius: 10px;
	background: #fff;
}
@media (max-width: 782px) {
	.tpd-live-preview-iframe { height: 420px; }
}

/* 36e vague, retour Chloé — item 4 : bascule d'aperçu par appareil
   (desktop/tablette/mobile) au-dessus de l'aperçu en direct — voir
   view-minisite.php et dashboard.js ("Aperçu par appareil"). L'iframe elle-
   même ne change jamais de taille : seul son CONTENEUR rétrécit et se
   centre, ce qui force les media queries du site public (base.css) à
   s'appliquer comme sur un vrai appareil de cette largeur. */
.tpd-live-preview-devices { display: flex; gap: 6px; margin-bottom: 12px; }
.tpd-device-toggle {
	padding: 6px 14px;
	border: 1px solid var(--tpd-line);
	border-radius: 999px;
	background: #fff;
	color: var(--tpd-muted);
	font-size: 13px;
	cursor: pointer;
}
.tpd-device-toggle.is-active { background: var(--tpd-ink); color: #fff; border-color: var(--tpd-ink); }
.tpd-live-preview-frame { width: 100%; transition: max-width 0.2s ease; margin: 0 auto; }
.tpd-live-preview-frame[data-device="tablet"] { max-width: 768px; }
.tpd-live-preview-frame[data-device="mobile"] { max-width: 390px; }
.tpd-live-preview-frame[data-device="tablet"] .tpd-live-preview-iframe,
.tpd-live-preview-frame[data-device="mobile"] .tpd-live-preview-iframe { height: 720px; }

/* Onboarding welcome banner */
.tpd-onboarding-banner {
	background: var(--tpd-ink);
	color: #fff;
	border-radius: 12px;
	padding: 24px 28px;
	margin-bottom: 28px;
}
.tpd-onboarding-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.tpd-onboarding-header h2 { font-family: 'Bodoni Moda', Georgia, serif; font-size: 20px; margin: 0 0 4px; }
.tpd-onboarding-header p { font-size: 13px; opacity: 0.75; margin: 0; }
.tpd-onboarding-banner .tpd-btn-ghost { color: #fff; border-color: rgba(255,255,255,0.3); }
/* item #332 (18e vague) — sur ce bandeau sombre, le survol générique de
   ".tpd-btn-ghost" (bordure/texte accent) serait peu lisible : on garde
   blanc, juste la bordure qui s'éclaircit légèrement. */
.tpd-onboarding-banner .tpd-btn-ghost:hover { color: #fff; border-color: rgba(255,255,255,0.6); }
.tpd-onboarding-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
.tpd-onboarding-list li { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.tpd-onboarding-list li a { color: var(--tpd-accent); text-decoration: underline; }
.tpd-onboarding-list li.is-done { opacity: 0.55; }
.tpd-onboarding-icon { width: 18px; }

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

/* item 5 (25e vague, retour Chloé) — rappel discret d'une ligne affiché à
   la place du bandeau complet une fois "Masqué", tant qu'il reste des
   étapes non terminées (voir view-dashboard.php). Même ton sombre que le
   bandeau complet pour rester reconnaissable, mais sans réclamer autant
   de place. */
/* 33e vague, retour Chloé — "quand un prestataire manque ce bloc il peut de
   nouveau l'afficher pour revoir les étapes" : le rappel slim (un seul <a>)
   devient une rangée avec un second contrôle ("Revoir toutes les étapes")
   qui réaffiche le bandeau complet — voir class-tpd-router.php,
   action 'show_onboarding'. margin-bottom déplacé de .tpd-onboarding-slim
   vers la rangée pour garder le même espacement qu'avant l'ajout du bouton. */
.tpd-onboarding-slim-row {
	display: flex;
	align-items: stretch;
	gap: 10px;
	margin-bottom: 28px;
}
.tpd-onboarding-slim {
	display: flex;
	justify-content: space-between;
	align-items: center;
	gap: 12px;
	background: var(--tpd-ink);
	color: #fff;
	border-radius: 10px;
	padding: 12px 18px;
	font-size: 13px;
	text-decoration: none;
	transition: opacity 0.15s ease;
	flex: 1;
	min-width: 0;
}
.tpd-onboarding-slim:hover { opacity: 0.88; color: #fff; }
.tpd-onboarding-slim strong { text-decoration: underline; }
.tpd-onboarding-show-form { display: flex; }
.tpd-onboarding-show-form .tpd-btn {
	height: 100%;
	white-space: nowrap;
	color: #fff;
	border-color: rgba(255,255,255,0.3);
}
.tpd-onboarding-show-form .tpd-btn:hover { color: #fff; border-color: rgba(255,255,255,0.6); }
@media (max-width: 700px) {
	.tpd-onboarding-slim-row { flex-direction: column; }
	.tpd-onboarding-slim { flex-direction: column; align-items: flex-start; gap: 4px; }
}

/* Add-ons marketplace */
.tpd-addon-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 32px; }
.tpd-addon-card { background: var(--tpd-paper); border: 1px solid var(--tpd-line); border-radius: 10px; padding: 22px; display: flex; flex-direction: column; gap: 14px; }
.tpd-addon-card h3 { font-family: 'Bodoni Moda', Georgia, serif; font-size: 17px; margin: 0; }
.tpd-addon-card p { font-size: 13px; color: var(--tpd-muted); margin: 0; flex: 1; }
.tpd-addon-card form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tpd-addon-section-title { font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--tpd-muted); margin: 0 0 14px; }
.tpd-addon-price { font-weight: 600; font-size: 15px; margin: 0 !important; color: var(--tpd-ink) !important; }
@media (max-width: 900px) {
	.tpd-addon-grid { grid-template-columns: 1fr; }
}

/* Support tier banner (Mon profil + Ajouter une option) */
.tpd-support-banner {
	display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap;
	background: var(--tpd-paper); border: 1px solid var(--tpd-line); border-radius: var(--tpd-radius);
	padding: 18px 22px; margin-bottom: 28px;
}

/* Packs — same card as addon cards, with an included-items list */
.tpd-pack-card.is-featured { border-color: var(--tpd-accent); }
.tpd-pack-included { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--tpd-ink); }

/* Client name cell: was overflowing the row before (fixed width + no shrink) */
.tpd-client-name-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; overflow: hidden; }
.tpd-client-name-cell strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; }

/* Form modal (Clients, Prestations, Suppléments, Codes promo, Formations, Équipe) */
.tpd-modal-form { max-width: 560px; width: 92%; position: relative; }
.tpd-modal-form .tpd-modal-close { position: absolute; top: 12px; right: 16px; font-size: 22px; text-decoration: none; color: var(--tpd-muted); }
.tpd-modal-form .tpd-card { border: none; padding: 0; }

/* Pagination */
.tpd-pagination { display: flex; gap: 6px; margin-top: 16px; flex-wrap: wrap; }
.tpd-page-link {
	width: 32px; height: 32px;
	display: flex; align-items: center; justify-content: center;
	border: 1px solid var(--tpd-line);
	border-radius: 6px;
	text-decoration: none;
	color: var(--tpd-ink);
	font-size: 13px;
}
.tpd-page-link.is-active { background: var(--tpd-ink); color: #fff; border-color: var(--tpd-ink); }

/* Onboarding step explanations */
.tpd-onboarding-list li { align-items: flex-start; }
.tpd-onboarding-help { display: block; font-size: 12px; opacity: 0.65; margin-top: 2px; }
.tpd-onboarding-list li.is-done .tpd-onboarding-help { display: none; }

/* Dashboard heatmap graph (Booknetic-style) */
/* 37e vague, retour Chloé — un peu d'air avant le titre "Aujourd'hui" qui
   suit juste en dessous (voir view-dashboard.php), sinon les deux blocs se
   touchaient. */
.tpd-graph-card { margin-top: 8px; margin-bottom: 28px; }
.tpd-graph-header { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.tpd-graph-label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--tpd-muted); }
.tpd-graph-range-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.tpd-graph-range-tab { padding: 6px 12px; border-radius: 6px; font-size: 12px; text-decoration: none; color: var(--tpd-muted); background: var(--tpd-sand); }
.tpd-graph-range-tab.is-active { background: var(--tpd-ink); color: #fff; }

.tpd-heatmap-scroll { overflow-x: auto; padding-bottom: 4px; }
.tpd-heatmap { display: inline-block; min-width: 100%; }
.tpd-heatmap-months { display: flex; gap: 3px; margin-left: 34px; margin-bottom: 4px; }
.tpd-heatmap-month-label { width: 13px; font-size: 11px; color: var(--tpd-muted); flex-shrink: 0; }
.tpd-heatmap-body { display: flex; gap: 6px; }
.tpd-heatmap-weekday-labels { display: flex; flex-direction: column; gap: 3px; width: 28px; flex-shrink: 0; }
.tpd-heatmap-weekday-label { height: 13px; font-size: 10px; color: var(--tpd-muted); line-height: 13px; }
.tpd-heatmap-grid { display: flex; gap: 3px; }
.tpd-heatmap-col { display: flex; flex-direction: column; gap: 3px; }
.tpd-heatmap-cell { width: 13px; height: 13px; border-radius: 3px; background: #EDEAE1; display: block; }
.tpd-heatmap-cell.is-blank { background: transparent; }
.tpd-heatmap-level-0 { background: #EDEAE1; }
.tpd-heatmap-level-1 { background: #C9DCF7; }
.tpd-heatmap-level-2 { background: #8FB6ED; }
.tpd-heatmap-level-3 { background: #4C82D6; }
.tpd-heatmap-level-4 { background: #1E4FA8; }

/* Day view: one column per staff member */
.tpd-day-columns { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; }
.tpd-day-column { flex: 1; min-width: 220px; }
.tpd-day-column-header { font-weight: 600; font-size: 13px; margin-bottom: 8px; text-align: center; padding: 6px; background: var(--tpd-sand); border-radius: 6px; }

/* Digital student card (Mon profil) */
.tpd-student-card {
	position: relative;
	overflow: hidden;
	border-radius: 16px;
	padding: 26px 22px 22px;
	background: linear-gradient(155deg, var(--tpd-ink) 0%, #111111 55%, #2A2823 100%);
	color: #fff;
	min-height: 360px;
	display: flex;
	flex-direction: column;
}
.tpd-student-card::before {
	content: "";
	position: absolute; top: -30px; left: -30px; width: 140px; height: 140px;
	background: repeating-linear-gradient(135deg, var(--tpd-accent) 0 6px, transparent 6px 16px);
	opacity: 0.45;
	-webkit-mask: radial-gradient(circle at top left, black 60%, transparent 61%);
	        mask: radial-gradient(circle at top left, black 60%, transparent 61%);
}
.tpd-student-card::after {
	content: "";
	position: absolute; bottom: -50px; right: -50px; width: 150px; height: 150px;
	border-radius: 50%;
	border: 20px solid var(--tpd-sand);
	opacity: 0.85;
}
.tpd-student-card-top { position: relative; z-index: 1; }
.tpd-student-card-brand { font-family: 'Bodoni Moda', Georgia, serif; font-size: 17px; letter-spacing: 0.02em; }
.tpd-student-card-avatar {
	width: 88px; height: 88px; border-radius: 50%;
	background: rgba(255,255,255,0.08);
	border: 2px solid rgba(255,255,255,0.3);
	margin: 22px auto 16px;
	display: flex; align-items: center; justify-content: center;
	position: relative; z-index: 1;
}
.tpd-student-card-name { font-family: 'Bodoni Moda', Georgia, serif; font-size: 22px; margin: 14px 0 8px; position: relative; z-index: 1; }
.tpd-student-card-detail { font-size: 13px; color: #D8D3C8; margin-bottom: 6px; position: relative; z-index: 1; }
.tpd-student-card-expiry { margin-top: auto; padding-top: 16px; font-size: 12px; color: #A8A29A; position: relative; z-index: 1; }
.tpd-student-card-expiry b { color: #fff; }

/* item #194 (5e vague) — carte "Avis sur Templiz" dans Mon profil. */
.tpd-testimonial-preview { font-family: 'Bodoni Moda', Georgia, serif; font-style: italic; font-size: 15px; line-height: 1.5; color: var(--tpd-ink); margin: 0; padding: 14px 16px; background: var(--tpd-sand); border-radius: 10px; }
/* item #202 (6e lot) — rappel de la note sous la citation (statuts publié/en attente). */
.tpd-testimonial-preview-stars { margin: 8px 0 0; font-size: 15px; letter-spacing: 2px; color: var(--tpd-accent); }

/* item #202 (6e lot) — sélecteur d'étoiles pur CSS pour "Laisser un avis sur
   Templiz" (voir view-profile.php). 5 radios cachées + labels affichés en
   ordre inversé (row-reverse) : l'étoile survolée/cochée et toutes celles
   qui la PRÉCÈDENT visuellement (donc la suivent dans le flux DOM inversé)
   passent en doré via le sélecteur général `~`. */
.tpd-star-rating { display: inline-flex; flex-direction: row-reverse; justify-content: flex-end; gap: 2px; font-size: 26px; line-height: 1; }
.tpd-star-rating input { position: absolute; opacity: 0; width: 0; height: 0; }
.tpd-star-rating label { cursor: pointer; color: var(--tpd-line); transition: color .1s ease; }
.tpd-star-rating input:checked ~ label,
.tpd-star-rating input:hover ~ label,
.tpd-star-rating label:hover,
.tpd-star-rating label:hover ~ label { color: var(--tpd-accent); }

/* Broader responsive pass: tablet + phone */
@media (max-width: 900px) {
	.tpd-month-grid { font-size: 12px; }
	.tpd-week-grid { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
	.tpd-day-columns { flex-wrap: nowrap; }
	.tpd-filter-bar { flex-wrap: wrap; }
	.tpd-filter-bar input, .tpd-filter-bar select { flex: 1 1 140px; }
	/* 30e vague — "Du"/"Au" doivent toujours rester côte à côte : le groupe
	   ne se replie jamais sur lui-même (flex-wrap: nowrap), et chaque champ
	   date reçoit une base plus petite que les 140px génériques ci-dessus
	   (qui les auraient fait déborder à deux sur la même ligne) pour que la
	   paire tienne sur un écran de ~320-375px. */
	.tpd-filter-date-range { flex-wrap: nowrap; gap: 8px; }
	.tpd-filter-date-range label { flex: 1 1 auto; min-width: 0; gap: 4px; }
	.tpd-filter-date-range input[type="date"] { flex: 1 1 100px; min-width: 0; padding: 7px 6px; }
	.tpd-modal { max-width: calc(100vw - 32px); }
	.tpd-calendar-toolbar { flex-wrap: wrap; gap: 8px; }
	.tpd-view-toggle, #tpd-cal-filter-toggle { flex-shrink: 0; }
}

@media (max-width: 700px) {
	.tpd-month-grid { grid-template-columns: repeat(7, minmax(36px, 1fr)); font-size: 10px; }
	.tpd-month-event { font-size: 9px; padding: 1px 3px; }
	.tpd-week-grid { grid-template-columns: 1fr; }
	.tpd-onboarding-list { grid-template-columns: 1fr; }
	.tpd-field-row { flex-direction: column; }
	/* item #123 — once "Valide du" / "au" stack (Codes promo), give "au"
	   some room from "Valide du"'s date box sitting right above it. Safe
	   here specifically because in this stacked layout there's no sibling
	   input to stay aligned with (unlike the row layout above). */
	.tpd-date-range-until { margin-top: 8px; }
	.tpd-day-column { min-width: 180px; }
	.tpd-loyalty-card { padding: 18px; }
	.tpd-service-row, .tpd-table-row { flex-wrap: wrap; }

	/* v0.19.0-proto — "rends toute les pages ... responsive sur tous les
	   appareils" : ces répéteurs (Suppléments, FAQ/témoignages du mini-site,
	   horaires d'équipe) empilaient des colonnes à largeur fixe (70px, 80px,
	   90px, 140px) qui ne laissaient plus assez de place au texte sur un
	   petit téléphone — ils passent en une colonne ici. */
	.tpd-extra-row, .tpd-faq-row, .tpd-testimonial-row, .tpd-variant-row { grid-template-columns: 1fr; }
	.tpd-schedule-row { flex-wrap: wrap; }
	.tpd-schedule-day-label { width: auto; }
}

/* Support tickets (Mon profil + Réseau admin > Templiz > Support) */
.tpd-ticket-list { display: flex; flex-direction: column; gap: 8px; }
.tpd-ticket-row {
	display: flex; justify-content: space-between; align-items: center; gap: 10px;
	padding: 10px 14px; border: 1px solid var(--tpd-line); border-radius: 10px;
	text-decoration: none; color: var(--tpd-ink);
}
.tpd-ticket-row:hover { border-color: var(--tpd-accent); }
.tpd-ticket-subject { font-weight: 600; font-size: 13px; }
.tpd-ticket-thread { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; max-height: 340px; overflow-y: auto; }
.tpd-ticket-msg { border-radius: 10px; padding: 10px 12px; font-size: 13px; }
.tpd-ticket-msg-prestataire { background: var(--tpd-sand); align-self: flex-end; max-width: 85%; }
.tpd-ticket-msg-admin { background: var(--tpd-paper); border: 1px solid var(--tpd-line); align-self: flex-start; max-width: 85%; }
.tpd-ticket-msg-from { font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--tpd-muted); margin-bottom: 4px; }
/* Audit responsive complet (retour Chloé) — même correctif que
   .tpd-message-bubble p plus haut dans ce fichier : white-space: pre-wrap
   seul ne coupe jamais un token sans espace (URL, email, mot très long). */
.tpd-ticket-msg-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.tpd-ticket-msg-at { font-size: 11px; color: var(--tpd-muted); margin-top: 4px; }

/* Nav grouped into sections (menu jugé trop long à plat) */
.tpd-nav-group-label {
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: rgba(255,255,255,0.4);
	padding: 14px 14px 4px;
}
.tpd-nav-group-label:first-child { padding-top: 2px; }

/* Guided tour (bubble tour of the sidebar sections, "Revoir la visite guidée")
   item #117 — round "?" button, replacing the old text link that used to
   sit in the sidebar footer menu.
   item 3 (27e vague, retour Chloé) — d'abord déplacé de position:fixed vers
   .tpd-sidebar-bar (à côté de la cloche/du hamburger), pour ne plus jamais
   être recouvert par la barre de navigation mobile/le bandeau
   d'impersonation.
   item 1 (28e vague, retour Chloé) — nuance apportée : "flotte en bas à
   droite comme avant sur ordinateur et tablette, sur mobile à côté des
   titres de page". Un seul bouton dans le HTML, déplacé entre ces deux
   emplacements par dashboard.js selon la largeur d'écran (voir son
   docblock) — le style de base ci-dessous ne fixe que la FORME (rond, "?"),
   chaque emplacement a sa propre règle juste en dessous, sélectionnée par
   le parent réel du bouton à un instant donné plutôt que par une media
   query seule (dashboard.js et ce fichier utilisent le même seuil 900px). */
.tpd-help-btn {
	border-radius: 50%;
	border: none;
	font-family: 'Bodoni Moda', Georgia, serif;
	font-weight: 700;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	flex-shrink: 0;
	transition: background 0.15s ease;
}
/* Domicile desktop/tablette (>900px) : .tpd-sidebar-actions, dans la barre
   du haut — flottant en position:fixed bas-droite, mêmes valeurs que
   l'ancien .tpd-help-fab d'avant la 27e vague (accent doré, 44px). */
.tpd-sidebar-actions .tpd-help-btn {
	position: fixed;
	right: 24px;
	bottom: 24px;
	width: 44px;
	height: 44px;
	background: var(--tpd-accent);
	color: var(--tpd-ink);
	font-size: 18px;
	box-shadow: 0 6px 18px rgba(0,0,0,0.22);
	z-index: 500;
}
.tpd-sidebar-actions .tpd-help-btn:hover { background: #8D7A5C; }
/* Domicile mobile (<=900px) : déplacé par dashboard.js juste à côté du <h1>
   de la page dans .tpd-page-title-wrap (créé à la volée) — sur le fond
   clair de .tpd-page-header, jamais le même style translucide-sur-fond-
   sombre que .tpd-bell-btn (invisible sur du blanc). Plus petit qu'en
   position flottante : purement décoratif à côté d'un titre, pas un bouton
   d'action isolé qui a besoin d'attirer l'œil. */
.tpd-page-title-wrap {
	display: flex;
	align-items: center;
	gap: 10px;
	min-width: 0;
}
.tpd-page-title-wrap .tpd-help-btn {
	width: 26px;
	height: 26px;
	background: var(--tpd-paper);
	color: var(--tpd-ink);
	border: 1px solid var(--tpd-line);
	font-size: 13px;
}
.tpd-page-title-wrap .tpd-help-btn:hover { background: var(--tpd-sand); }

/* item 6 (26e vague) — .tpd-bottom-nav lui-même (display:none par défaut,
   display:flex dans le @media 900px) a été déplacé plus haut dans ce
   fichier, juste après .tpd-mobile-nav-toggle — voir le docblock à cet
   endroit pour le détail du bug d'ordre de cascade que ce déplacement
   corrige. Seules les règles de style des ÉLÉMENTS à l'intérieur de la
   barre (pas de display à surcharger par media query, donc pas concernées
   par ce bug) restent ici, à leur place naturelle avec le reste des
   composants de la sidebar/du shell. */
.tpd-bottom-nav-item {
	position: relative;
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 4px;
	padding: 9px 4px 8px;
	background: none;
	border: none;
	color: rgba(255,255,255,0.7);
	text-decoration: none;
	font: inherit;
	font-size: 10px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	text-align: center;
	cursor: pointer;
	transition: color 0.15s ease;
}
.tpd-bottom-nav-item svg { width: 22px; height: 22px; }
/* item 2 (27e vague, retour Chloé) — 5e élément "Messages" : simple pastille
   (comme .tpd-nav-badge dans la sidebar, mais sans chiffre — la place est
   trop réduite ici pour un badge texte) positionnée juste au-dessus de
   l'icône, elle-même centrée par le "position: relative" ajouté ci-dessus. */
.tpd-bottom-nav-dot {
	position: absolute;
	top: 6px;
	left: 50%;
	margin-left: 3px;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--tpd-danger);
	border: 1.5px solid var(--tpd-sidebar-bg, var(--tpd-ink));
}
.tpd-bottom-nav-item span { line-height: 1.2; }
.tpd-bottom-nav-item:hover, .tpd-bottom-nav-item.is-active { color: #fff; }
/* item 6 (26e vague) — bouton central "+ Ajouter" mis en avant, même
   couleur d'accent que les autres actions principales (.tpd-btn-primary)
   — c'est un raccourci d'action (ouvre la modale), jamais une page, donc
   jamais d'état ".is-active" sur celui-ci. */
.tpd-bottom-nav-add-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border-radius: 50%;
	background: var(--tpd-accent);
	color: var(--tpd-ink);
	margin-top: -20px;
	box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.tpd-bottom-nav-add-icon svg { width: 18px; height: 18px; }
.tpd-bottom-nav-add:hover .tpd-bottom-nav-add-icon { background: #8D7A5C; }

.tpd-tour-overlay {
	position: fixed;
	inset: 0;
	background: rgba(17,17,17,0.55);
	z-index: 9998;
	pointer-events: none;
}
.tpd-tour-highlight {
	position: relative;
	z-index: 9999;
	box-shadow: 0 0 0 3px var(--tpd-accent);
	border-radius: 6px;
}
.tpd-tour-bubble {
	position: fixed;
	z-index: 10000;
	width: 300px;
	max-width: calc(100vw - 20px);
	background: var(--tpd-paper);
	color: var(--tpd-ink);
	border-radius: var(--tpd-radius);
	box-shadow: 0 12px 32px rgba(0,0,0,0.28);
	padding: 16px 18px;
}
.tpd-tour-step {
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--tpd-accent);
	font-weight: 700;
	margin-bottom: 4px;
}
.tpd-tour-bubble h4 { font-family: 'Bodoni Moda', Georgia, serif; font-size: 16px; margin: 0 0 6px; }
.tpd-tour-bubble p { margin: 0; font-size: 13px; color: var(--tpd-muted); line-height: 1.5; }
.tpd-tour-actions { display: flex; align-items: center; justify-content: space-between; margin-top: 14px; gap: 8px; }
.tpd-tour-nav { display: flex; gap: 6px; }
.tpd-tour-actions .tpd-btn-primary { width: auto; margin-top: 0; }

/* Calendar day-picker (Vacances / Jours spéciaux) */
.tpd-cal { max-width: 320px; }
.tpd-cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.tpd-cal-label { font-family: 'Bodoni Moda', Georgia, serif; font-size: 15px; text-transform: capitalize; }
.tpd-cal-nav {
	background: var(--tpd-sand);
	border: 1px solid var(--tpd-line);
	border-radius: 6px;
	width: 28px;
	height: 28px;
	cursor: pointer;
	font-size: 15px;
	line-height: 1;
	color: var(--tpd-ink);
}
.tpd-cal-nav:hover { background: var(--tpd-line); }
.tpd-cal-weekdays, .tpd-cal-grid {
	display: grid;
	grid-template-columns: repeat(7, 1fr);
	gap: 4px;
}
.tpd-cal-weekdays span { text-align: center; font-size: 11px; color: var(--tpd-muted); text-transform: uppercase; padding-bottom: 4px; }
.tpd-cal-day {
	aspect-ratio: 1;
	border: 1px solid transparent;
	background: var(--tpd-sand);
	border-radius: 6px;
	font-size: 13px;
	color: var(--tpd-ink);
	cursor: pointer;
}
.tpd-cal-day:hover:not(:disabled) { border-color: var(--tpd-accent); }
.tpd-cal-day.is-muted { color: var(--tpd-muted); opacity: 0.45; }
.tpd-cal-day.is-today { font-weight: 700; box-shadow: inset 0 0 0 1px var(--tpd-accent); }
.tpd-cal-day.is-past { opacity: 0.3; cursor: not-allowed; }
.tpd-cal-day.is-selected { background: var(--tpd-accent); color: #fff; }
.tpd-cal-selected-summary { font-size: 13px; color: var(--tpd-muted); margin: 10px 0 0; min-height: 1.2em; }

/* Statistiques (item #146 — option payante) */
.tpd-stats-period-filter { display: flex; gap: 6px; margin-bottom: 20px; flex-wrap: wrap; }
.tpd-stats-period-btn {
	font-size: 12.5px;
	font-weight: 600;
	padding: 7px 14px;
	border-radius: 20px;
	background: var(--tpd-sand);
	border: 1px solid var(--tpd-line);
	color: var(--tpd-ink);
	text-decoration: none;
}
.tpd-stats-period-btn:hover { border-color: var(--tpd-accent); }
.tpd-stats-period-btn.active { background: var(--tpd-ink); color: var(--tpd-paper); border-color: var(--tpd-ink); }

/* item #317 (82e vague) — passé de repeat(5, 1fr) à auto-fit/minmax : avec
   l'ajout de la tuile "Taux de fidélité", le nombre de tuiles KPI n'est plus
   un multiple propre de 5 (7 désormais) — un nombre de colonnes fixe aurait
   laissé une dernière ligne à moitié vide. auto-fit s'adapte automatiquement
   à n'importe quel nombre de tuiles, aujourd'hui comme pour un futur ajout. */
.tpd-stats-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 18px; margin-bottom: 28px; }
.tpd-stats-kpi {
	background: var(--tpd-paper);
	border: 1px solid var(--tpd-line);
	border-radius: var(--tpd-radius);
	padding: 16px 18px;
}
.tpd-stats-kpi .label { font-size: 11.5px; color: var(--tpd-muted); text-transform: uppercase; letter-spacing: .03em; margin-bottom: 6px; }
.tpd-stats-kpi .value { font-family: 'Bodoni Moda', Georgia, serif; font-size: 24px; }
.tpd-stats-kpi.highlight { background: var(--tpd-ink); border-color: var(--tpd-ink); }
.tpd-stats-kpi.highlight .label { color: rgba(255,255,255,.6); }
.tpd-stats-kpi.highlight .value { color: var(--tpd-paper); }
.tpd-stats-kpi.alert .value { color: var(--tpd-danger); }
.tpd-stats-kpi-split span { color: var(--tpd-muted); font-size: 16px; margin: 0 3px; }
@media (max-width: 900px) {
	.tpd-stats-kpis { grid-template-columns: repeat(2, 1fr); }
}

/* item #164 (retour Chloé) — "les blocs sont collés entre eux laisse de
   l'espace" : .tpd-two-col ne pose un gap qu'ENTRE les 2 cartes d'une même
   ligne (côte à côte) — rien n'espaçait une ligne de la suivante quand
   plusieurs .tpd-two-col s'empilent, comme sur cet écran (3 lignes). C'était
   déjà corrigé côté Réseau admin > Templiz > Statistiques (voir
   #tpd-stats-admin-report dans stats-admin.css) mais jamais porté ici, côté
   Mon Espace — d'où la persistance du problème malgré le 1er correctif
   (qui n'avait touché que l'espacement interne des cartes KPI). Scopé à
   .tpd-stats-report pour ne pas modifier .tpd-two-col ailleurs dans Mon
   Espace (Équipe, Suppléments, Formations, etc., une seule ligne chacun). */
.tpd-stats-report .tpd-two-col { margin-bottom: 28px; }
.tpd-stats-report .tpd-two-col:last-child { margin-bottom: 0; }

.tpd-stats-chart { width: 100%; }
.tpd-stats-svg { width: 100%; height: 140px; display: block; }
.tpd-stats-gridline { stroke: var(--tpd-line); stroke-width: 1; stroke-dasharray: 2 3; }
.tpd-stats-chart-labels { display: flex; justify-content: space-between; font-size: 11.5px; color: var(--tpd-muted); margin-top: 10px; }
/* item #178 (4e vague) — un point par jour + infobulle native (voir
   render_line_chart() dans class-tpd-stats.php) ; cursor:pointer signale
   que chaque point est survolable, même si le point visible reste discret. */
.tpd-stats-point, .tpd-stats-svg circle[tabindex] { cursor: pointer; }
.tpd-stats-chart-peak { font-weight: 600; color: var(--tpd-ink); margin: 6px 0 0; font-size: 12.5px; }
.tpd-stats-chart-peak-sep { color: var(--tpd-muted); font-weight: 400; margin: 0 4px; }
/* item #199 (6e vague, retour Chloé) — "améliore la présentation des
   graphiques avec légende pour que les prestataires comprennent" : pastille
   de la couleur du graphique + intitulé de ce qui est tracé, juste au-dessus
   du SVG (voir render_line_chart() dans class-tpd-stats.php). */
.tpd-stats-chart-legend { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--tpd-ink); margin-bottom: 8px; }
.tpd-stats-chart-legend-swatch { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.tpd-stats-chart-legend-label { font-weight: 500; }
.tpd-stats-empty { color: var(--tpd-muted); font-size: 13.5px; text-align: center; padding: 30px 0; }

/* item #164 — "Agrandi un peu « Rendez-vous dans le temps » et « Revenu
   dans le temps »" : uniquement cette ligne (tpd-two-col-charts), cartes et
   graphiques un peu plus grands que les autres blocs Statistiques.
   item #172 — "à agrandir en largeur" : column plutôt que côte à côte, pour
   que chaque carte (et son graphique, width:100% à l'intérieur) profite de
   toute la largeur disponible au lieu de se partager la ligne en deux. */
.tpd-two-col-charts { flex-direction: column; }
.tpd-two-col-charts .tpd-card { padding: 32px; }
.tpd-two-col-charts .tpd-stats-svg { height: 190px; }

/* item #172 (retour Chloé) — "améliore l'onboarding détail chaque blocs" :
   petite bulle d'aide "?" à côté du titre de chaque bloc Statistiques (voir
   TPD_Stats::help_icon()). Pur CSS (:hover/:focus), currentColor pour rester
   lisible aussi bien sur les cartes claires que sur le KPI "Revenu" (fond
   sombre). */
.tpd-stats-kpi .label { display: flex; align-items: center; gap: 4px; }
/* Scopé à .tpd-stats-report (pas .tpd-card h3 tout court) pour ne changer
   aucun autre écran de Mon Espace utilisant déjà des cartes avec <h3>
   (Rendez-vous, Prestations, Équipe...). */
.tpd-stats-report .tpd-card h3 { display: flex; align-items: center; gap: 6px; }
.tpd-stats-help { position: relative; display: inline-flex; }
.tpd-stats-help-icon {
	display: inline-flex; align-items: center; justify-content: center;
	width: 14px; height: 14px; border-radius: 50%;
	border: 1px solid currentColor; color: inherit; opacity: 0.55;
	font-size: 10px; line-height: 1; font-weight: 600; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
	text-transform: none; letter-spacing: 0; cursor: help;
}
.tpd-card h3 .tpd-stats-help-icon { width: 16px; height: 16px; font-size: 11px; }
.tpd-stats-help:hover .tpd-stats-help-icon,
.tpd-stats-help:focus .tpd-stats-help-icon,
.tpd-stats-help:focus-within .tpd-stats-help-icon { opacity: 1; }
.tpd-stats-help-tip {
	position: absolute; z-index: 20; top: calc(100% + 8px); left: 50%; transform: translateX(-50%);
	width: max-content; max-width: 240px;
	background: var(--tpd-ink); color: #fff;
	font-size: 12px; font-weight: 400; text-transform: none; letter-spacing: 0; line-height: 1.4;
	padding: 8px 10px; border-radius: 6px;
	box-shadow: 0 6px 18px rgba(0,0,0,0.18);
	opacity: 0; visibility: hidden; transform: translateX(-50%) translateY(-4px);
	transition: opacity .12s ease, transform .12s ease;
	pointer-events: none;
}
.tpd-stats-help:hover .tpd-stats-help-tip,
.tpd-stats-help:focus .tpd-stats-help-tip,
.tpd-stats-help:focus-within .tpd-stats-help-tip { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
@media (max-width: 480px) {
	.tpd-stats-help-tip { left: 0; transform: translateY(-4px); }
	.tpd-stats-help:hover .tpd-stats-help-tip,
	.tpd-stats-help:focus .tpd-stats-help-tip,
	.tpd-stats-help:focus-within .tpd-stats-help-tip { transform: translateY(0); }
}

/* item #164 — filtre par date personnalisé, à côté des boutons de période
   fixe existants. */
/* Audit responsive complet (retour Chloé) — flex-wrap manquant : les deux
   champs date natifs + le séparateur "–" + le bouton "Appliquer" restaient
   forcés sur une seule ligne, qui dépasse un écran de ~320-375px dès que
   le sélecteur de date natif du téléphone prend sa largeur habituelle. */
.tpd-stats-custom-range { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tpd-stats-custom-range input[type="date"] {
	font-size: 12.5px;
	padding: 6px 8px;
	border-radius: 8px;
	border: 1px solid var(--tpd-line);
	background: var(--tpd-paper);
	color: var(--tpd-ink);
	min-width: 0;
	flex: 1 1 120px;
}
.tpd-stats-custom-range span { color: var(--tpd-muted); font-size: 12.5px; }
.tpd-stats-custom-range .tpd-stats-period-btn { border: none; cursor: pointer; font: inherit; }
.tpd-stats-custom-range.active .tpd-stats-period-btn { background: var(--tpd-ink); color: var(--tpd-paper); }

.tpd-stats-barlist { display: flex; flex-direction: column; gap: 10px; }
.tpd-stats-bar-row { display: grid; grid-template-columns: 120px 1fr auto; align-items: center; gap: 10px; }
.tpd-stats-bar-label { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tpd-stats-bar-track { background: var(--tpd-sand); border-radius: 6px; height: 8px; overflow: hidden; }
.tpd-stats-bar-fill { display: block; height: 100%; background: var(--tpd-accent); border-radius: 6px; }
.tpd-stats-bar-value { font-size: 13px; font-weight: 600; white-space: nowrap; }
.tpd-stats-bar-count { font-weight: 400; color: var(--tpd-muted); }
@media (max-width: 600px) {
	.tpd-stats-bar-row { grid-template-columns: 90px 1fr auto; }
}

.tpd-stats-mini-kpis { display: flex; gap: 18px; flex-wrap: wrap; }
.tpd-stats-mini-kpis > div { display: flex; flex-direction: column; gap: 2px; }
.tpd-stats-mini-kpis .n { font-family: 'Bodoni Moda', Georgia, serif; font-size: 20px; }
.tpd-stats-mini-kpis .l { font-size: 11.5px; color: var(--tpd-muted); }

/**
 * 130e vague, retour Chloé (suite) — "adresse : laisse un espace au dessus
 * pour pas que ça soit coller à déplacement et agrandi la balise de
 * l'adresse" (modale "Ajouter un nouveau rendez-vous", voir
 * partial-add-appt-modal.php). Ce champ vit directement dans
 * .tpd-add-appt-travel-wrap plutôt que dans un <label> comme le reste de ce
 * formulaire (Prénom, Nom...) — c'est justement ce <label> en
 * display:flex;flex-direction:column (".tpd-card label") qui étire les
 * autres champs à la largeur de la carte ; sans lui, ce champ-ci gardait sa
 * largeur intrinsèque de <input type="text"> (~20 caractères), d'où la
 * "petite balise" collée juste sous l'interrupteur. display:block + width
 * 100% règle la taille, margin-top l'espacement — l'attribut HTML "hidden"
 * (voir partial-add-appt-modal.php/dashboard.js) continue de primer tant
 * que "Déplacement à domicile" n'est pas activé, ce style ne joue donc
 * qu'une fois le champ déjà affiché.
 */
.tpd-add-appt-travel-wrap .tpd-add-appt-travel-address {
	display: block;
	width: 100%;
	margin-top: 10px;
}
