        /* 🎨 Identité visuelle CABIVA (indépendante du site public) */
        :root { --color-primary: #00A99D; --color-secondary: #132F55; --sc-navy: #132F55; --sc-navy-dark: #0D1B2A; --sc-teal: #00A99D; --sc-mint: #E6F7F4; --sc-gray: #F2F4F7; }
        * { box-sizing: border-box; }
        html, body { font-family: 'Poppins', 'Outfit', sans-serif; max-width: 100vw; overflow-x: hidden !important; width: 100%; margin: 0; padding: 0; background-color: #F2F4F7; color: #132F55; }
        .font-serif { font-family: 'Poppins', sans-serif !important; font-weight: 700; letter-spacing: -0.02em; }
        /* Onglet actif : forcer la couleur de marque (contourne un conflit d'animation Tailwind CDN) */
        .tab-button.text-primary, .tab-button.text-primary .sidebar-text, .mobile-tab-btn.text-primary { color: var(--color-primary) !important; }

        /* 🌑 Menu latéral en mode sombre (identité CABIVA) */
        #sidebar { background: linear-gradient(180deg, #132F55 0%, #0D1B2A 100%) !important; border-color: rgba(255,255,255,0.08) !important; }
        #sidebar .border-slate-100, #sidebar .border-slate-200 { border-color: rgba(255,255,255,0.08) !important; }
        #sidebar .bg-slate-50\/50 { background-color: rgba(255,255,255,0.03) !important; }
        #sidebar h1.text-slate-800, #sidebar .text-slate-800 { color: #f1f5f9 !important; }
        #sidebar .text-slate-600 { color: #cbd5e1 !important; }
        #sidebar .text-slate-500 { color: #94a3b8 !important; }
        #sidebar .menu-header, #sidebar .text-slate-400 { color: #6b7f9e !important; }
        #sidebar .hover\:bg-slate-50:hover { background-color: rgba(255,255,255,0.07) !important; }
        #sidebar #now-widget { background-color: rgba(0,0,0,0.22) !important; }
        #sidebar #global-search { background-color: rgba(255,255,255,0.06) !important; border-color: rgba(255,255,255,0.1) !important; color: #e2e8f0 !important; }
        #sidebar #global-search::placeholder { color: #64748b !important; }
        #sidebar #global-search:focus { background-color: rgba(255,255,255,0.12) !important; }
        #sidebar #global-search-results { background-color: #0D1B2A !important; border-color: rgba(255,255,255,0.12) !important; }
        #sidebar #global-search-results .border-slate-50 { border-color: rgba(255,255,255,0.06) !important; }
        #sidebar #global-search-results .hover\:bg-primary\/5:hover { background-color: rgba(255,255,255,0.06) !important; }
        /* Logo sidebar (fond sombre) : sans fond, ajusté au conteneur */
        #sidebar #header-logo-img:not(.hidden) { height:3.9rem !important; max-width:230px !important; }
        /* Sidebar réduite (desktop) : logo carré centré, pas de débordement */
        #sidebar.w-20 > div:first-child { padding-left:0 !important; padding-right:0 !important; justify-content:center !important; }
        /* object-contain : le logo est fourni détouré avec ses propres coins
           arrondis — le recadrer (cover) en couperait les bords. */
        #sidebar.w-20 #header-logo-img:not(.hidden) { height:3.25rem !important; width:3.25rem !important; max-width:3.25rem !important; object-fit:contain; }
        /* Menu : texte aligné à gauche (pas centré), plus petit pour ne pas être tronqué */
        #sidebar nav button, #sidebar nav a { font-size:0.8125rem !important; }
        #sidebar nav button > .sidebar-text.truncate, #sidebar nav a > .sidebar-text.truncate { min-width:0; flex:1 1 auto; text-align:left; }
        /* Badges du menu : masqués en mode réduit */
        #sidebar.w-20 .side-badge { display:none !important; }
        .table-container { width: 100%; max-width: 100%; overflow-x: auto; -ms-overflow-style: none; scrollbar-width: none; }
        .table-container::-webkit-scrollbar { display: none; }
        .loader { border-top-color: var(--color-primary); animation: spinner 1.5s linear infinite; }
        @keyframes spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
        ::-webkit-scrollbar { height: 6px; width: 8px; } 
        ::-webkit-scrollbar-track { background: transparent; border-radius: 4px; } 
        ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; } 
        ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
        .toast-enter { transform: translateY(100%); opacity: 0; } 
        .toast-enter-active { transform: translateY(0); opacity: 1; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } 
        .toast-exit { transform: translateY(0); opacity: 1; } 
        .toast-exit-active { transform: translateY(100%); opacity: 0; transition: all 0.3s ease-in; }
        .hide-scroll::-webkit-scrollbar { display: none; } 
        .hide-scroll { -ms-overflow-style: none; scrollbar-width: none; }
        .modal-overlay { transition: opacity 0.3s ease; opacity: 0; pointer-events: none; }
        .modal-overlay.active { opacity: 1; pointer-events: auto; }
        .modal-content { transition: transform 0.3s ease; transform: scale(0.95); }
        .modal-overlay.active .modal-content { transform: scale(1); }
        /* ✖️ Pas de croix de fermeture sur les écrans affichés COMME DES PAGES.
           Un « Nouveau RDV » ou un dossier patient occupe tout l'espace et se
           quitte par le fil d'Ariane : une croix en plus laissait croire à une
           fenêtre superposée et donnait deux façons de faire la même chose.
           Les VRAIES fenêtres (.modal-overlay sans .modal-page — confirmation,
           éditeur, aperçu, import…) gardent la leur : elles n'ont pas de fil
           d'Ariane et la croix y est le seul moyen de sortir. */
        .modal-page button[onclick*="closeModal"] { display: none !important; }

        /* 📄 Fenêtres affichées DANS le flux de la page (comme un onglet agenda/accueil) */
        .modal-page.mp-inline { position:static !important; inset:auto !important; display:block !important; opacity:1 !important; pointer-events:auto !important; background:transparent !important; padding:0 !important; z-index:auto !important; transform:none !important; animation:fadeUp 0.3s cubic-bezier(0.16,1,0.3,1); }
        .modal-page.mp-inline .modal-content { width:100% !important; max-width:100% !important; height:auto !important; max-height:none !important; transform:none !important; margin:0 auto !important; }
        .modal-page.mp-inline:not(#modal-patient-profile) .modal-content { max-width:920px !important; }
        /* Neutraliser les zones à hauteur fixe internes pour que TOUTE la page scrolle */
        .modal-page.mp-inline .overflow-y-auto, .modal-page.mp-inline .overflow-y-scroll { overflow:visible !important; max-height:none !important; }
        @keyframes ping-large { 75%, 100% { transform: scale(2); opacity: 0; } } 
        .animate-ping-large { animation: ping-large 1.5s cubic-bezier(0, 0, 0.2, 1) infinite; }
        input[type=number]::-webkit-inner-spin-button, input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
        
        /* Kanban Styles */
        /* 🩺 Fil des étapes de consultation.
           Il défilait horizontalement avec une barre masquée : la 4ᵉ étape
           « Finalisation » était coupée et inatteignable à la souris. On laisse
           les étapes passer à la ligne — elles restent toutes visibles. */
        #consult-stepper { flex-wrap: wrap !important; overflow: visible !important; row-gap: .375rem; }
        #consult-stepper > * { flex: 0 1 auto; }

        /* 📅 Agenda Global — vues Mois et Semaine.
           FullCalendar tronque le titre d'un événement sur une seule ligne : on
           lisait « 10 h Fatima Zahra… » sans jamais voir le motif ni le numéro.
           On autorise le retour à la ligne et on laisse la case grandir. */
        #global-calendar .fc-daygrid-event,
        #global-calendar .fc-timegrid-event { white-space: normal !important; }
        #global-calendar .fc-event-title,
        #global-calendar .fc-event-title-container { white-space: normal !important; overflow: visible !important; text-overflow: clip !important; line-height: 1.25; }
        #global-calendar .fc-daygrid-event-harness { margin-bottom: 2px; }
        #global-calendar .fc-daygrid-day-frame { min-height: 5.5rem; }
        #global-calendar .fc-daygrid-day-events { font-size: .72rem; }

        .kanban-container { min-height: 150px; padding-bottom: 20px; transition: background-color 0.2s; }
        /* 🖱️ Kanban : la classe hide-scroll masquait la barre de défilement.
           Sur mobile c'est bien (on fait glisser au doigt), mais à la souris il
           ne restait AUCUN moyen d'atteindre les dernières colonnes. On rétablit
           une barre fine sur ordinateur ; la molette est traitée en JS. */
        @media (min-width: 1024px) {
            #agenda-kanban-view { scrollbar-width: thin !important; scrollbar-color: #cbd5e1 transparent; -ms-overflow-style: auto !important; }
            #agenda-kanban-view::-webkit-scrollbar { display: block !important; height: 9px; }
            #agenda-kanban-view::-webkit-scrollbar-track { background: transparent; }
            #agenda-kanban-view::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 999px; }
            #agenda-kanban-view::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
        }
        .kb-card { transition: transform 0.2s, box-shadow 0.2s; cursor: grab; }
        .kb-card:active { cursor: grabbing; }
        .sortable-ghost { opacity: 0.4; background-color: #f1f5f9; border: 2px dashed #cbd5e1; }
        .sortable-drag { transform: scale(1.05); box-shadow: 0 10px 25px rgba(0,0,0,0.1); }
        
        /* FullCalendar Customizations */
        .fc { font-family: 'Outfit', sans-serif; }
        .fc-theme-standard td, .fc-theme-standard th { border-color: #f1f5f9; }
        .fc-col-header-cell { padding: 0.5rem 0; color: #64748b; background-color: #f8fafc; font-size: 0.875rem; }
        .fc-v-event { border-radius: 6px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); border: none !important; border-left: 4px solid rgba(0,0,0,0.2) !important;}
        .fc-v-event:hover { opacity: 0.9; cursor: pointer; }
        .fc-event-main { padding: 2px 4px; }
        .fc-timegrid-slot-label { font-size: 0.75rem; color: #94a3b8; font-weight: 500; }
        .fc .fc-toolbar-title { font-size: 1.1rem; font-weight: bold; color: #1e293b; }
        .fc .fc-button-primary { background-color: var(--color-primary); border-color: var(--color-primary); text-transform: capitalize; font-weight: bold; }
        .fc .fc-button-primary:hover { opacity: 0.9; background-color: var(--color-primary); border-color: var(--color-primary); }
        .fc .fc-scroller { -webkit-overflow-scrolling: touch; }
        .fc-event-title { font-weight: 700 !important; font-size: 0.8rem !important; line-height: 1.25 !important; }
        .fc-event-time { font-weight: 600 !important; font-size: 0.72rem !important; }
        .fc .fc-timegrid-slot { height: 2.2em; }

        /* FullCalendar Mobile (Agenda Global) */
        @media (max-width: 767px) {
            .fc .fc-toolbar.fc-header-toolbar { flex-direction: column; align-items: stretch; gap: 0.5rem; margin-bottom: 0.75rem; }
            .fc .fc-toolbar-chunk { display: flex; justify-content: center; flex-wrap: wrap; gap: 0.25rem; }
            .fc .fc-toolbar-title { font-size: 1rem; text-align: center; }
            .fc .fc-button { padding: 0.35rem 0.6rem; font-size: 0.75rem; }
            .fc .fc-col-header-cell { font-size: 0.7rem; padding: 0.25rem 0; }
            .fc-timegrid-slot-label { font-size: 0.65rem; }
            .fc .fc-event-main { font-size: 0.7rem; padding: 1px 2px; }
            .fc .fc-daygrid-day-number, .fc .fc-daygrid-event { font-size: 0.7rem; }
            #global-calendar, #daily-calendar { min-height: 450px; }
            #tab-calendrier .bg-white { padding: 0.75rem; }
        }

        /* ✨ Skeleton loaders (shimmer) */
        @keyframes shimmer { 0% { background-position: -800px 0; } 100% { background-position: 800px 0; } }
        .skeleton { background: linear-gradient(90deg, #eef2f7 25%, #f8fafc 50%, #eef2f7 75%); background-size: 800px 100%; animation: shimmer 1.4s infinite linear; border-radius: 10px; }

        /* ✨ Transitions & micro-animations */
        .tab-content:not(.hidden) { animation: fadeUp 0.35s cubic-bezier(0.16,1,0.3,1); }
        @keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
        .kb-card { animation: fadeUp 0.3s ease both; }
        .stat-card { transition: transform 0.2s ease, box-shadow 0.2s ease; }
        .stat-card:hover { transform: translateY(-3px); box-shadow: 0 12px 24px -8px rgba(15,23,42,0.15); }
        #fab-btn { transition: transform 0.2s ease, box-shadow 0.2s ease; }


        /* ═══════════════════════════════════════════════════════════════
           ✨ AFFINAGE VISUEL — « surfaces plates »
           Refonte de la FORME uniquement : mêmes couleurs d'identité
           (#00A99D / #132F55 / #0D1B2A / #F2F4F7), même contenu, mêmes
           fonctions. Le menu latéral sombre est CONSERVÉ (choix du cabinet).
           Principe : remplacer les ombres portées par des filets fins.
           Les ombres empilées créaient un bruit visuel sur un écran
           consulté toute la journée ; un filet de 1px sépare aussi bien
           et laisse le regard se poser sur les chiffres.
           ═══════════════════════════════════════════════════════════════ */

        /* 1. Cartes plates : filet au lieu d'ombre */
        #main-scroll .shadow-sm,
        #main-scroll .shadow-md,
        #main-scroll .shadow-lg,
        #main-scroll .shadow-xl,
        #main-scroll .shadow-2xl { box-shadow: none !important; }
        #main-scroll .bg-white.border,
        #main-scroll .bg-white.rounded-2xl,
        #main-scroll .bg-white.rounded-xl { border: 1px solid #e6eaf0 !important; }

        /* 2. Rayons unifiés : plus calmes, moins « bulle » */
        #main-scroll .rounded-3xl { border-radius: 1rem !important; }
        #main-scroll .rounded-2xl { border-radius: 0.875rem !important; }

        /* 3. En-tête : filet net plutôt qu'une ombre diffuse */
        header.bg-white, #breadcrumb-bar { box-shadow: none !important; border-bottom: 1px solid #e6eaf0 !important; }

        /* 4. Cartes de statistiques : le chiffre devient le héros */
        #main-scroll .stat-card { transition: border-color .15s ease, transform .15s ease; }
        #main-scroll .stat-card:hover { border-color: var(--sc-teal) !important; transform: translateY(-1px); }
        #main-scroll .stat-card p.uppercase { letter-spacing: .06em; font-weight: 600; color: #94a3b8 !important; }
        #main-scroll .stat-card h3 { font-weight: 700; letter-spacing: -.02em; }

        /* 5. Tableaux : en-tête discret, lignes plus aérées */
        #main-scroll thead tr { background: #fafbfc !important; }
        #main-scroll thead th { font-weight: 600 !important; letter-spacing: .05em; color: #8494a8 !important; border-bottom: 1px solid #e6eaf0 !important; }
        #main-scroll tbody tr { transition: background-color .12s ease; }
        #main-scroll tbody tr:hover { background-color: #f7f9fb !important; }

        /* 6. Champs de saisie : bordure plus douce, focus net à la marque */
        #main-scroll input:not([type=color]):not([type=checkbox]),
        #main-scroll select, #main-scroll textarea {
            border-color: #dfe5ec !important; transition: border-color .15s ease, box-shadow .15s ease;
        }
        #main-scroll input:not([type=color]):not([type=checkbox]):focus,
        #main-scroll select:focus, #main-scroll textarea:focus {
            border-color: var(--sc-teal) !important; box-shadow: 0 0 0 3px rgba(0,169,157,.12) !important; outline: none;
        }

        /* 7. Boutons : appui tactile plus lisible, sans ombre colorée */
        #main-scroll button { transition: filter .15s ease, transform .12s ease, background-color .15s ease; }
        #main-scroll button:active { transform: scale(.985); }

        /* 8. Menu latéral CONSERVÉ sombre — état actif plus lisible
              (barre d'accent à gauche au lieu d'un simple changement de teinte) */
        #sidebar .tab-button, #sidebar .side-action { position: relative; border-radius: .625rem !important; }
        #sidebar .tab-button.text-primary { background-color: rgba(0,169,157,.14) !important; }
        #sidebar .tab-button.text-primary::before {
            content: ''; position: absolute; left: 0; top: 18%; bottom: 18%; width: 3px;
            border-radius: 0 3px 3px 0; background: var(--sc-teal);
        }
        #sidebar nav { gap: .125rem; }
        #sidebar .menu-header { font-size: .625rem !important; letter-spacing: .12em; margin-top: .25rem; }

        /* 9. Onglets du dossier patient : soulignement au lieu d'une pastille pleine */
        .pt-tab-btn { border-radius: .5rem !important; }

        /* 10. Bouton flottant : plus discret au repos */
        #fab-btn { box-shadow: 0 4px 14px rgba(0,169,157,.35) !important; }

        /* ═══════════════════════════════════════════════════════════════
           📱 BARRES DE FILTRES — anti-chevauchement (mobile / tablette / PC)
           Les barres empilaient des champs à largeur fixe : sur petit écran
           ils se chevauchaient, sur tablette ils débordaient de la carte.
           Règle unique : tout élément de filtre peut rétrécir (min-width:0)
           et passe à la ligne proprement.
           ═══════════════════════════════════════════════════════════════ */
        .filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; width: 100%; min-width: 0; }
        .filter-bar > * { min-width: 0; }
        .filter-bar input[type="text"],
        .filter-bar input[type="search"] { flex: 1 1 12rem; min-width: 0; }
        .filter-bar input[type="date"] { flex: 0 1 9.5rem; min-width: 0; }
        .filter-bar select { flex: 0 1 11rem; min-width: 0; }
        .filter-bar button { flex: 0 0 auto; }

        /* Les conteneurs de filtres existants héritent du même comportement */
        #tab-rdv .flex.flex-wrap, #tab-crm .flex.flex-wrap,
        #tab-facturation .flex.flex-wrap, #tab-stock .flex.flex-wrap { min-width: 0; }
        #tab-rdv input, #tab-rdv select,
        #tab-crm input, #tab-crm select,
        #tab-facturation input, #tab-facturation select,
        #tab-stock input, #tab-stock select { min-width: 0; max-width: 100%; }

        @media (max-width: 640px) {
            /* Mobile : les champs occupent toute la largeur, les boutons se partagent la ligne */
            #tab-rdv input[type="text"], #tab-crm input[type="text"],
            #tab-facturation input[type="text"], #tab-stock input[type="text"] { flex: 1 1 100%; }
            #tab-rdv input[type="date"], #tab-facturation input[type="date"] { flex: 1 1 calc(50% - .25rem); }
            #tab-rdv select, #tab-crm select, #tab-facturation select, #tab-stock select { flex: 1 1 100%; }
            /* Les groupes de boutons d'action ne débordent plus */
            #tab-facturation .flex.gap-2, #tab-rdv .flex.gap-2 { flex-wrap: wrap; }
            #tab-facturation .flex.gap-2 > button, #tab-rdv .flex.gap-2 > button { flex: 1 1 auto; }
        }
        @media (min-width: 641px) and (max-width: 1024px) {
            /* Tablette : deux colonnes de filtres, jamais de débordement */
            #tab-rdv input[type="text"], #tab-crm input[type="text"],
            #tab-facturation input[type="text"] { flex: 1 1 16rem; }
        }

        /* ═══════════════════════════════════════════════════════════════
           🩹 LE LISERÉ AU-DESSUS DES BARRES COLLANTES
           ═══════════════════════════════════════════════════════════════
           ⚠️ MESURÉ : dans « Contrôle Site », une bande de contenu défilait
           VISIBLEMENT au-dessus de la barre « Contrôle du Site (CMS) », qui est
           pourtant censée tout recouvrir. Relevé : le conteneur `#main-scroll`
           commençait à y = 149, la barre collait à y = 181 — 32 px trop bas.

           La cause n'est pas un z-index : `#main-scroll` porte `p-4 md:p-8`, et
           un élément `position: sticky; top: 0` se fixe au bord de la BOÎTE DE
           PADDING, pas au bord visible du conteneur. Il reste donc, en haut, une
           bande de la hauteur exacte du padding où le contenu passe à découvert.

           Remonter la barre (`top: -2rem`) la rendrait plus haute au repos ;
           retirer le padding du conteneur décalerait les neuf autres sections.
           On peint donc la bande, et rien d'autre : un `::before` solidaire de
           la barre, de la couleur du fond (`#f8fafc`, celle de `<main>`). Au
           repos il recouvre du padding de même teinte — invisible ; collé, il
           masque le contenu qui glisse dessous. Aucun décalage de mise en page.

           ⚠️ Vaut pour les QUATRE barres collantes : Tous les RDV, Patients,
           Contrôle Site et Facturation. Le défaut leur était commun.
           ═══════════════════════════════════════════════════════════════ */
        #main-scroll .sticky.top-0::before {
            content: '';
            position: absolute;
            left: 0; right: 0;
            bottom: 100%;
            height: 1rem;              /* = p-4 du conteneur */
            background: #f8fafc;       /* = bg-[#f8fafc] de <main> */
            pointer-events: none;
        }
        @media (min-width: 768px) {
            #main-scroll .sticky.top-0::before { height: 2rem; }   /* = md:p-8 */
        }

        /* ═══════════════════════════════════════════════════════════════
           💾 LA BARRE D'ENREGISTREMENT DU CMS, EN BAS
           ═══════════════════════════════════════════════════════════════
           Déplacée du haut vers le bas : en haut elle disputait son rang aux
           menus déroulants de la barre supérieure (§ 9.21) et mangeait la
           première ligne utile de l'écran. En bas, elle ne croise plus rien de
           ce qui descend du haut, et le bouton tombe sous la main.

           ⚠️ MÊME PIÈGE QU'EN § 9.20, PAR L'AUTRE BOUT.
           `sticky; bottom: 0` se fixe au bord de la boîte de PADDING. Le
           conteneur ayant `p-4 md:p-8`, la barre s'arrêtait 32 px au-dessus du
           bas visible — et dans cette bande, le contenu défilait sous elle.
           Mesuré : 32 px, un titre de section visible dedans.

           J'avais d'abord écrit l'inverse, en croyant que le bas du conteneur
           n'était que du padding donc vide. Faux : le `padding-bottom` n'est
           atteint qu'en FIN de défilement ; partout ailleurs ce sont des pixels
           de contenu. On annule donc le padding par un `bottom` négatif — la
           barre se colle au bas RÉEL — plutôt que de repeindre une bande.

           ⚠️ LE BOUTON D'ACTION FLOTTANT OCCUPE LES 76 PX DE DROITE.
           Mesuré : il s'étendait de 824 à 880 px, par-dessus « Enregistrer »
           (695-835). Il est `fixed` en z-45, la barre est en z-10 : il gagnera
           toujours. On lui réserve donc la place au lieu de se disputer le rang.
           ═══════════════════════════════════════════════════════════════ */
        /*  ⚠️ L'OFFSET N'EST PAS LE MÊME AUX DEUX LARGEURS, ET CE N'EST PAS
            UNE COQUETTERIE. Le conteneur porte `p-4 md:p-8 pb-24` :
              • sous 768 px, `pb-24` l'emporte      → padding-bottom = 96 px ;
              • au-delà, `md:p-8` passe après lui   → padding-bottom = 32 px.
            Mesuré aux deux tailles. Avoir supposé 16 px en mobile laissait le
            contenu défiler sur 80 px sous la barre. */
        #tab-cms > .sticky.bottom-0 {
            bottom: -6rem;                      /* = pb-24 du conteneur, en mobile */
            padding-right: 5rem;                /* dégage le bouton d'action flottant */
            border-bottom-left-radius: 0;       /* collée au bord : plus d'arrondi bas */
            border-bottom-right-radius: 0;
        }
        @media (min-width: 768px) {
            #tab-cms > .sticky.bottom-0 { bottom: -2rem; }   /* = md:p-8 */
        }

        /* ═══════════════════════════════════════════════════════════════
           📱 BARRE DU HAUT — deux boutons sortaient de l'écran
           ═══════════════════════════════════════════════════════════════
           ⚠️ MESURÉ, pas supposé : sur un écran de 375 px, le groupe de droite
           s'étendait jusqu'à x = 434. Le journal d'activité et le bouton
           d'actualisation étaient donc ENTIÈREMENT hors cadre, et impossibles à
           toucher. Rien ne le signalait — pas de coupure visible, pas de
           défilement horizontal (la page est bornée par `max-w-[100vw]`).

           La cause : le groupe de droite est `shrink-0`, à juste titre — des
           icônes écrasées ne se touchent plus. Le bloc de gauche, lui, aurait dû
           céder la place. Il ne le faisait pas : un élément flex a
           `min-width: auto` par défaut, ce qui l'empêche de descendre sous la
           largeur de son contenu. Le `truncate` posé sur le titre ne servait
           donc jamais. Une seule déclaration débloque tout.

           (J'ai ajouté le bouton « ? » des visites guidées dans cette barre :
           40 px de plus. Le débordement lui préexistait, mais il l'a aggravé.)
           ═══════════════════════════════════════════════════════════════ */
        @media (max-width: 767px) {
            header > div:first-child { min-width: 0; flex: 1 1 auto; }
            /* Un peu d'air rendu au titre : 8 px × 5 intervalles. */
            header > div:last-child { gap: .25rem; }
            /*  ⚠️ Et le logo doit RÉTRÉCIR, pas être coupé.
                Il porte `max-w-[165px]`, plus large que le cadre une fois celui-ci
                réduit : il débordait donc et se faisait trancher en plein mot par
                l'`overflow` du titre. Un logo tronqué passe pour un affichage
                cassé. Avec `max-width: 100%`, `object-contain` le met à l'échelle
                à l'intérieur de la place disponible, entier.                     */
            #mobile-header-logo { max-width: 100%; }
        }

        /* ═══════════════════════════════════════════════════════════════
           👤 DOSSIER PATIENT — barre d'actions en icônes sur mobile
           Les libellés faisaient déborder la barre ; l'icône suffit,
           le libellé reste accessible via l'attribut title.
           ═══════════════════════════════════════════════════════════════ */
        @media (max-width: 640px) {
            #prof-actions .act-label { display: none; }
            #prof-actions button, #prof-actions a {
                width: 2.75rem; height: 2.75rem; padding: 0 !important;
                display: inline-flex; align-items: center; justify-content: center;
                gap: 0 !important; border-radius: .75rem;
            }
            #prof-actions { gap: .5rem; flex-wrap: wrap; }
            #prof-actions i { margin: 0 !important; font-size: 1.05rem; }
        }

        /* ── Correctif ciblé : chevauchement filtres ↔ boutons ──────────────
           Les barres sont construites en « groupe de filtres (flex-1) + groupe
           de boutons (shrink-0) ». Les encadrés de dates n'avaient pas de
           min-width:0 : leur largeur intrinsèque débordait du groupe filtres et
           venait se superposer aux boutons. On autorise le rétrécissement, et
           sous 640 px chaque groupe occupe sa propre ligne. */
        #tab-facturation .flex.flex-wrap > div,
        #tab-rdv .flex.flex-wrap > div,
        #tab-stock .flex.flex-wrap > div,
        #tab-crm .flex.flex-wrap > div { min-width: 0; }

        #tab-facturation input[type="date"],
        #tab-rdv input[type="date"] { min-width: 0; width: 100%; }

        @media (max-width: 767px) {
            /* Groupe de boutons : passe sous les filtres au lieu de les chevaucher */
            #tab-facturation .flex.gap-2.shrink-0,
            #tab-rdv .flex.gap-2.shrink-0,
            #tab-crm .flex.gap-2.shrink-0,
            #tab-stock .flex.gap-2.shrink-0 {
                flex: 1 0 100% !important; flex-wrap: wrap; margin-top: .25rem;
            }
            #tab-facturation .flex.gap-2.shrink-0 > *,
            #tab-rdv .flex.gap-2.shrink-0 > * { flex: 1 1 auto; justify-content: center; }
            /* Les deux encadrés de dates se partagent la ligne */
            #tab-facturation .flex.flex-wrap.gap-2 > div:has(input[type="date"]) { flex: 1 1 calc(50% - .5rem); }
        }

        /* ═══════════════════════════════════════════════════════════════
           📱 COHÉRENCE MOBILE DES BARRES D'ACTIONS
           Sur téléphone, trois zones se comportaient différemment :
             • la barre d'actions du dossier laissait WhatsApp (ml-auto) tomber
               seul sur une 2ᵉ ligne, avec un grand vide à gauche ;
             • le bouton « réinitialiser » restait un carré de 42 px orphelin
               sur sa propre ligne, sous des champs pleine largeur ;
             • l'export apparaissait tantôt seul, tantôt avec un autre bouton.
           Règle unique : en dessous de 768 px, un contrôle occupe toute la
           largeur OU partage sa ligne à parts égales. Jamais d'orphelin.
           ═══════════════════════════════════════════════════════════════ */
        @media (max-width: 767px) {
            /*  Barre d'actions du dossier.
                ⚠️ CETTE RÈGLE A VIEILLI ET COUPAIT DES BOUTONS.
                Écrite pour six icônes, elle les forçait sur UNE ligne
                (`grid-auto-flow: column`) sans débordement (`overflow: visible`).
                La barre en compte huit aujourd'hui : mesuré sur un écran de
                375 px, il fallait 410 px pour 335 disponibles — les deux
                derniers boutons, dont l'envoi WhatsApp, étaient hors cadre et
                impossibles à toucher. Rien ne le signalait : pas de barre de
                défilement, pas de coupure visible.
                On passe donc à quatre par rangée, qui se partagent la largeur :
                huit boutons font deux rangées pleines, et aucun ne sort.
                ⚠️ `width: auto` sans `!important` perdait contre la règle
                `#prof-actions button { width: 2.75rem }` ci-dessus, plus
                spécifique — c'est elle qui provoquait le débordement.          */
            #prof-actions {
                display: flex; flex-wrap: wrap; align-content: flex-start;
                gap: .375rem; overflow: visible;
            }
            #prof-actions > * {
                margin-left: 0 !important; min-width: 0;
                flex: 1 1 calc(25% - .375rem); width: auto !important;
                display: inline-flex; align-items: center; justify-content: center;
                padding-left: 0; padding-right: 0;
            }
            /* Zones de filtres : chaque champ pleine largeur, actions à parts égales.
               ⚠️ Sélecteurs volontairement doublés : Tailwind est injecté APRÈS
               cette feuille, donc à spécificité égale (.flex) c'est lui qui
               gagnerait et `display: grid` serait ignoré. */
            .zone-filtres > div { width: 100%; }
            /* Sans flex-wrap, les champs ne peuvent pas descendre : ils se font
               écraser (le select du stock tombait à 26 px, réduit à sa flèche). */
            .zone-filtres .zone-filtres-champs { flex-wrap: wrap !important; }
            .zone-filtres .zone-filtres-champs > * { width: 100% !important; max-width: none; flex: 0 0 100%; }
            .zone-filtres .zone-filtres-reset { display: flex !important; align-items: center; justify-content: center; }
            /* Classe réutilisable : toute barre de boutons qui laisserait un
               orphelin sur une 2ᵉ ligne. Sert aussi à la barre d'outils de la
               synthèse (Focus / Renouveler / Actualiser / Imprimer). */
            .zone-filtres-actions {
                /* auto-fit plutôt qu'un nombre fixe de colonnes : le plancher de
                   8rem empêche d'écraser un libellé comme « Renouveler », et
                   auto-fit fait disparaître les colonnes vides — un bouton seul
                   occupe donc toute la largeur au lieu de rester à un quart. */
                display: grid !important;
                grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr));
                gap: .5rem;
                /* Sinon la barre partage sa ligne avec le titre voisin et se
                   retrouve écrasée à ~112 px (cas de la synthèse du dossier). */
                width: 100%; flex-basis: 100%;
            }
            /* :not([style*="none"]) — sans cette exclusion, le !important
               réaffichait les boutons que les permissions viennent de masquer
               (la secrétaire revoyait « Importer » alors qu'elle n'y a pas droit). */
            .zone-filtres-actions > *:not([style*="none"]) {
                display: inline-flex !important; align-items: center; justify-content: center;
                min-width: 0; padding-left: .5rem; padding-right: .5rem;
            }
            /* Libellés toujours affichés : deux boutons partageant une ligne
               laissent assez de place, et une icône seule est ambiguë. */
            .zone-filtres-actions > * > span { white-space: nowrap; }

            /* Pagination : « Total » et les trois boutons se disputaient une
               seule ligne — « Suivant » finissait sous le bouton flottant « + ».
               On empile, puis on réserve la hauteur du bouton flottant. */
            .zone-pagination {
                flex-direction: column; align-items: stretch; gap: .5rem;
                padding-bottom: 5rem;
            }
            .zone-pagination > span { text-align: center; }
            .zone-pagination > div {
                display: grid !important; grid-auto-flow: column;
                grid-auto-columns: 1fr; gap: .5rem;
            }
            .zone-pagination > div > * { text-align: center; white-space: nowrap; }
        }

        /* Sur ordinateur, les champs sans classe de largeur (date, select)
           s'étiraient sur toute la ligne et repoussaient les suivants : les
           filtres s'empilaient sur trois lignes au lieu d'une. On les ramène à
           leur largeur naturelle. */
        @media (min-width: 768px) {
            /* !important : Tailwind est injecté après cette feuille et marque
               ses utilitaires en !important — sans cela la largeur est ignorée. */
            .zone-filtres-champs > input,
            .zone-filtres-champs > select { width: auto !important; min-width: 9rem; }
        }

        /* ═══════════════════════════════════════════════════════════════
           👤 DOSSIER PATIENT — 2 colonnes (ordinateur) · accordéon (mobile)
           ═══════════════════════════════════════════════════════════════ */
        #pt-layout { display: block; }
        #pt-side { display: none; }
        .pt-acc-head { display: none; }

        /* ── Ordinateur : colonne de contexte fixe à droite ── */
        @media (min-width: 1024px) {
            #pt-layout { display: grid; grid-template-columns: minmax(0, 1fr) 19rem; gap: 1rem; align-items: start; }
            #pt-main { min-width: 0; }
            #pt-side { display: block; }
            #pt-side > div { position: sticky; top: .5rem; }

            /* La barre d'onglets n'existe QUE sur ordinateur (le mobile utilise
               l'accordéon) : un défilement horizontal n'y a donc aucun sens —
               à la souris il oblige à un glissé maladroit et les derniers
               onglets restaient invisibles. On passe en lignes : les 8 sections
               sont toutes atteignables d'un seul clic, sans rien faire défiler. */
            #pt-tabbar { flex-wrap: wrap; overflow: visible; gap: .25rem; }
            /* Base à 25 % => 4 par ligne, donc 4+4 pour les 8 sections du Docteur.
               flex-grow à 0 : quand le rôle en masque (Secrétaire n'en garde que
               deux), les restants gardent leur largeur au lieu de s'étirer sur
               toute la barre. */
            #pt-tabbar .pt-tab-btn {
                /* 25 % sur un grand écran (=> 4 par ligne), mais jamais moins de
                   9rem : sur un 1024 px la colonne ne fait que ~330 px et un
                   quart tronquerait « Historique ». En dessous, on passe
                   naturellement à 2 par ligne. */
                flex: 0 1 max(9rem, calc(25% - .25rem)); min-width: 0;
                display: inline-flex; align-items: center; justify-content: center; gap: .35rem;
            }
        }

        /* ── Mobile & tablette : accordéon vertical, plus de défilement latéral ── */
        @media (max-width: 1023px) {
            #pt-tabbar { display: none; }
            .pt-acc-head {
                display: flex; align-items: center; justify-content: space-between;
                width: 100%; margin-top: .5rem; padding: .75rem 1rem;
                background: #fff; border: 1px solid #e6eaf0; border-radius: .75rem;
                font-size: .8125rem; font-weight: 700; color: #475569;
                transition: background-color .15s ease, color .15s ease;
            }
            .pt-acc-head .pt-acc-chev { font-size: .7rem; transition: transform .2s ease; color: #94a3b8; }
            .pt-acc-head.is-open {
                background: var(--sc-teal); color: #fff; border-color: var(--sc-teal);
                border-bottom-left-radius: 0; border-bottom-right-radius: 0; margin-bottom: 0;
            }
            .pt-acc-head.is-open .pt-acc-chev { transform: rotate(180deg); color: #fff; }
            /* La section ouverte se raccorde visuellement à son en-tête */
            .pt-tab-content:not(.hidden) {
                border: 1px solid var(--sc-teal); border-top: 0;
                border-radius: 0 0 .75rem .75rem; padding: .875rem; background: #fff;
            }
        }

        /* ═══════════════════════════════════════════════════════════════
           👥 PAGE PATIENTS — mise en page mobile
           L'en-tête « Campagne Promotionnelle » empilait deux boutons pleine
           largeur au-dessus des filtres : le tableau était repoussé sous la
           ligne de flottaison. Sur mobile on compacte l'en-tête et on met les
           deux actions côte à côte.
           ═══════════════════════════════════════════════════════════════ */
        @media (max-width: 767px) {
            #tab-crm .bg-slate-50.p-4,
            #tab-crm .bg-slate-50.p-5 { padding: .75rem !important; }
            /* Titre + sous-titre de la campagne : plus compacts */
            #tab-crm h4 { font-size: .8125rem !important; }
            #tab-crm h4 + p { font-size: .6875rem !important; margin-top: .125rem !important; }
            /* Les deux boutons partagent la ligne au lieu de s'empiler */
            #tab-crm .flex.flex-wrap.gap-2.justify-center { flex-wrap: nowrap !important; gap: .5rem; width: 100%; }
            #tab-crm .flex.flex-wrap.gap-2.justify-center > button {
                flex: 1 1 0; min-width: 0; padding-left: .5rem !important; padding-right: .5rem !important;
                font-size: .6875rem !important; white-space: normal; line-height: 1.15;
            }
            #tab-crm .flex.flex-wrap.gap-2.justify-center > button i { margin-right: .25rem !important; }
            /* Filtres : recherche et ville sur une ligne, actions à droite */
            #tab-crm input[type="text"] { flex: 1 1 100% !important; }
            #tab-crm .px-4.py-4 { padding: .625rem .75rem !important; }
            /* Le tableau des patients devient lisible sans zoom */
            #tab-crm table { font-size: .8125rem; }
            #tab-crm #all-crm-body td { padding-top: .625rem !important; padding-bottom: .625rem !important; }
        }

        /* Mobile : supprimer le défilement imbriqué des tableaux.
           Le conteneur était limité en hauteur (184 px pour 917 px de contenu) :
           l'utilisateur devait faire défiler DANS le tableau, à l'intérieur de la
           page qui défile déjà. Sur petit écran, la page défile d'un seul bloc. */
        @media (max-width: 767px) {
            #tab-crm .table-container,
            #tab-rdv .table-container,
            #tab-facturation .table-container { overflow-y: visible !important; flex: none !important; height: auto !important; }
            #tab-crm .tab-content, #tab-crm > div { height: auto !important; min-height: 0 !important; }
            #tab-crm, #tab-rdv, #tab-facturation { height: auto !important; }
            /* Les deux boutons d'outils des filtres se placent côte à côte */
            #tab-crm .px-4.py-4 > .flex.gap-2,
            #tab-crm .px-4.py-4 > button { display: inline-flex; }
            #tab-crm .px-4.py-4 { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
            #tab-crm .px-4.py-4 > button { flex: 0 0 auto; }
        }
