/* ==========================================================================
   echeckin.ma — Design System
   SaaS for tourist rental management in Morocco
   ========================================================================== */

/* ==========================================================================
   1. CSS CUSTOM PROPERTIES (DESIGN TOKENS)
   ========================================================================== */

:root {
  /* --- Colors: Primary — « Maroc Blue » ---------------------------------
     Le bleu de la marque : navigation, CTA principaux, liserés. Assez
     profond pour porter du texte blanc (9,6:1) et pour servir de fond de
     sidebar sans écraser le reste de l'écran. */
  --color-primary:        #1B4965;
  --color-primary-light:  #245A7C;  /* survol des CTA — blanc à 7,4:1      */
  --color-primary-lighter:#2E6E96;  /* liens sur fond clair — 5,6:1        */
  --color-primary-50:     #EDF2F6;  /* fond de pastille / ligne active     */
  --color-primary-100:    #D3E0E9;  /* bordure de pastille                 */

  /* --- Colors: Accent — « Warm Clay » -----------------------------------
     L'argile casse la monotonie du bleu (toits de Marrakech, tadelakt).
     C'est une couleur CLAIRE : elle porte du texte ardoise (4,9:1), jamais
     du blanc (2,2:1). Pour écrire EN argile sur fond clair, utiliser
     --color-accent-strong. */
  --color-accent:         #D4A574;
  --color-accent-strong:  #8A5A24;  /* argile en TEXTE sur fond clair 5,9:1 */
  --color-accent-light:   #C08E4E;  /* survol des surfaces en argile        */
  --color-accent-lighter: #E6C9A6;
  --color-accent-50:      #FBF5EE;
  --color-accent-100:     #F2E2CE;

  /* --- Colors: Semantic -------------------------------------------------
     Deux usages distincts par statut, et c'est volontaire :
       • --color-<x>          : APLATS et liserés (jauges, rails 4px, points)
       • --color-<x>-dark     : TEXTE (badges, titres d'alerte) — AA vérifié
       • --color-<x>-light    : fond de badge, calibré pour que -dark passe
     Ne jamais écrire en --color-success / --color-warning : ces deux-là sont
     trop clairs pour du texte (2,9:1 et 1,8:1 sur blanc). */
  --color-success:        #27AE60;  /* aplat : check-in validé             */
  --color-success-light:  #EAF7EF;
  --color-success-dark:   #1B7F46;  /* texte — 5,0:1 sur blanc             */
  --color-warning:        #E8B923;  /* aplat : en attente                  */
  --color-warning-light:  #FDF6E0;
  --color-warning-dark:   #8A6A10;  /* texte — 5,1:1 sur blanc             */
  --color-danger:         #C0392B;  /* terre cuite : erreur bloquante      */
  --color-danger-light:   #FCEEEC;
  --color-danger-dark:    #9C2A1E;
  --color-info:           #1F6FEB;
  --color-info-light:     #EAF1FB;
  --color-info-dark:      #1A5FBF;

  /* --- Colors: Grays ----------------------------------------------------
     Papier CHAUD, encre FROIDE — c'est la tension qui donne son caractère
     à l'écran : les valeurs claires (50→300) tirent vers la crème et
     servent de fonds/bordures, les valeurs foncées (400→900) sont des
     ardoises issues de #2C3E50 et servent de texte.
     Seuils vérifiés sur blanc ET sur crème :
       500 = 4,6:1 (plus petit niveau admis pour du texte)
       400 = 3,4:1 — icônes et bordures seulement, jamais de texte. */
  --color-gray-50:        #FAF8F5;
  --color-gray-100:       #F0ECE6;
  --color-gray-200:       #E2DDD4;
  --color-gray-300:       #C9C2B7;
  --color-gray-400:       #7E8D9A;  /* UI (3,4:1) — pas de texte dessus    */
  --color-gray-500:       #5E7183;  /* labels — 4,6:1                      */
  --color-gray-600:       #4A6072;
  --color-gray-700:       #3B4F61;
  --color-gray-800:       #334655;
  --color-gray-900:       #2C3E50;  /* « Dark Slate » — titres et texte    */
  --color-white:          #ffffff;

  /* --- Colors: Surface --------------------------------------------------
     Crème cassée (#F5F3F0) pour la page, blanc franc pour les cartes : la
     carte se détache par le TON, pas par une ombre. */
  --color-bg:             #F5F3F0;
  --color-surface:        #ffffff;
  --color-surface-raised: #ffffff;
  --color-border:         #E2DDD4;
  --color-border-subtle:  #EFEBE4;

  /* --- Typography: Font Families --- */
  --font-sans:    'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-arabic:  'Tajawal', 'Noto Sans Arabic', 'Arabic UI Text', sans-serif;
  --font-mono:    'JetBrains Mono', 'Fira Code', 'Courier New', monospace;

  /* --- Typography: Sizes --- */
  --text-xs:      0.75rem;    /* 12px */
  --text-sm:      0.875rem;   /* 14px */
  --text-base:    1rem;       /* 16px */
  --text-lg:      1.125rem;   /* 18px */
  --text-xl:      1.25rem;    /* 20px */
  --text-2xl:     1.5rem;     /* 24px */
  --text-3xl:     1.875rem;   /* 30px */
  --text-4xl:     2.25rem;    /* 36px */
  /* Pas d'affichage : titre de page (h1). 28px — le brief demande 28-32px, on
     prend le bas de la fourchette parce qu'un back-office affiche le titre à
     côté d'actions, pas en couverture. */
  --text-display: 1.75rem;    /* 28px */

  /* --- Typography: Line Heights --- */
  --leading-tight:  1.25;
  --leading-snug:   1.375;
  --leading-normal: 1.5;
  --leading-relaxed:1.625;
  --leading-body:   1.6;      /* corps de texte (brief : 15-16px / 1.6) */

  /* Longueur de ligne confortable : ~75 caractères. Appliqué aux blocs de
     prose (sous-titres, états vides, aides de formulaire), pas à tous les
     <p> — une cellule de tableau n'est pas de la prose. */
  --measure:        75ch;

  /* --- Typography: Font Weights --- */
  --font-weight-normal:   400;
  --font-weight-medium:   500;
  --font-weight-semibold: 600;
  --font-weight-bold:     700;

  /* --- Spacing Scale --- */
  --space-0:   0;
  --space-px:  1px;
  --space-0-5: 0.125rem;   /* 2px */
  --space-1:   0.25rem;    /* 4px */
  --space-2:   0.5rem;     /* 8px */
  --space-3:   0.75rem;    /* 12px */
  --space-4:   1rem;       /* 16px */
  --space-5:   1.25rem;    /* 20px */
  --space-6:   1.5rem;     /* 24px */
  --space-7:   1.75rem;    /* 28px */
  --space-8:   2rem;       /* 32px */
  --space-10:  2.5rem;     /* 40px */
  --space-12:  3rem;       /* 48px */
  --space-16:  4rem;       /* 64px */

  /* --- Border Radius --- */
  --radius-sm:   0.25rem;   /* 4px */
  --radius-md:   0.5rem;    /* 8px */
  --radius-lg:   0.75rem;   /* 12px */
  --radius-xl:   1rem;      /* 16px */
  --radius-2xl:  1.5rem;    /* 24px */
  --radius-full: 9999px;

  /* --- Shadows --- */
  /* Teintées Maroc Blue (27 73 101), jamais du gris neutre. Les deux premiers
     niveaux sont volontairement imperceptibles : la structure vient des
     bordures et du contraste crème/blanc. Les niveaux md→xl sont réservés à
     ce qui FLOTTE réellement au-dessus de la page (menus, modale, toast). */
  --shadow-xs:  none;
  --shadow-sm:  none;
  --shadow-md:  0 2px 8px -2px rgb(27 73 101 / 0.14);
  --shadow-lg:  0 8px 24px -8px rgb(27 73 101 / 0.20);
  --shadow-xl:  0 16px 48px -12px rgb(27 73 101 / 0.26);
  --shadow-inner: inset 0 1px 2px 0 rgb(27 73 101 / 0.08);
  /* Anneau de focus : doublé par un outline 2px (section 4) — l'anneau seul
     ne suffit pas en contraste sur fonds colorés. */
  --shadow-focus: 0 0 0 3px rgb(27 73 101 / 0.20);
  --shadow-accent-focus: 0 0 0 3px rgb(212 165 116 / 0.40);

  /* --- Transitions --- */
  --transition-fast:   150ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-base:   250ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow:   400ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-bounce: 300ms cubic-bezier(0.34, 1.56, 0.64, 1);

  /* --- Z-Index Scale --- */
  --z-below:    -1;
  --z-base:      0;
  --z-raised:   10;
  --z-dropdown: 100;
  --z-sticky:   200;
  --z-overlay:  300;
  --z-modal:    400;
  --z-toast:    500;
  --z-tooltip:  600;

  /* --- Layout --- */
  --sidebar-width:         240px;
  --sidebar-width-collapsed: 72px;
  --header-height:         64px;
  --container-max:         1280px;
  /* Rail de statut des cartes opérationnelles (réservation, check-in) :
     4px de couleur à gauche = statut lisible sans lire. */
  --rail-width:            4px;

  /* --- Bleu de marque en ENCRE ---------------------------------------
     --color-primary est un FOND : il reste foncé en thème sombre, sinon la
     sidebar et les CTA cesseraient de porter du texte blanc. Pour ÉCRIRE en
     bleu de marque sur une surface claire, c'est ce token-ci — lui s'éclaircit
     la nuit. */
  --color-primary-ink:        var(--color-primary);

  /* --- Bouton secondaire (contour bleu) ------------------------------ */
  --btn-secondary-fg:         var(--color-primary-ink);
  --btn-secondary-border:     var(--color-primary-100);
  --btn-secondary-bg-hover:   var(--color-primary-50);
}

/* ==========================================================================
   2. DARK MODE TOKENS
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root {
    /* Pas de noir neutre : on descend la MÊME ardoise (#2C3E50) jusqu'au fond
       de page, ce qui garde l'identité du produit la nuit. */
    --color-bg:             #14202B;
    --color-surface:        #1C2B38;
    --color-surface-raised: #243646;
    --color-border:         #3A4F60;
    --color-border-subtle:  #243440;

    --color-gray-50:        #1C2B38;
    --color-gray-100:       #243646;
    --color-gray-200:       #2F4454;
    --color-gray-300:       #456073;
    --color-gray-400:       #7B93A5;  /* UI — 4,5:1 sur surface            */
    --color-gray-500:       #9FB3C2;  /* labels — 6,7:1                    */
    --color-gray-600:       #BCCBD6;
    --color-gray-700:       #D6E1E9;
    --color-gray-800:       #E7EEF3;
    --color-gray-900:       #F4F8FA;  /* texte — 13,5:1 sur surface        */

    /* Le bleu de marque s'éclaircit : #1B4965 en aplat sur un fond ardoise
       ne se détacherait plus (et ne porterait plus de texte blanc lisible).
       --color-primary reste tel quel : il sert de fond (sidebar, CTA) et
       porte toujours du blanc à 9,6:1. */
    --color-primary-50:     #1E3243;
    --color-primary-100:    #2A4A61;
    --color-primary-lighter:#7FB3D5;  /* liens — 6,4:1 sur surface sombre   */
    --color-primary-ink:    #7FB3D5;  /* bleu de marque en texte — 6,4:1    */

    /* Statuts : en sombre, un badge « light » resterait une tache blanche en
       plein écran. On inverse la paire — fond teinté sombre, texte clair —
       en gardant les mêmes noms de tokens, donc sans toucher aux composants. */
    --color-success-light:  #15341F;
    --color-success-dark:   #6EE7A0;  /* 8,8:1 sur son fond                */
    --color-warning-light:  #33280A;
    --color-warning-dark:   #F0C65A;  /* 8,9:1                             */
    --color-danger-light:   #3A1712;
    --color-danger-dark:    #F3A79B;  /* 8,3:1                             */
    --color-info-light:     #12263F;
    --color-info-dark:      #8FC2FF;  /* 8,2:1                             */

    /* L'argile en texte doit s'éclaircir, sinon elle disparaît ; ses tons
       clairs (pastilles d'icône) doivent au contraire s'assombrir, sinon ce
       sont des carrés crème en plein écran sombre. */
    --color-accent-strong:  #E6C9A6;
    --color-accent-50:      #33281C;
    --color-accent-100:     #4A3826;

    /* Bouton secondaire : bordure à 3,1:1 sur ardoise. */
    --btn-secondary-border:   #4A7A9B;
    --btn-secondary-bg-hover: #1E3243;

    /* Ombres : toujours teintées, mais plus profondes — le fond est sombre,
       une ombre claire n'existe pas. */
    --shadow-md:  0 2px 8px -2px rgb(0 0 0 / 0.50);
    --shadow-lg:  0 8px 24px -8px rgb(0 0 0 / 0.60);
    --shadow-xl:  0 16px 48px -12px rgb(0 0 0 / 0.70);
  }
}

/* ==========================================================================
   3. KEYFRAME ANIMATIONS
   ========================================================================== */

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideUp {
  from { transform: translateY(100%); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}

/* Toast : monte du bas sur une courte distance. Le but n'est pas de faire
   joli, c'est que l'œil sache QUE quelque chose vient de se passer et OÙ. */
@keyframes toastRise {
  from { transform: translateY(12px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

/* Modale : échelle 0.95 → 1 + fondu, 150ms. L'objet semble venir du clic,
   pas tomber du plafond. */
@keyframes modalIn {
  from { transform: scale(0.95); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

/* Entrée en cascade de la page : chaque bloc opérationnel (tuile, ligne de
   réservation) arrive décalé de 50ms. UN SEUL moment orchestré, au chargement
   — rien ne refait ça au scroll ni au survol. */
@keyframes riseIn {
  from { transform: translateY(8px); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}

@keyframes slideDown {
  from { transform: translateY(-100%); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

@keyframes slideInRight {
  from { transform: translateX(100%); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}

@keyframes slideInLeft {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0);     opacity: 1; }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.5; }
}

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

@keyframes scaleIn {
  from { transform: scale(0.92); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}

@keyframes ripple {
  to {
    transform: scale(4);
    opacity: 0;
  }
}

/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ==========================================================================
   4. MODERN CSS RESET
   ========================================================================== */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--font-weight-normal);
  line-height: var(--leading-body);
  color: var(--color-gray-900);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
}

[dir="rtl"] body,
[dir="rtl"] {
  font-family: var(--font-arabic);
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, textarea, select {
  font: inherit;
  width: 100%;
}

/* Les cases à cocher et les boutons radio sont EXCLUS du width:100% ci-dessus
   (même raison que le <button> exclu plus bas) : ce sont des cases de taille
   fixe, pas des champs de saisie. Étirées à 100 %, elles occupaient toute la
   ligne flex et expédiaient leur libellé à l'autre bout — d'où les cases à
   cocher « très éloignées du texte » et les radios décalés.
   La taille revient à l'intrinsèque ; les composants stylés
   (.checkbox-input / .radio-input / .form-check-input) la redéfinissent. */
input[type="checkbox"],
input[type="radio"] {
  width: auto;
  flex-shrink: 0;
}

/* `button` volontairement exclu du reset ci-dessus (G19) : un <button> sans
   classe .btn héritait de width:100%, invisible la plupart du temps (les
   boutons .btn ont flex-shrink:1 et se retassent), mais catastrophique dès
   qu'un bouton a flex-shrink:0 dans une ligne flex à côté d'un élément
   flex:1 (.alert-close, .modal-close, .toast-close…) : le texte flex:1 voisin
   se retrouvait compressé à ~0px et s'affichait lettre par lettre. Un bouton
   HTML est nativement en largeur "auto" — la pleine largeur reste un choix
   explicite via .btn--full / .btn-block, déjà utilisés ailleurs dans ce sens. */
button {
  font: inherit;
}

p, h1, h2, h3, h4, h5, h6 {
  overflow-wrap: break-word;
}

ul, ol {
  list-style: none;
}

table {
  border-collapse: collapse;
}

button {
  cursor: pointer;
  border: none;
  background: none;
}

a {
  color: var(--color-primary-lighter);
  text-decoration: none;
  transition: color var(--transition-fast);
}

/* Survol d'un lien : la couleur change et un soulignement discret apparaît.
   Pas de « → » accolé au libellé — le soulignement dit « cliquable », la
   flèche ne disait rien que le curseur ne disait déjà. */
a:hover {
  color: var(--color-accent-strong);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ---- Focus clavier : visible PARTOUT ---------------------------------
   Un outline 2px Maroc Blue avec 2px de décalage, qui tient sur fond clair
   comme sur fond crème. Les composants qui ont besoin d'autre chose (fond
   navy, champ de saisie) le surchargent explicitement — ils n'enlèvent
   jamais l'outline sans le remplacer. */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Sur fond navy (sidebar), le bleu de marque serait invisible : on passe en
   argile, qui ressort à 4,3:1 sur ce fond. */
.sidebar :focus-visible,
.toast :focus-visible {
  outline-color: var(--color-accent);
}

/* Le soulignement de a:hover s'adresse aux liens DE TEXTE. Tout ce qui est
   déjà un contrôle (bouton, item de menu, onglet, pastille de langue, bloc
   utilisateur) le refuse : sur ces éléments l'affordance vient de la forme,
   et un soulignement surgissant au survol ressemble à un défaut. */
a.btn:hover,
.btn:hover,
.sidebar-nav-link:hover,
.sidebar-logo:hover,
.sidebar-user-info--link:hover,
.sidebar-user-logout:hover,
.lang-btn:hover,
.tab:hover,
.quick-link:hover,
.pagination-link:hover,
.dropdown-item:hover,
.card-link:hover .badge,
.booking-row a.btn:hover {
  text-decoration: none;
}

hr {
  border: none;
  border-top: 1px solid var(--color-border);
  margin: var(--space-6) 0;
}

/* ==========================================================================
   5. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4, h5, h6 {
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-tight);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
}

/* Échelle explicite — aucune taille improvisée ailleurs dans la feuille.
   h1 28px / h2 24px / h3 20px / h4 18px : chaque pas se voit, et le pas
   d'affichage reste sobre parce qu'un titre de back-office cohabite avec
   des boutons d'action, pas avec une couverture. */
h1 { font-size: var(--text-display); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }
h5 { font-size: var(--text-base); }
h6 { font-size: var(--text-sm); }

p {
  line-height: var(--leading-body);
  color: var(--color-gray-700);
}

/* Longueur de ligne : ~75 caractères. Posé sur les blocs de PROSE seulement
   (sous-titre de carte, état vide, aide de champ) — une cellule de tableau
   ou un libellé de bouton n'est pas de la prose et ne doit pas être bridé. */
.measure,
.card-subtitle,
.empty-state p,
.form-help {
  max-width: var(--measure);
}

small {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}

strong, b {
  font-weight: var(--font-weight-semibold);
}

code {
  font-family: var(--font-mono);
  font-size: 17px;
  background: var(--color-gray-100) !important;
  padding: 0.1em 0.3em !important;
  border-radius: var(--radius-sm) !important;
  color: var(--color-primary-ink);
  font-weight: bold;
}

/* ==========================================================================
   6. LAYOUT — CONTAINER & GRID
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

@media (min-width: 640px) {
  .container { padding-inline: var(--space-6); }
}

@media (min-width: 1024px) {
  .container { padding-inline: var(--space-8); }
}

/* App shell: sidebar + content */
/* La sidebar étant position:fixed elle sort du flux grid — on utilise
   uniquement margin-left sur .main-content pour éviter une largeur nulle. */
.layout-sidebar {
  min-height: 100vh;
}

@media (max-width: 1023px) {
  .layout-sidebar {
    grid-template-columns: 1fr;
  }
}

/* Responsive grid helpers */
.grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

.grid-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

.grid-4 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

@media (min-width: 640px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1024px) {
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
}

/* Page header */
.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-8);
  flex-wrap: wrap;
}

.page-header-title h1,
.page-header-title h2 {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
}

.page-header-title p {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  margin-top: var(--space-1);
}

.page-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
}

/* ==========================================================================
   7. SIDEBAR NAVIGATION
   ========================================================================== */

.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--sidebar-width);
  /* 100vh = hauteur du viewport "URL bar cachée" sur mobile : plus grand que
     la zone réellement visible, ce qui poussait le bas du menu (footer + derniers
     items) sous le pli et obligeait à scroller dans la sidebar. 100dvh suit la
     zone visible ; on garde 100vh en repli pour les navigateurs anciens. */
  height: 100vh;
  height: 100dvh;
  background: var(--color-primary);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  z-index: var(--z-sticky);
  transition: transform var(--transition-base), width var(--transition-base);
}

[dir="rtl"] .sidebar {
  left: auto;
  right: 0;
}

@media (max-width: 1023px) {
  .sidebar {
    transform: translateX(-100%);
    box-shadow: var(--shadow-xl);
  }

  [dir="rtl"] .sidebar {
    transform: translateX(100%);
  }

  .sidebar.sidebar-open {
    transform: translateX(0);
  }
}

/* Sidebar brand/logo */
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-5);
  border-bottom: 1px solid rgb(255 255 255 / 0.08);
  text-decoration: none;
  min-height: var(--header-height);
  flex-shrink: 0;
}

.sidebar-brand-logo {
  width: 36px;
  height: 36px;
  background: var(--color-accent);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: var(--text-lg);
  font-weight: var(--font-weight-bold);
  color: var(--color-white);
  letter-spacing: -0.03em;
}

.sidebar-brand-text {
  display: flex;
  flex-direction: column;
}

.sidebar-brand-name {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-white);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.sidebar-brand-tagline {
  font-size: var(--text-xs);
  color: rgb(255 255 255 / 0.45);
  margin-top: 1px;
}

/* Sidebar scrollable nav area */
.sidebar-nav-wrap {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-4) 0;
  scrollbar-width: thin;
  scrollbar-color: rgb(255 255 255 / 0.1) transparent;
}

.sidebar-nav-wrap::-webkit-scrollbar {
  width: 4px;
}

.sidebar-nav-wrap::-webkit-scrollbar-track {
  background: transparent;
}

.sidebar-nav-wrap::-webkit-scrollbar-thumb {
  background: rgb(255 255 255 / 0.1);
  border-radius: var(--radius-full);
}

/* Nav sections */
.sidebar-nav {
  padding: 0 var(--space-3);
}

.nav-section-label {
  font-size: 10px;
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.35);
  padding: var(--space-4) var(--space-3) var(--space-2);
}

.nav-divider {
  height: 1px;
  background: rgb(255 255 255 / 0.08);
  margin: var(--space-3) var(--space-3);
}

/* Nav items */
.nav-item {
  margin-bottom: var(--space-1);
}

.nav-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2-5, 0.625rem) var(--space-3);
  border-radius: var(--radius-md);
  color: rgb(255 255 255 / 0.65);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  transition:
    background var(--transition-fast),
    color var(--transition-fast);
  position: relative;
  white-space: nowrap;
}

.nav-link:hover {
  background: rgb(255 255 255 / 0.08);
  color: var(--color-white);
}

.nav-link.active,
.nav-link[aria-current="page"] {
  background: rgb(255 255 255 / 0.12);
  color: var(--color-white);
}

.nav-link.active::before,
.nav-link[aria-current="page"]::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 60%;
  background: var(--color-accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

[dir="rtl"] .nav-link.active::before,
[dir="rtl"] .nav-link[aria-current="page"]::before {
  left: auto;
  right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}

.nav-link-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  opacity: 0.75;
}

.nav-link.active .nav-link-icon,
.nav-link:hover .nav-link-icon {
  opacity: 1;
}

.nav-badge {
  margin-left: auto;
  background: var(--color-accent);
  /* L'argile est claire : elle porte de l'ardoise, pas du blanc (2,2:1). */
  color: var(--color-gray-900);
  font-size: 10px;
  font-weight: var(--font-weight-bold);
  padding: 1px 6px;
  border-radius: var(--radius-full);
  min-width: 18px;
  text-align: center;
}

[dir="rtl"] .nav-badge {
  margin-left: 0;
  margin-right: auto;
}

/* Sidebar bottom user card */
.sidebar-user {
  border-top: 1px solid rgb(255 255 255 / 0.08);
  padding: var(--space-4) var(--space-4);
  flex-shrink: 0;
}

.sidebar-user-inner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: background var(--transition-fast);
  text-decoration: none;
}

.sidebar-user-inner:hover {
  background: rgb(255 255 255 / 0.08);
}

.sidebar-user-avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  flex-shrink: 0;
  overflow: hidden;
}

.sidebar-user-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.sidebar-user-info {
  flex: 1;
  min-width: 0;
}

.sidebar-user-name {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-white);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar-user-role {
  font-size: var(--text-xs);
  color: rgb(255 255 255 / 0.45);
}

/* Main content area */
.main-content {
  margin-left: var(--sidebar-width);
  min-height: 100vh;
  overflow-y: auto;
  padding: var(--space-8);
  transition: margin var(--transition-base);
}

[dir="rtl"] .main-content {
  margin-left: 0;
  margin-right: var(--sidebar-width);
}

@media (max-width: 1023px) {
  /* Le sélecteur [dir="rtl"] est nécessaire : sans lui, la règle RTL
     "margin-right: var(--sidebar-width)" (plus spécifique) garderait
     260px de marge sur mobile et écraserait tout le contenu. */
  .main-content,
  [dir="rtl"] .main-content {
    margin-left: 0;
    margin-right: 0;
    padding: var(--space-4);
  }
}

/* Mobile top bar */
.mobile-topbar {
  display: none;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
}

@media (max-width: 1023px) {
  .mobile-topbar { display: flex; }
}

.sidebar-toggle {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-gray-700);
  transition: background var(--transition-fast);
}

.sidebar-toggle:hover {
  background: var(--color-gray-100);
}

/* Sidebar overlay for mobile */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  /* Ardoise plutôt que noir pur : le voile doit assombrir la page, pas la
     salir. Même teinte que le voile de modale. */
  background: rgb(44 62 80 / 0.45);
  z-index: calc(var(--z-sticky) - 1);
  backdrop-filter: blur(2px);
  animation: fadeIn var(--transition-fast) ease;
}

@media (max-width: 1023px) {
  .sidebar-overlay.active {
    display: block;
  }
}

/* ==========================================================================
   8. CARDS
   ========================================================================== */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  /* 12px pour un PANNEAU. Les cartes opérationnelles (propriété,
     réservation) descendent à 8px : deux objets différents, deux rayons
     différents — c'est ce qui évite le mur de cartes identiques. */
  border-radius: var(--radius-lg);
  overflow: hidden;
}

/* Survol d'une carte cliquable : la bordure prend la couleur de marque.
   Pas de soulèvement, pas de halo — le pointeur dit déjà « cliquable ». */
.card-hover {
  transition: border-color var(--transition-fast);
}

.card-hover:hover {
  border-color: var(--color-primary-100);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-border);
  gap: var(--space-2) var(--space-4);
}

/* Le sous-titre prend toute la largeur et passe SOUS le titre. Sans cela, le
   <h2> et le <p> frères se partageaient la ligne en space-between : le titre
   se cassait sur trois lignes pendant que le sous-titre occupait la moitié
   droite de l'en-tête. */
.card-header > .card-subtitle { flex-basis: 100%; margin-top: 0; }

/* Sous 640px, titre et lien d'en-tête s'empilent : côte à côte, le titre
   tombait sur trois lignes dans la largeur restante. */
@media (max-width: 639px) {
  .card-header {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-4) var(--space-4);
  }
}

/* Groupe d'actions d'en-tête : compteur et bouton tiennent ensemble à droite
   du titre. Sans ce groupe, un troisième enfant du `.card-header` en
   space-between renvoyait le compteur au MILIEU de la ligne. */
.card-header-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
}

/* Compteur d'en-tête (« 2 / 3 publiées ») : du texte secondaire, pas un
   titre. Remplace un font-size posé en style inline dans la vue. */
.card-header-meta {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}

/* À 360px, le bouton passe sous le compteur et prend la largeur de la carte :
   son libellé reste entier plutôt que coupé en bout de ligne. */
@media (max-width: 479px) {
  .card-header-actions {
    width: 100%;
    align-items: stretch;
    flex-direction: column;
  }
  .card-header-actions .btn {
    justify-content: center;
    width: 100%;
  }
}

.card-header-title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.01em;
}

.card-body {
  padding: var(--space-6);
}

.card-footer {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-gray-50);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* Stat card — tuile de chiffre opérationnel.
   Avant : une barre dégradée navy→or en haut de CHAQUE tuile, identique
   partout, qui ne disait rien. Elle est remplacée par un liseré gauche dont
   la couleur porte le sens de la tuile (cf. .stat-card--*), donc par de
   l'information. */
.stat-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: var(--rail-width) solid var(--rail-neutral);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  position: relative;
  overflow: hidden;
}

[dir="rtl"] .stat-card {
  border-left: 1px solid var(--color-border);
  border-right: var(--rail-width) solid var(--rail-neutral);
}

.stat-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}

.stat-card-icon {
  width: 44px;
  height: 44px;
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
  flex-shrink: 0;
}

.stat-card-icon.accent {
  background: var(--color-accent-50);
  color: var(--color-accent-strong);
}

.stat-card-icon.success {
  background: var(--color-success-light);
  color: var(--color-success-dark);
}

.stat-card-icon.warning {
  background: var(--color-warning-light);
  color: var(--color-warning-dark);
}

/* .stat-card-value / .stat-card-label : définis une seule fois, en section 37
   (DASHBOARD) — c'est là que vit la tuile. Le doublon qui se trouvait ici
   était systématiquement écrasé par celui de la section 37. */

.stat-card-trend {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  margin-top: var(--space-3);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-full);
}

.stat-card-trend.up {
  color: var(--color-success-dark);
  background: var(--color-success-light);
}

.stat-card-trend.down {
  color: var(--color-danger-dark);
  background: var(--color-danger-light);
}

.stat-card-trend.neutral {
  color: var(--color-gray-600);
  background: var(--color-gray-100);
}

/* ==========================================================================
   9. BUTTONS
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 0.5625rem var(--space-4);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  line-height: 1;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  transition:
    background var(--transition-fast),
    color var(--transition-fast),
    border-color var(--transition-fast),
    box-shadow var(--transition-fast),
    transform var(--transition-fast);
  user-select: none;
  -webkit-user-select: none;
}

/* Focus clavier : l'outline global (section 4) s'applique, et l'anneau
   teinté vient par-dessus. On ne retire JAMAIS l'outline ici — c'était le
   trou d'accessibilité : sur fond navy, l'anneau seul ne se voyait pas. */
.btn:focus-visible {
  box-shadow: var(--shadow-focus);
}

/* Cible tactile : 44px minimum dès qu'on est au doigt (mobile ou écran
   tactile). Sur une souris, 36px suffit et garde les barres d'action
   compactes — imposer 44px partout alourdirait chaque tableau. */
@media (max-width: 767px), (hover: none) and (pointer: coarse) {
  .btn,
  .btn--sm,
  .btn-sm,
  .btn--xs,
  .btn-xs {
    min-height: 44px;
  }
  .btn-icon {
    min-width: 44px;
  }
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled,
.btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* Button variants */
.btn-primary {
  background: var(--color-primary);
  color: var(--color-white);
  border-color: var(--color-primary);
}

/* Survol : la couleur du fond bouge, rien ne lévite. */
.btn-primary:hover {
  background: var(--color-primary-light);
  border-color: var(--color-primary-light);
  color: var(--color-white);
}

/* L'argile est claire : son texte est ardoise (4,9:1), pas blanc (2,2:1). */
.btn-accent {
  background: var(--color-accent);
  color: var(--color-gray-900);
  border-color: var(--color-accent);
}

/* Au survol, l'argile se CREUSE au lieu de s'éclaircir, et le texte passe
   au blanc : #C08E4E en fond ne portait plus l'ardoise (3,8:1), alors que
   #8A5A24 porte le blanc à 5,9:1. */
.btn-accent:hover {
  background: var(--color-accent-strong);
  border-color: var(--color-accent-strong);
  color: var(--color-white);
}

/* Secondaire = contour seul, en bleu de marque (« Annuler », « Voir
   détails »). Il se lit comme une alternative au CTA, pas comme un bouton
   gris désactivé — c'était l'ambiguïté de la version précédente. */
.btn-secondary {
  background: transparent;
  color: var(--btn-secondary-fg);
  border-color: var(--btn-secondary-border);
}

.btn-secondary:hover {
  background: var(--btn-secondary-bg-hover);
  border-color: var(--btn-secondary-fg);
  color: var(--btn-secondary-fg);
}

.btn-danger {
  background: var(--color-danger);
  color: var(--color-white);
  border-color: var(--color-danger);
}

.btn-danger:hover {
  background: var(--color-danger-dark);
  border-color: var(--color-danger-dark);
  color: var(--color-white);
}

/* Le vert d'aplat (#27AE60) ne porte pas de blanc lisible (2,9:1) : un
   bouton plein utilise donc la variante foncée (5,0:1). */
.btn-success {
  background: var(--color-success-dark);
  color: var(--color-white);
  border-color: var(--color-success-dark);
}

.btn-success:hover {
  background: #146B39;
  border-color: #146B39;
  color: var(--color-white);
}

/* Action lourde mais pas destructrice — « Archiver la réservation »,
   « Signaler un problème ». L'ambre arrête l'œil sans crier au danger, et
   porte du texte ardoise à 6,0:1. Le rouge reste pour ce qui supprime. */
.btn-warning {
  background: var(--color-warning);
  color: var(--color-gray-900);
  border-color: var(--color-warning);
}

.btn-warning:hover {
  background: #D4A70F;
  border-color: #D4A70F;
  color: var(--color-gray-900);
}

.btn-ghost {
  background: transparent;
  color: var(--color-gray-600);
  border-color: transparent;
}

.btn-ghost:hover {
  background: var(--color-gray-100);
  color: var(--color-gray-900);
}

.btn-ghost-primary {
  background: transparent;
  color: var(--color-primary-ink);
  border-color: transparent;
}

.btn-ghost-primary:hover {
  background: var(--color-primary-50);
}

/* Button sizes */
.btn-xs {
  padding: 0.3125rem var(--space-3);
  font-size: var(--text-xs);
  border-radius: var(--radius-sm);
}

.btn-sm {
  padding: 0.4375rem var(--space-3);
  font-size: var(--text-sm);
}

.btn-lg {
  padding: 0.75rem var(--space-6);
  font-size: var(--text-base);
  border-radius: var(--radius-lg);
}

.btn-xl {
  padding: 1rem var(--space-8);
  font-size: var(--text-lg);
  border-radius: var(--radius-lg);
}

/* Icon-only button */
.btn-icon {
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: var(--radius-md);
  flex-shrink: 0;
}

.btn-icon.btn-sm {
  width: 30px;
  height: 30px;
}

.btn-icon.btn-lg {
  width: 44px;
  height: 44px;
}

/* Full width */
.btn-block {
  width: 100%;
}

/* Loading state */
.btn-loading {
  color: transparent !important;
  pointer-events: none;
}

.btn-loading::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 2px solid currentColor;
  border-color: rgb(255 255 255 / 0.3) rgb(255 255 255 / 0.3) rgb(255 255 255 / 0.3) var(--color-white);
  border-radius: var(--radius-full);
  animation: spin 0.7s linear infinite;
}

.btn-loading.btn-secondary::after,
.btn-loading.btn-ghost::after {
  border-color: rgb(44 62 80 / 0.15) rgb(44 62 80 / 0.15) rgb(44 62 80 / 0.15) var(--color-gray-700);
}

/* RTL arrow fix */
.btn .btn-arrow,
.btn-arrow-icon {
  transition: transform var(--transition-fast);
}

[dir="rtl"] .btn .btn-arrow,
[dir="rtl"] .btn-arrow-icon {
  transform: scaleX(-1);
}

/* ==========================================================================
   10. FORMS
   ========================================================================== */

.form-group {
  margin-bottom: var(--space-5);
}

.form-label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-700);
  margin-bottom: var(--space-2);
}

.form-label.required::after {
  content: ' *';
  color: var(--color-danger);
}

[dir="rtl"] .form-label {
  text-align: right;
}

.form-control {
  display: block;
  width: 100%;
  padding: var(--space-2-5, 0.625rem) var(--space-3);
  font-size: var(--text-sm);
  font-family: inherit;
  font-weight: var(--font-weight-normal);
  color: var(--color-gray-900);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  line-height: var(--leading-normal);
  transition:
    border-color var(--transition-fast),
    box-shadow var(--transition-fast),
    background var(--transition-fast);
  appearance: none;
  -webkit-appearance: none;
}

.form-control::placeholder {
  color: var(--color-gray-400);
}

.form-control:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--shadow-focus);
  background: var(--color-white);
}

.form-control:disabled {
  background: var(--color-gray-50);
  color: var(--color-gray-400);
  cursor: not-allowed;
}

.form-control.is-error {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px rgb(239 68 68 / 0.12);
}

.form-control.is-success {
  border-color: var(--color-success);
  box-shadow: 0 0 0 3px rgb(34 197 94 / 0.12);
}

/* Textarea */
textarea.form-control {
  resize: vertical;
  min-height: 100px;
}

/* Select */
select.form-control {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236b7280'%3E%3Cpath fill-rule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clip-rule='evenodd'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  background-size: 16px;
  padding-right: var(--space-10);
}

[dir="rtl"] select.form-control {
  background-position: left var(--space-3) center;
  padding-right: var(--space-3);
  padding-left: var(--space-10);
}

/* Hint and error messages */
.form-hint {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  margin-top: var(--space-1-5, 0.375rem);
}

.form-error {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-danger);
  margin-top: var(--space-1-5, 0.375rem);
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* Input group (prefix / suffix) */
.input-group {
  display: flex;
  align-items: stretch;
}

.input-group .form-control {
  flex: 1;
  min-width: 0;
  border-radius: 0;
}

.input-group-prefix {
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  background: var(--color-gray-100);
  border: 1px solid var(--color-border);
  border-right: none;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  white-space: nowrap;
  flex-shrink: 0;
}

.input-group-suffix {
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  background: var(--color-gray-100);
  border: 1px solid var(--color-border);
  border-left: none;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  white-space: nowrap;
  flex-shrink: 0;
}

.input-group .form-control:first-child {
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}

.input-group .form-control:last-child {
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

[dir="rtl"] .input-group-prefix {
  border-right: 1px solid var(--color-border);
  border-left: none;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

[dir="rtl"] .input-group-suffix {
  border-left: 1px solid var(--color-border);
  border-right: none;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}

/* Custom checkbox */
.form-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  cursor: pointer;
  user-select: none;
}

.form-check-input {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border: 2px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-white);
  cursor: pointer;
  flex-shrink: 0;
  margin-top: 1px;
  transition:
    background var(--transition-fast),
    border-color var(--transition-fast),
    box-shadow var(--transition-fast);
  position: relative;
}

.form-check-input:checked {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.form-check-input:checked::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 5px;
  width: 5px;
  height: 9px;
  border: 2px solid white;
  border-top: none;
  border-left: none;
  transform: rotate(45deg);
}

.form-check-input:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
}

/* Custom radio */
.form-check-input[type="radio"] {
  border-radius: var(--radius-full);
}

.form-check-input[type="radio"]:checked::after {
  top: 3px;
  left: 3px;
  width: 8px;
  height: 8px;
  border: none;
  background: var(--color-white);
  border-radius: var(--radius-full);
  transform: none;
}

.form-check-label {
  font-size: var(--text-sm);
  color: var(--color-gray-700);
  cursor: pointer;
  line-height: 1.4;
}

/* File upload dropzone */
.upload-zone {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-xl);
  padding: var(--space-10) var(--space-6);
  text-align: center;
  cursor: pointer;
  transition:
    border-color var(--transition-fast),
    background var(--transition-fast);
  background: var(--color-gray-50);
}

.upload-zone:hover,
.upload-zone.drag-over {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
}

.upload-zone-icon {
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-4);
  color: var(--color-gray-400);
}

.upload-zone-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-700);
  margin-bottom: var(--space-1);
}

.upload-zone-hint {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
}

.upload-zone input[type="file"] {
  display: none;
}

/* Signature pad */
.signature-pad {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  overflow: hidden;
  position: relative;
}

.signature-pad canvas {
  display: block;
  width: 100%;
  cursor: crosshair;
  touch-action: none;
}

.signature-pad-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-2) var(--space-4);
  background: var(--color-gray-50);
  border-top: 1px solid var(--color-border);
}

.signature-pad-hint {
  font-size: var(--text-xs);
  color: var(--color-gray-400);
}

/* ==========================================================================
   11. TABLES
   ========================================================================== */

.table-responsive {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-xl);
  border: 1px solid var(--color-border);
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  background: var(--color-surface);
}

.table thead th {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-gray-500);
  text-align: left;
  background: var(--color-gray-50);
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}

[dir="rtl"] .table thead th {
  text-align: right;
}

.table tbody td {
  padding: var(--space-4);
  color: var(--color-gray-700);
  border-bottom: 1px solid var(--color-border-subtle);
  vertical-align: middle;
}

.table tbody tr:last-child td {
  border-bottom: none;
}

.table-striped tbody tr:nth-child(even) td {
  background: var(--color-gray-50);
}

.table-hover tbody tr {
  transition: background var(--transition-fast);
}

.table-hover tbody tr:hover td {
  background: var(--color-primary-50);
}

.table .col-actions {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

[dir="rtl"] .table .col-actions {
  text-align: left;
}

/* Badges */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-0-5) var(--space-2-5, 0.625rem);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  border-radius: var(--radius-full);
  line-height: 1.5;
  white-space: nowrap;
}

.badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: currentColor;
  flex-shrink: 0;
}

.badge-default {
  background: var(--color-gray-100);
  color: var(--color-gray-700);
}

.badge-primary {
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
}

.badge-accent {
  background: var(--color-accent-50);
  color: var(--color-accent-strong);
}

.badge-success {
  background: var(--color-success-light);
  color: var(--color-success-dark);
}

.badge-warning {
  background: var(--color-warning-light);
  color: var(--color-warning-dark);
}

.badge-danger {
  background: var(--color-danger-light);
  color: var(--color-danger-dark);
}

.badge-info {
  background: var(--color-info-light);
  color: var(--color-info-dark);
}

/* ==========================================================================
   12. ALERTS & TOASTS
   ========================================================================== */

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  border: 1px solid transparent;
}

.alert-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
}

.alert-content {
  flex: 1;
}

.alert-title {
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-1);
}

.alert-success {
  background: var(--color-success-light);
  border-color: rgb(34 197 94 / 0.2);
  color: var(--color-success-dark);
}

.alert-warning {
  background: var(--color-warning-light);
  border-color: rgb(245 158 11 / 0.2);
  color: var(--color-warning-dark);
}

.alert-danger {
  background: var(--color-danger-light);
  border-color: rgb(239 68 68 / 0.2);
  color: var(--color-danger-dark);
}

.alert-info {
  background: var(--color-info-light);
  border-color: rgb(59 130 246 / 0.2);
  color: var(--color-info-dark);
}

/* Toast container */
/* Le toast confirme une action. Il arrive donc du BAS — près de la barre
   d'actions et du pouce — et non du coin haut-droit, où l'œil n'était pas.
   column-reverse : le plus récent est toujours le plus près du bord. */
.toast-container {
  position: fixed;
  bottom: var(--space-4);
  right: var(--space-4);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-3);
  max-width: 380px;
  width: calc(100% - var(--space-8));
}

[dir="rtl"] .toast-container {
  right: auto;
  left: var(--space-4);
}

@media (max-width: 639px) {
  .toast-container {
    right: var(--space-4);
    left: var(--space-4);
    max-width: none;
    width: auto;
  }
}

/* Fond navy de marque, et non --color-gray-900 : ce token s'inverse en mode
   sombre (il devient presque blanc) et le toast devenait blanc sur blanc,
   donc illisible la nuit. Le navy, lui, est un fond dans les deux modes. */
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--color-primary);
  color: var(--color-white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  /* 200ms ease-out, 12px de course : assez pour être remarqué, trop court
     pour être attendu. */
  animation: toastRise 200ms cubic-bezier(0, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

[dir="rtl"] .toast {
  animation: toastRise 200ms cubic-bezier(0, 0, 0.2, 1);
}

.toast::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  height: 3px;
  background: var(--color-accent);
  animation: toastProgress 4s linear forwards;
}

@keyframes toastProgress {
  from { width: 100%; }
  to   { width: 0%; }
}

.toast-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  margin-top: 1px;
}

.toast-content { flex: 1; }

.toast-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  margin-bottom: 2px;
}

.toast-message {
  font-size: var(--text-xs);
  color: rgb(255 255 255 / 0.7);
}

.toast-close {
  color: rgb(255 255 255 / 0.5);
  padding: 2px;
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast);
  flex-shrink: 0;
}

.toast-close:hover {
  color: var(--color-white);
}

/* La couleur du toast dit le résultat sans le lire : vert = c'est validé,
   ambre = regarde ça, rouge = ça n'est pas passé. Le liseré monte à 4px
   (--rail-width) pour parler le même langage que les cartes de statut. */
.toast.toast-success {
  background: var(--color-success-dark);
  border-left: var(--rail-width) solid var(--color-success);
}
.toast.toast-warning {
  background: var(--color-warning);
  color: var(--color-gray-900);
  border-left: var(--rail-width) solid var(--color-warning-dark);
}
.toast.toast-danger {
  background: var(--color-danger);
  border-left: var(--rail-width) solid var(--color-danger-dark);
}
/* Sur l'ambre, la barre de progression doit se voir : l'argile y disparaît. */
.toast.toast-warning::after { background: var(--color-warning-dark); }
.toast.toast-warning .toast-close { color: var(--color-gray-900); }

[dir="rtl"] .toast.toast-success,
[dir="rtl"] .toast.toast-warning,
[dir="rtl"] .toast.toast-danger {
  border-left: none;
  border-right: var(--rail-width) solid currentColor;
}

/* Un toast est un objet SOMBRE dans les deux thèmes : c'est une notification
   posée par-dessus la page, pas une surface de la page. Les tokens de statut
   s'inversent en mode sombre (--color-success-dark devient un vert clair,
   --color-gray-900 devient presque blanc) — sans ce garde-fou on retombait
   sur du blanc sur vert clair et du blanc sur ambre, illisibles tous les
   deux. Valeurs figées ici, et seulement ici. */
@media (prefers-color-scheme: dark) {
  .toast.toast-success {
    background: #1B7F46;
    color: #ffffff;
  }
  .toast.toast-warning {
    background: #E8B923;
    color: #2C3E50;
  }
  .toast.toast-warning .toast-close { color: #2C3E50; }
  .toast.toast-danger {
    background: #C0392B;
    color: #ffffff;
  }
}
.toast.toast-info    { border-left: 3px solid var(--color-info); }

[dir="rtl"] .toast.toast-success,
[dir="rtl"] .toast.toast-warning,
[dir="rtl"] .toast.toast-danger,
[dir="rtl"] .toast.toast-info {
  border-left: none;
  border-right: 3px solid;
}

[dir="rtl"] .toast.toast-success { border-right-color: var(--color-success); }
[dir="rtl"] .toast.toast-warning { border-right-color: var(--color-warning); }
[dir="rtl"] .toast.toast-danger  { border-right-color: var(--color-danger); }
[dir="rtl"] .toast.toast-info    { border-right-color: var(--color-info); }

/* ==========================================================================
   13. COMPLIANCE INDICATORS
   ========================================================================== */

.compliance-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
}

.compliance-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  transition:
    border-color var(--transition-fast),
    box-shadow var(--transition-fast);
}

.compliance-item:hover {
  border-color: var(--color-gray-300);
  box-shadow: var(--shadow-sm);
}

.compliance-item-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.compliance-item.ok    .compliance-item-icon { background: var(--color-success-light); color: var(--color-success-dark); }
.compliance-item.pending .compliance-item-icon { background: var(--color-warning-light); color: var(--color-warning-dark); }
.compliance-item.missing  .compliance-item-icon { background: var(--color-danger-light); color: var(--color-danger-dark); }

.compliance-item-label {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  display: block;
}

.compliance-item-value {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  display: block;
}

.compliance-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
  font-size: 10px;
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-left: auto;
  flex-shrink: 0;
}

[dir="rtl"] .compliance-badge {
  margin-left: 0;
  margin-right: auto;
}

.compliance-badge.ok      { background: var(--color-success-light); color: var(--color-success-dark); }
.compliance-badge.pending { background: var(--color-warning-light); color: var(--color-warning-dark); }
.compliance-badge.missing { background: var(--color-danger-light);  color: var(--color-danger-dark); }

/* ==========================================================================
   14. STEP WIZARD
   ========================================================================== */

.wizard-steps {
  display: flex;
  align-items: center;
  margin-bottom: var(--space-8);
  overflow-x: auto;
  padding-bottom: var(--space-2);
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.wizard-steps::-webkit-scrollbar {
  display: none;
}

.wizard-step {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.wizard-step-circle {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  border: 2px solid var(--color-border);
  background: var(--color-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-400);
  transition:
    background var(--transition-base),
    border-color var(--transition-base),
    color var(--transition-base);
  position: relative;
  z-index: 1;
  flex-shrink: 0;
}

.wizard-step.active .wizard-step-circle {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
  box-shadow: 0 0 0 4px var(--color-primary-50);
}

.wizard-step.completed .wizard-step-circle {
  background: var(--color-success);
  border-color: var(--color-success);
  color: var(--color-white);
}

.wizard-step-info {
  margin-left: var(--space-3);
  white-space: nowrap;
}

[dir="rtl"] .wizard-step-info {
  margin-left: 0;
  margin-right: var(--space-3);
}

.wizard-step-number {
  font-size: var(--text-xs);
  color: var(--color-gray-400);
  display: block;
}

.wizard-step-label {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-500);
}

.wizard-step.active  .wizard-step-label { color: var(--color-primary-ink); font-weight: var(--font-weight-semibold); }
.wizard-step.completed .wizard-step-label { color: var(--color-success-dark); }

.wizard-step-line {
  flex: 1;
  height: 2px;
  background: var(--color-border);
  margin: 0 var(--space-3);
  min-width: var(--space-6);
  transition: background var(--transition-base);
  position: relative;
  top: -10px;
}

.wizard-step.completed + .wizard-step-line,
.wizard-step-line.completed {
  background: var(--color-success);
}

@media (max-width: 639px) {
  .wizard-steps {
    gap: 0;
  }

  .wizard-step-info {
    display: none;
  }

  .wizard-step.active .wizard-step-info {
    display: block;
  }

  .wizard-step-line {
    min-width: var(--space-4);
    margin: 0 var(--space-2);
  }
}

/* ==========================================================================
   15. CHECK-IN GUEST FORM
   ========================================================================== */

.checkin-layout {
  min-height: 100vh;
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.checkin-header {
  width: 100%;
  max-width: 100%;
  padding: var(--space-6) var(--space-4);
  text-align: center;
}

.checkin-property-logo {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-xl);
  margin: 0 auto var(--space-4);
  object-fit: cover;
  box-shadow: var(--shadow-md);
}

.checkin-property-name {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
}

.checkin-property-location {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  margin-top: var(--space-1);
}

.checkin-progress {
  margin-top: var(--space-5);
  background: var(--color-border);
  height: 4px;
  border-radius: var(--radius-full);
  overflow: hidden;
}

.checkin-progress-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--color-primary), var(--color-accent));
  border-radius: var(--radius-full);
  transition: width var(--transition-slow);
}

.checkin-body {
  width: 100%;
  max-width: 640px;
  padding: 0 var(--space-4) var(--space-8);
  flex: 1;
}

.checkin-card {
  background: var(--color-surface);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  animation: fadeInUp var(--transition-slow) ease;
}

.checkin-card-header {
  padding: var(--space-6);
  border-bottom: 1px solid var(--color-border);
  background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-lighter) 100%);
  color: var(--color-white);
}

.checkin-step-label {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.6);
  margin-bottom: var(--space-1);
}

.checkin-step-title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-white);
  letter-spacing: -0.02em;
}

.checkin-card-body {
  padding: var(--space-6);
}

.checkin-card-footer {
  padding: var(--space-5) var(--space-6);
  border-top: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  background: var(--color-gray-50);
}

/* Camera / document scan */
.camera-container {
  position: relative;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--color-gray-900);
  aspect-ratio: 4/3;
}

.camera-container video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.camera-container canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.scan-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.scan-frame {
  width: 80%;
  aspect-ratio: 85/54;  /* ID card ratio */
  position: relative;
}

.scan-frame::before,
.scan-frame::after,
.scan-frame .corner-tr,
.scan-frame .corner-bl {
  content: '';
  position: absolute;
  width: 24px;
  height: 24px;
  border-color: var(--color-accent);
  border-style: solid;
  border-width: 0;
}

.scan-frame::before {
  top: 0;
  left: 0;
  border-top-width: 3px;
  border-left-width: 3px;
  border-radius: var(--radius-sm) 0 0 0;
}

.scan-frame::after {
  top: 0;
  right: 0;
  border-top-width: 3px;
  border-right-width: 3px;
  border-radius: 0 var(--radius-sm) 0 0;
}

.scan-frame .corner-bl {
  bottom: 0;
  left: 0;
  border-bottom-width: 3px;
  border-left-width: 3px;
  border-radius: 0 0 0 var(--radius-sm);
}

.scan-frame .corner-tr {
  bottom: 0;
  right: 0;
  border-bottom-width: 3px;
  border-right-width: 3px;
  border-radius: 0 0 var(--radius-sm) 0;
}

.scan-line {
  position: absolute;
  left: 10%;
  right: 10%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--color-accent), transparent);
  animation: scanLineMove 2s ease-in-out infinite;
}

@keyframes scanLineMove {
  0%   { top: 10%; }
  50%  { top: 85%; }
  100% { top: 10%; }
}

/* Selfie circular frame */
.selfie-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.selfie-circle {
  width: min(240px, 65%);
  aspect-ratio: 1;
  border: 3px solid var(--color-accent);
  border-radius: var(--radius-full);
  box-shadow:
    0 0 0 9999px rgb(0 0 0 / 0.5),
    0 0 0 3px var(--color-accent);
  position: relative;
}

.camera-controls {
  position: absolute;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.btn-capture {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-full);
  background: var(--color-white);
  border: 3px solid var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
  box-shadow: var(--shadow-lg);
}

.btn-capture:hover {
  transform: scale(1.05);
  box-shadow: var(--shadow-xl);
}

.btn-capture:active {
  transform: scale(0.95);
}

.btn-capture-inner {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-full);
  background: var(--color-accent);
}

/* OCR result preview */
.ocr-result {
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-top: var(--space-4);
}

.ocr-result-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.ocr-result-title {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-gray-500);
}

.ocr-field {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  gap: var(--space-3);
}

.ocr-field:last-child {
  border-bottom: none;
}

.ocr-field-label {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  flex-shrink: 0;
}

.ocr-field-value {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  text-align: right;
}

[dir="rtl"] .ocr-field-value {
  text-align: left;
}

/* ==========================================================================
   16. CHARTS PLACEHOLDER
   ========================================================================== */

.chart-container {
  position: relative;
  width: 100%;
}

.chart-container canvas {
  display: block;
  width: 100% !important;
}

.chart-container.aspect-wide {
  aspect-ratio: 16/5;
}

.chart-container.aspect-square {
  aspect-ratio: 1;
  max-width: 300px;
  margin: 0 auto;
}

.chart-container.aspect-rect {
  aspect-ratio: 4/3;
}

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

.chart-legend-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-gray-600);
}

.chart-legend-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  flex-shrink: 0;
}

/* ==========================================================================
   17. MODAL
   ========================================================================== */

/* Voile à 0.3 et non 0.5 : on veut que la page reste LISIBLE derrière la
   modale (on y vérifie souvent la ligne qu'on est en train de traiter),
   pas qu'elle disparaisse. Teinté ardoise plutôt que noir pur. */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgb(44 62 80 / 0.3);
  z-index: var(--z-modal);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  animation: fadeIn 150ms cubic-bezier(0, 0, 0.2, 1);
  backdrop-filter: blur(2px);
}

.modal {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  width: 100%;
  max-width: 560px;
  max-height: calc(100vh - var(--space-8));
  display: flex;
  flex-direction: column;
  /* 0.95 → 1 en 150ms : la modale « s'ouvre » depuis le clic. */
  animation: modalIn 150ms cubic-bezier(0, 0, 0.2, 1);
  overflow: hidden;
}

.modal-sm { max-width: 400px; }
.modal-lg { max-width: 720px; }
.modal-xl { max-width: 960px; }

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-border);
  flex-shrink: 0;
  gap: var(--space-4);
}

.modal-title {
  font-size: var(--text-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.01em;
}

.modal-close {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-gray-400);
  transition: background var(--transition-fast), color var(--transition-fast);
  flex-shrink: 0;
}

.modal-close:hover {
  background: var(--color-gray-100);
  color: var(--color-gray-900);
}

.modal-body {
  padding: var(--space-6);
  overflow-y: auto;
  flex: 1;
}

.modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-gray-50);
  flex-shrink: 0;
}

[dir="rtl"] .modal-footer {
  flex-direction: row-reverse;
}

/* ==========================================================================
   18. LOADING STATES
   ========================================================================== */

/* Spinner */
.spinner {
  display: inline-block;
  width: 24px;
  height: 24px;
  border: 2px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: var(--radius-full);
  animation: spin 0.7s linear infinite;
}

.spinner-sm { width: 16px; height: 16px; border-width: 2px; }
.spinner-lg { width: 36px; height: 36px; border-width: 3px; }
.spinner-xl { width: 48px; height: 48px; border-width: 3px; }

.spinner-accent {
  border-color: var(--color-accent-lighter);
  border-top-color: var(--color-accent);
}

.spinner-white {
  border-color: rgb(255 255 255 / 0.25);
  border-top-color: var(--color-white);
}

/* Skeleton */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--color-gray-100) 25%,
    var(--color-gray-200) 50%,
    var(--color-gray-100) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-md);
}

.skeleton-text {
  height: 1em;
  border-radius: var(--radius-sm);
}

.skeleton-text.w-3\/4 { width: 75%; }
.skeleton-text.w-1\/2 { width: 50%; }
.skeleton-text.w-full { width: 100%; }

.skeleton-circle {
  border-radius: var(--radius-full);
}

.skeleton-card {
  height: 160px;
  border-radius: var(--radius-xl);
}

/* Page loading overlay */
.page-loading {
  position: fixed;
  inset: 0;
  background: var(--color-surface);
  z-index: calc(var(--z-toast) + 100);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  animation: fadeIn var(--transition-fast) ease;
}

.page-loading-logo {
  width: 56px;
  height: 56px;
  background: var(--color-primary);
  border-radius: var(--radius-xl);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-white);
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  animation: pulse 1.5s ease-in-out infinite;
}

.page-loading-text {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}

/* ==========================================================================
   19. DARK MODE OVERRIDES
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  /* La rampe de gris s'inverse en thème sombre (section 2) : gray-900 est la
     teinte de TEXTE, gray-100 une teinte de FOND. Les règles ci-dessous
     visaient l'inverse — elles posaient du texte sombre sur fond sombre. */
  body {
    color: var(--color-gray-900);
    background-color: var(--color-bg);
  }

  h1, h2, h3, h4, h5, h6 {
    color: var(--color-gray-900);
  }

  /* .toast n'est volontairement PAS dans cette liste : c'est une notification
     posée au-dessus de la page, elle garde son fond de marque (section 12)
     dans les deux thèmes. */
  .card,
  .stat-card,
  .modal,
  .checkin-card,
  .compliance-item,
  .ocr-result,
  .signature-pad {
    background: var(--color-surface);
    border-color: var(--color-border);
  }

  .card-footer,
  .modal-footer,
  .checkin-card-footer,
  .upload-zone {
    background: var(--color-surface-raised);
  }

  .table thead th {
    background: var(--color-surface-raised);
    color: var(--color-gray-500);
  }

  .table tbody td {
    color: var(--color-gray-800);
  }

  .table-striped tbody tr:nth-child(even) td {
    background: var(--color-surface-raised);
  }

  .form-control {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-gray-900);
  }

  .form-control:focus {
    background: var(--color-surface-raised);
  }

  /* .btn-secondary : plus de surcharge ici — ses trois couleurs sont des
     tokens (--btn-secondary-fg / -border / -bg-hover) qui basculent déjà. */

  .btn-ghost:hover {
    background: var(--color-surface-raised);
  }

  .input-group-prefix,
  .input-group-suffix {
    background: var(--color-surface-raised);
    border-color: var(--color-border);
    color: var(--color-gray-500);
  }

  code {
    background: var(--color-surface-raised);
    color: var(--color-accent-strong);
  }

  /* Maroc Blue creusé : la sidebar reste la même couleur de marque, juste
     descendue d'un cran pour ne pas briller sur un fond ardoise. */
  .sidebar {
    background: #12303F;
  }

  .mobile-topbar {
    background: var(--color-surface);
    border-color: var(--color-border);
  }

  .skeleton {
    background: linear-gradient(
      90deg,
      var(--color-surface) 25%,
      var(--color-surface-raised) 50%,
      var(--color-surface) 75%
    );
    background-size: 200% 100%;
  }

  .page-loading {
    background: var(--color-bg);
  }
}

/* ==========================================================================
   20. UTILITY CLASSES
   ========================================================================== */

/* --- Text alignment --- */
.text-left    { text-align: left !important; }
.text-center  { text-align: center !important; }
.text-right   { text-align: right !important; }

[dir="rtl"] .text-left  { text-align: right !important; }
[dir="rtl"] .text-right { text-align: left !important; }

/* --- Text colors --- */
.text-muted   { color: var(--color-gray-500) !important; }
.text-primary { color: var(--color-primary) !important; }
.text-accent  { color: var(--color-accent) !important; }
.text-success { color: var(--color-success-dark) !important; }
.text-warning { color: var(--color-warning-dark) !important; }
.text-danger  { color: var(--color-danger-dark) !important; }
.text-white   { color: var(--color-white) !important; }
.text-dark    { color: var(--color-gray-900) !important; }

/* --- Text sizes --- */
.text-xs  { font-size: var(--text-xs) !important; }
.text-sm  { font-size: var(--text-sm) !important; }
.text-base{ font-size: var(--text-base) !important; }
.text-lg  { font-size: var(--text-lg) !important; }
.text-xl  { font-size: var(--text-xl) !important; }
.text-2xl { font-size: var(--text-2xl) !important; }

/* --- Font weights --- */
.font-normal   { font-weight: var(--font-weight-normal) !important; }
.font-medium   { font-weight: var(--font-weight-medium) !important; }
.font-semibold { font-weight: var(--font-weight-semibold) !important; }
.font-bold     { font-weight: var(--font-weight-bold) !important; }

/* --- Display --- */
.d-none    { display: none !important; }
.d-block   { display: block !important; }
.d-inline  { display: inline !important; }
.d-inline-block { display: inline-block !important; }
.d-flex    { display: flex !important; }
.d-grid    { display: grid !important; }

@media (min-width: 640px) {
  .d-sm-none  { display: none !important; }
  .d-sm-block { display: block !important; }
  .d-sm-flex  { display: flex !important; }
}

@media (min-width: 768px) {
  .d-md-none  { display: none !important; }
  .d-md-block { display: block !important; }
  .d-md-flex  { display: flex !important; }
}

@media (min-width: 1024px) {
  .d-lg-none  { display: none !important; }
  .d-lg-block { display: block !important; }
  .d-lg-flex  { display: flex !important; }
}

/* --- Flex --- */
.flex-wrap   { flex-wrap: wrap !important; }
.flex-nowrap { flex-wrap: nowrap !important; }
.flex-1      { flex: 1 !important; }
.flex-shrink-0 { flex-shrink: 0 !important; }

.align-start   { align-items: flex-start !important; }
.align-center  { align-items: center !important; }
.align-end     { align-items: flex-end !important; }
.align-stretch { align-items: stretch !important; }

.justify-start   { justify-content: flex-start !important; }
.justify-center  { justify-content: center !important; }
.justify-end     { justify-content: flex-end !important; }
.justify-between { justify-content: space-between !important; }
.justify-around  { justify-content: space-around !important; }

.flex-col { flex-direction: column !important; }
.flex-row { flex-direction: row !important; }

[dir="rtl"] .flex-row    { flex-direction: row-reverse !important; }
[dir="rtl"] .flex-row-rtl-keep { flex-direction: row !important; }

/* --- Gaps --- */
.gap-1 { gap: var(--space-1) !important; }
.gap-2 { gap: var(--space-2) !important; }
.gap-3 { gap: var(--space-3) !important; }
.gap-4 { gap: var(--space-4) !important; }
.gap-6 { gap: var(--space-6) !important; }
.gap-8 { gap: var(--space-8) !important; }

/* --- Margins --- */
.m-0  { margin: 0 !important; }
.mt-0 { margin-top: 0 !important; }
.mt-1 { margin-top: var(--space-1) !important; }
.mt-2 { margin-top: var(--space-2) !important; }
.mt-3 { margin-top: var(--space-3) !important; }
.mt-4 { margin-top: var(--space-4) !important; }
.mt-5 { margin-top: var(--space-5) !important; }
.mt-6 { margin-top: var(--space-6) !important; }
.mt-8 { margin-top: var(--space-8) !important; }

.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: var(--space-1) !important; }
.mb-2 { margin-bottom: var(--space-2) !important; }
.mb-3 { margin-bottom: var(--space-3) !important; }
.mb-4 { margin-bottom: var(--space-4) !important; }
.mb-5 { margin-bottom: var(--space-5) !important; }
.mb-6 { margin-bottom: var(--space-6) !important; }
.mb-8 { margin-bottom: var(--space-8) !important; }

.ms-auto { margin-inline-start: auto !important; }
.me-auto { margin-inline-end: auto !important; }
.mx-auto { margin-inline: auto !important; }

/* --- Paddings --- */
.p-0 { padding: 0 !important; }
.p-2 { padding: var(--space-2) !important; }
.p-3 { padding: var(--space-3) !important; }
.p-4 { padding: var(--space-4) !important; }
.p-5 { padding: var(--space-5) !important; }
.p-6 { padding: var(--space-6) !important; }

.px-2 { padding-inline: var(--space-2) !important; }
.px-3 { padding-inline: var(--space-3) !important; }
.px-4 { padding-inline: var(--space-4) !important; }
.px-6 { padding-inline: var(--space-6) !important; }

.py-2 { padding-block: var(--space-2) !important; }
.py-3 { padding-block: var(--space-3) !important; }
.py-4 { padding-block: var(--space-4) !important; }
.py-6 { padding-block: var(--space-6) !important; }

/* --- Width / Height --- */
.w-full  { width: 100% !important; }
.h-full  { height: 100% !important; }
.w-auto  { width: auto !important; }
.min-w-0 { min-width: 0 !important; }

/* --- Borders --- */
.border        { border: 1px solid var(--color-border) !important; }
.border-top    { border-top: 1px solid var(--color-border) !important; }
.border-bottom { border-bottom: 1px solid var(--color-border) !important; }
.border-none   { border: none !important; }

.rounded    { border-radius: var(--radius-md) !important; }
.rounded-sm { border-radius: var(--radius-sm) !important; }
.rounded-lg { border-radius: var(--radius-lg) !important; }
.rounded-xl { border-radius: var(--radius-xl) !important; }
.rounded-full { border-radius: var(--radius-full) !important; }

/* --- Overflow --- */
.overflow-hidden { overflow: hidden !important; }
.overflow-auto   { overflow: auto !important; }
.overflow-x-auto { overflow-x: auto !important; }

/* --- Position --- */
.relative { position: relative !important; }
.absolute { position: absolute !important; }
.fixed    { position: fixed !important; }
.sticky   { position: sticky !important; top: 0; }

/* --- Text --- */
.truncate {
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}

.whitespace-nowrap { white-space: nowrap !important; }
.break-words { word-break: break-word !important; }

/* --- Screen reader only --- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

/* --- Honeypot field (anti-bot) : masqué visuellement SANS débordement.
   `left:-9999px` cassait la mise en page RTL (barre de défilement horizontale,
   contenu collé à droite) — cette technique (1px + clip) ne déborde jamais. --- */
.hp-field {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  padding: 0;
  margin: -1px;
}

/* --- Shadow utilities --- */
.shadow-none { box-shadow: none !important; }
.shadow-sm   { box-shadow: var(--shadow-sm) !important; }
.shadow-md   { box-shadow: var(--shadow-md) !important; }
.shadow-lg   { box-shadow: var(--shadow-lg) !important; }

/* --- Background --- */
.bg-white    { background: var(--color-white) !important; }
.bg-surface  { background: var(--color-surface) !important; }
.bg-gray-50  { background: var(--color-gray-50) !important; }
.bg-primary  { background: var(--color-primary) !important; }
.bg-accent   { background: var(--color-accent) !important; }

/* --- Opacity --- */
.opacity-0   { opacity: 0 !important; }
.opacity-50  { opacity: 0.5 !important; }
.opacity-100 { opacity: 1 !important; }

/* --- Cursor --- */
.cursor-pointer  { cursor: pointer !important; }
.cursor-default  { cursor: default !important; }
.cursor-not-allowed { cursor: not-allowed !important; }

/* --- Transition --- */
.transition { transition: all var(--transition-base) !important; }
.transition-fast { transition: all var(--transition-fast) !important; }

/* ==========================================================================
   21. RTL COMPREHENSIVE OVERRIDES
   ========================================================================== */

[dir="rtl"] {
  /* Sidebar and layout */
  .main-content {
    margin-left: 0;
    margin-right: var(--sidebar-width);
  }

  /* Page header actions */
  .page-header {
    flex-direction: row-reverse;
  }

  /* Form controls */
  .form-control {
    text-align: right;
  }

  /* Table */
  .table thead th,
  .table tbody td {
    text-align: right;
  }

  /* Card header */
  .card-header {
    flex-direction: row-reverse;
  }

  /* Stat card */
  .stat-card-header {
    flex-direction: row-reverse;
  }

  /* Nav badge auto margin */
  .nav-badge {
    margin-left: 0;
    margin-right: auto;
  }

  /* Checkin footer */
  .checkin-card-footer {
    flex-direction: row-reverse;
  }

  /* Compliance badge */
  .compliance-badge {
    margin-left: 0;
    margin-right: auto;
  }

  /* Toast */
  .toast-container {
    right: auto;
    left: var(--space-4);
  }

  /* Input group */
  .input-group-prefix {
    border-right: 1px solid var(--color-border);
    border-left: none;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
  }

  .input-group-suffix {
    border-left: 1px solid var(--color-border);
    border-right: none;
    border-radius: var(--radius-md) 0 0 var(--radius-md);
  }

  .input-group .form-control:first-child {
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
  }

  .input-group .form-control:last-child {
    border-radius: var(--radius-md) 0 0 var(--radius-md);
  }

  /* Flip arrow icons used for navigation */
  .icon-arrow-right,
  .icon-chevron-right,
  [class*="icon-arrow"],
  [class*="icon-chevron"] {
    transform: scaleX(-1);
  }
}

/* ==========================================================================
   22. COMPONENT: EMPTY STATES
   ========================================================================== */

.empty-state {
  text-align: center;
  padding: var(--space-16) var(--space-4);
}

.empty-state-icon {
  width: 64px;
  height: 64px;
  margin: 0 auto var(--space-5);
  color: var(--color-gray-300);
}

.empty-state-title {
  font-size: var(--text-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-700);
  margin-bottom: var(--space-2);
}

.empty-state-description {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  max-width: 340px;
  margin: 0 auto var(--space-6);
}

/* ==========================================================================
   23. COMPONENT: DROPDOWN MENU
   ========================================================================== */

.dropdown {
  position: relative;
  display: inline-block;
}

.dropdown-menu {
  position: absolute;
  top: calc(100% + var(--space-2));
  left: 0;
  min-width: 200px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-1);
  z-index: var(--z-dropdown);
  animation: fadeInUp var(--transition-fast) ease;
}

.dropdown-menu.menu-right {
  left: auto;
  right: 0;
}

[dir="rtl"] .dropdown-menu {
  left: auto;
  right: 0;
}

[dir="rtl"] .dropdown-menu.menu-right {
  right: auto;
  left: 0;
}

.dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-gray-700);
  border-radius: var(--radius-md);
  transition: background var(--transition-fast), color var(--transition-fast);
  cursor: pointer;
  text-decoration: none;
  width: 100%;
  text-align: left;
}

[dir="rtl"] .dropdown-item {
  text-align: right;
}

.dropdown-item:hover {
  background: var(--color-gray-50);
  color: var(--color-gray-900);
}

.dropdown-item.danger {
  color: var(--color-danger);
}

.dropdown-item.danger:hover {
  background: var(--color-danger-light);
}

.dropdown-divider {
  height: 1px;
  background: var(--color-border);
  margin: var(--space-1) 0;
}

/* ==========================================================================
   24. COMPONENT: PAGINATION
   ========================================================================== */

.pagination {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

[dir="rtl"] .pagination {
  flex-direction: row-reverse;
}

.page-item {
  display: flex;
}

.page-link {
  min-width: 36px;
  height: 36px;
  padding: 0 var(--space-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-700);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  transition:
    background var(--transition-fast),
    border-color var(--transition-fast),
    color var(--transition-fast);
}

.page-link:hover {
  background: var(--color-gray-50);
  border-color: var(--color-gray-300);
  color: var(--color-gray-900);
}

.page-item.active .page-link {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

.page-item.disabled .page-link {
  opacity: 0.4;
  pointer-events: none;
}

/* ==========================================================================
   25. COMPONENT: TABS
   ========================================================================== */

.tabs {
  border-bottom: 1px solid var(--color-border);
  display: flex;
  /* gap:0 collait les onglets les uns aux autres — on ne voyait plus où
     l'un finissait et où l'autre commençait. */
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.tabs::-webkit-scrollbar { display: none; }

.tab-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* 44px de haut : un onglet est une cible, au doigt comme à la souris. */
  min-height: 44px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-500);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition:
    color var(--transition-fast),
    background var(--transition-fast),
    border-color var(--transition-fast);
  margin-bottom: -1px;
}

.tab-item:hover {
  color: var(--color-gray-900);
  background: var(--color-gray-50);
  border-bottom-color: var(--color-gray-300);
  text-decoration: none;
}

.tab-item.active {
  color: var(--color-primary-ink);
  border-bottom-color: var(--color-primary);
  font-weight: var(--font-weight-semibold);
}

/* Pastille de l'onglet : compte d'erreurs de validation. Elle n'apparaît que
   quand le serveur a renvoyé des erreurs — sinon un onglet masqué pourrait
   contenir un champ en faute sans que rien ne le signale. */
.tab-item-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--color-danger);
  color: var(--color-white);
  font-size: 11px;
  font-weight: var(--font-weight-bold);
  line-height: 1;
}
.tab-item.has-errors { color: var(--color-danger-dark); }
.tab-item.has-errors.active { border-bottom-color: var(--color-danger); }

.tab-content {
  padding-top: var(--space-6);
}

.tab-pane {
  display: none;
  animation: fadeIn var(--transition-fast) ease;
}

.tab-pane.active {
  display: block;
}

/* ==========================================================================
   26. COMPONENT: AVATAR
   ========================================================================== */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
  font-weight: var(--font-weight-semibold);
  overflow: hidden;
  flex-shrink: 0;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-xs  { width: 24px; height: 24px; font-size: var(--text-xs); }
.avatar-sm  { width: 32px; height: 32px; font-size: var(--text-xs); }
.avatar-md  { width: 40px; height: 40px; font-size: var(--text-sm); }
.avatar-lg  { width: 48px; height: 48px; font-size: var(--text-base); }
.avatar-xl  { width: 64px; height: 64px; font-size: var(--text-xl); }

.avatar-group {
  display: flex;
}

.avatar-group .avatar {
  border: 2px solid var(--color-surface);
  margin-left: -8px;
}

.avatar-group .avatar:first-child {
  margin-left: 0;
}

[dir="rtl"] .avatar-group .avatar {
  margin-left: 0;
  margin-right: -8px;
}

[dir="rtl"] .avatar-group .avatar:first-child {
  margin-right: 0;
}

/* ==========================================================================
   27. COMPONENT: PROPERTY CARD (domain specific)
   ========================================================================== */

.property-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition-base), transform var(--transition-base);
}

.property-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.property-card-image {
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
  background: var(--color-gray-100);
}

.property-card-body {
  padding: var(--space-4) var(--space-5);
}

.property-card-name {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  margin-bottom: var(--space-1);
}

.property-card-location {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.property-card-footer {
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.property-card-stat {
  text-align: center;
}

.property-card-stat-value {
  font-size: var(--text-lg);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  display: block;
}

.property-card-stat-label {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
}

/* ==========================================================================
   28. COMPONENT: GUEST CARD (domain specific)
   ========================================================================== */

.guest-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.guest-card:hover {
  border-color: var(--color-gray-300);
  box-shadow: var(--shadow-sm);
}

.guest-card-info {
  flex: 1;
  min-width: 0;
}

.guest-card-name {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.guest-card-meta {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  margin-top: var(--space-0-5);
}

.guest-card-status {
  flex-shrink: 0;
}

/* ==========================================================================
   29. COMPONENT: BOOKING TIMELINE
   ========================================================================== */

.timeline {
  position: relative;
  padding-left: var(--space-8);
}

[dir="rtl"] .timeline {
  padding-left: 0;
  padding-right: var(--space-8);
}

.timeline::before {
  content: '';
  position: absolute;
  left: 20px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--color-border);
}

[dir="rtl"] .timeline::before {
  left: auto;
  right: 20px;
}

.timeline-item {
  position: relative;
  padding-bottom: var(--space-6);
}

.timeline-item:last-child {
  padding-bottom: 0;
}

.timeline-dot {
  position: absolute;
  left: calc(-1 * var(--space-8) + 12px);
  top: 3px;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: 2px solid var(--color-border);
  z-index: 1;
}

[dir="rtl"] .timeline-dot {
  left: auto;
  right: calc(-1 * var(--space-8) + 12px);
}

.timeline-dot.active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-50);
}

.timeline-dot.success {
  background: var(--color-success);
  border-color: var(--color-success);
}

.timeline-content {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
}

.timeline-time {
  font-size: var(--text-xs);
  color: var(--color-gray-400);
  margin-bottom: var(--space-1);
}

.timeline-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
}

.timeline-description {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  margin-top: var(--space-1);
}

/* ==========================================================================
   30. COMPONENT: SEARCH BAR
   ========================================================================== */

.search-bar {
  position: relative;
  display: flex;
  align-items: center;
}

.search-bar-icon {
  position: absolute;
  left: var(--space-3);
  color: var(--color-gray-400);
  pointer-events: none;
  width: 18px;
  height: 18px;
}

[dir="rtl"] .search-bar-icon {
  left: auto;
  right: var(--space-3);
}

.search-bar .form-control {
  padding-left: var(--space-10);
}

[dir="rtl"] .search-bar .form-control {
  padding-left: var(--space-3);
  padding-right: var(--space-10);
}

.search-bar-clear {
  position: absolute;
  right: var(--space-3);
  color: var(--color-gray-400);
  cursor: pointer;
  width: 18px;
  height: 18px;
  display: none;
}

[dir="rtl"] .search-bar-clear {
  right: auto;
  left: var(--space-3);
}

.search-bar:has(input:not(:placeholder-shown)) .search-bar-clear {
  display: block;
}

/* ==========================================================================
   31. PRINT STYLES
   ========================================================================== */

@media print {
  .sidebar,
  .mobile-topbar,
  .sidebar-overlay,
  .toast-container,
  .modal-overlay,
  .btn-icon,
  .page-header-actions {
    display: none !important;
  }

  .main-content {
    margin: 0 !important;
    padding: 0 !important;
  }

  .card {
    box-shadow: none !important;
    border: 1px solid var(--color-gray-300) !important;
  }

  body {
    font-size: 12px;
    color: #000 !important;
    background: #fff !important;
  }

  h1, h2, h3, h4, h5, h6 {
    color: #000 !important;
  }
}

/* ==========================================================================
   32. CHECKIN GUEST FORM — Layout & Component Styles
   ========================================================================== */

/* ── Global SVG icon constraint ── */
/* Buttons and inline icons must not inherit max-width:100% from the reset */
.btn svg,
.nav-link svg,
.alert-icon,
.step-progress-check,
.consent-highlight-item svg,
.confirm-check-item svg,
.ocr-result-header svg,
.ocr-failed svg,
.footer-security svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* ── Body / Page shell ── */
body.layout-checkin {
  min-height: 100vh;
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

/* ── Header ── */
.checkin-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  gap: var(--space-4);
}

.checkin-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
  color: var(--color-gray-900);
  font-size: var(--text-lg);
  font-weight: var(--font-weight-bold);
  letter-spacing: -0.02em;
}

.checkin-logo-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
}

.checkin-lang {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.lang-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 32px;
  padding: 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-500);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.lang-btn:hover {
  background: var(--color-gray-100);
  color: var(--color-gray-900);
}

.lang-btn.is-active {
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
  border-color: var(--color-primary-100);
}

/* ── Property banner ── */
.checkin-property-banner {
  background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-lighter) 100%);
  color: var(--color-white);
  padding: var(--space-3) var(--space-4);
}

.checkin-property-banner-inner {
  max-width: 720px;
  margin-inline: auto;
}

.checkin-property-info {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.checkin-property-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: rgb(255 255 255 / 0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.checkin-property-icon svg {
  width: 20px;
  height: 20px;
  color: var(--color-white);
}

.checkin-property-name {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-white);
  margin-bottom: var(--space-0-5);
}

.checkin-property-dates {
  font-size: var(--text-sm);
  color: rgb(255 255 255 / 0.8);
  line-height: 1.4;
}

/* ── Main content wrapper ── */
.checkin-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-6) var(--space-4) var(--space-12);
}

.checkin-container {
  width: 100%;
  max-width: 680px;
}

/* ── Step progress indicator ── */
.step-progress {
  margin-bottom: var(--space-6);
}

.step-progress-list {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  position: relative;
  list-style: none;
  padding: 0;
  margin: 0;
}

/* connecting line between dots */
.step-progress-list::before {
  content: '';
  position: absolute;
  top: 16px;
  left: calc(100% / 12);
  right: calc(100% / 12);
  height: 2px;
  background: var(--color-border);
  z-index: 0;
}

.step-progress-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  flex: 1;
  position: relative;
  z-index: 1;
}

.step-progress-dot {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  border: 2px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-base), border-color var(--transition-base);
  position: relative;
}

.step-progress-num {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-400);
}

.step-progress-check {
  width: 14px !important;
  height: 14px !important;
  color: var(--color-white);
  display: none;
}

.step-progress-label {
  font-size: 10px;
  color: var(--color-gray-400);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 72px;
}

/* Active step */
.step-progress-item.is-active .step-progress-dot {
  background: var(--color-primary);
  border-color: var(--color-primary);
  box-shadow: 0 0 0 4px var(--color-primary-50);
}

.step-progress-item.is-active .step-progress-num {
  color: var(--color-white);
}

.step-progress-item.is-active .step-progress-label {
  color: var(--color-primary-ink);
  font-weight: var(--font-weight-semibold);
}

/* Done step */
.step-progress-item.is-done .step-progress-dot {
  background: var(--color-success);
  border-color: var(--color-success);
}

.step-progress-item.is-done .step-progress-num { display: none; }
.step-progress-item.is-done .step-progress-check { display: block; }

.step-progress-item.is-done .step-progress-label {
  color: var(--color-success-dark);
}

@media (max-width: 480px) {
  .step-progress-label { display: none; }
  .step-progress-item.is-active .step-progress-label { display: block; }
}

/* ── Checkin step card ── */
.checkin-step {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  animation: fadeInUp var(--transition-slow) ease;
}

/* ── Step header ── */
.step-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-6) var(--space-4);
  border-bottom: 1px solid var(--color-border-subtle);
}

.step-icon {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-xl);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
}

.step-icon svg {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
}

/* Colour variants */
.step-icon--shield  { background: var(--color-primary-50); color: var(--color-primary-ink); }
.step-icon--person  { background: var(--color-primary-50); color: var(--color-primary-ink); }
.step-icon--card    { background: var(--color-accent-50);  color: var(--color-accent-strong); }
.step-icon--selfie  { background: var(--color-accent-50);  color: var(--color-accent-strong); }
.step-icon--contract{ background: var(--color-warning-light); color: var(--color-warning-dark); }
.step-icon--confirm { background: var(--color-success-light); color: var(--color-success-dark); }

.step-title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
  margin: 0;
}

.step-hint {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  margin: 0;
  line-height: var(--leading-relaxed);
}

/* ── Step body ── */
.step-body {
  padding: var(--space-6);
}

/* ── Step footer ── */
.step-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-gray-50);
}

/* Mobile : un bouton .btn--full (width:100%) partagerait la ligne avec
   "Précédent" et le recouvrirait — on le passe sur sa propre ligne. */
@media (max-width: 480px) {
  .step-footer {
    flex-wrap: wrap;
  }
  .step-footer .btn--full {
    flex-basis: 100%;
  }
}

/* ── Form fields (checkin-specific aliases) ── */
.form-input,
.form-select {
  display: block;
  width: 100%;
  padding: 0.625rem var(--space-3);
  font-size: var(--text-base);
  font-family: inherit;
  color: var(--color-gray-900);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  line-height: var(--leading-normal);
  appearance: none;
  -webkit-appearance: none;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.form-input:focus,
.form-select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--shadow-focus);
}

.form-input.is-invalid,
.form-select.is-invalid {
  border-color: var(--color-danger);
}

.form-input--lg { font-size: var(--text-lg); padding: 0.75rem var(--space-4); }

.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236b7280'%3E%3Cpath fill-rule='evenodd' d='M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z' clip-rule='evenodd'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  background-size: 16px;
  padding-right: var(--space-10);
  cursor: pointer;
}

[dir="rtl"] .form-select {
  background-position: left var(--space-3) center;
  padding-right: var(--space-3);
  padding-left: var(--space-10);
}

.form-label--required::after {
  content: ' *';
  color: var(--color-danger);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

/* ── Téléphone scindé : <select> d'indicatif + numéro national ──
   Utilisé par l'inscription (le même champ que la landing Meta). L'indicatif
   garde une largeur fixe, le numéro occupe le reste de la ligne. */
.tel-split {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
}

.tel-split__code {
  flex: 0 0 9.5rem;
  width: 9.5rem;
  padding-left: var(--space-2);
  padding-right: var(--space-6);
  background-position: right var(--space-2) center;
  text-overflow: ellipsis;
}

[dir="rtl"] .tel-split__code {
  padding-right: var(--space-2);
  padding-left: var(--space-6);
  background-position: left var(--space-2) center;
}

.tel-split > .form-input {
  flex: 1 1 auto;
  min-width: 0;
  direction: ltr;
}

@media (max-width: 380px) {
  .tel-split { flex-wrap: wrap; }
  .tel-split__code { flex-basis: 100%; width: 100%; }
}

/* Éléments dépliés/masqués par le check-in (résidence, entrée au Maroc) : sans
   cette règle, un `display` explicite (.btn, .form-group) l'emporte sur [hidden]. */
#sameAddressBtn[hidden],
#entreePointDetailGroup[hidden],
.entree-block[hidden] { display: none !important; }

/* G25 — Panneaux OCR (chargement / succès / échec) : `.ocr-processing` et
   `.ocr-failed` portent `display: flex`, qui l'emporte sur [hidden]. Sans cette
   règle, « Extraction en cours… » et « Extraction échouée » restaient affichés
   en permanence (et en même temps que le succès), quel que soit le résultat. */
.ocr-section[hidden],
.ocr-processing[hidden],
.ocr-result[hidden],
.ocr-failed[hidden] { display: none !important; }

/* G27 — bloc « Enfants » de l'étape Informations : même piège (.alert a un
   `display`), la zone d'erreur vide restait affichée. */
.minors-block[hidden],
#minorsError[hidden] { display: none !important; }

#sameAddressBtn { margin-bottom: var(--space-3); }

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

.form-section-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-700);
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
}

/* ── Button size modifiers ── */
.btn--full { width: 100%; }
.btn--lg {
  padding: 0.75rem var(--space-6);
  font-size: var(--text-base);
  border-radius: var(--radius-lg);
}
.btn--sm {
  padding: 0.4375rem var(--space-3);
  font-size: var(--text-sm);
}
.btn--xs {
  padding: 0.3125rem var(--space-2);
  font-size: var(--text-xs);
  border-radius: var(--radius-sm);
}
.btn--capture {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-full);
  background: var(--color-white);
  border: 3px solid var(--color-primary);
  box-shadow: var(--shadow-lg);
  padding: 0;
  flex-shrink: 0;
}
.btn--capture:hover { transform: scale(1.05); }
.btn--capture:active { transform: scale(0.95); }

.capture-btn-inner {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
}

/* ── Consent box ── */
.consent-box {
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  margin-bottom: var(--space-5);
}

.consent-text {
  font-size: var(--text-sm);
  color: var(--color-gray-700);
  line-height: var(--leading-relaxed);
  margin-bottom: var(--space-4);
}

.consent-highlights {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.consent-highlight-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-gray-700);
}

.consent-highlight-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--color-primary-ink);
}

.cndp-badge {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}

.cndp-text {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
}

/* ── Custom checkbox ── */
.checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  cursor: pointer;
  user-select: none;
}

.checkbox-label--consent {
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.checkbox-label--consent:has(.checkbox-input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
}

.checkbox-input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.checkbox-custom {
  width: 20px;
  height: 20px;
  border: 2px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-white);
  flex-shrink: 0;
  margin-top: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-fast), border-color var(--transition-fast);
  position: relative;
}

.checkbox-input:checked + .checkbox-custom {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

.checkbox-input:checked + .checkbox-custom::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 6px;
  width: 5px;
  height: 9px;
  border: 2px solid white;
  border-top: none;
  border-left: none;
  transform: rotate(45deg);
}

.checkbox-input:focus-visible + .checkbox-custom {
  box-shadow: var(--shadow-focus);
}

.checkbox-text {
  font-size: var(--text-sm);
  color: var(--color-gray-700);
  line-height: 1.5;
}

/* ── Document type selector ── */
.doc-type-selector {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.doc-type-option { cursor: pointer; }

.doc-type-radio { position: absolute; opacity: 0; width: 0; height: 0; }

.doc-type-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border: 2px solid var(--color-border);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-600);
  background: var(--color-surface);
  transition: border-color var(--transition-fast), background var(--transition-fast), color var(--transition-fast);
  min-width: 90px;
  text-align: center;
}

.doc-type-card svg {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}

.doc-type-radio:checked + .doc-type-card {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
}

/* ── Document capture area ── */
.doc-capture-area {
  margin-top: var(--space-4);
}

.doc-capture-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.doc-preview-img {
  width: 100%;
  max-width: 420px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border);
  object-fit: contain;
}

.doc-capture-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.capture-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6);
  border: 2px dashed var(--color-border);
  border-radius: var(--radius-xl);
  background: var(--color-gray-50);
  width: 100%;
}

.capture-placeholder svg {
  width: 80px;
  height: 60px;
  flex-shrink: 0;
}

.capture-hint {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  text-align: center;
  margin: 0;
}

.capture-btn-row {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  flex-wrap: wrap;
}

/* ── Camera view ── */
.doc-camera-view {
  position: relative;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: #000;
  aspect-ratio: 4/3;
}

.camera-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.camera-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.camera-frame--card {
  width: 80%;
  aspect-ratio: 85/54;
  border: 2px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--radius-md);
  box-shadow: 0 0 0 9999px rgba(0,0,0,0.4);
}

.camera-controls {
  position: absolute;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* ── OCR section ── */
.ocr-section {
  margin-top: var(--space-4);
}

.ocr-processing {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6);
  color: var(--color-gray-600);
  font-size: var(--text-sm);
}

.ocr-spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: var(--radius-full);
  animation: spin 0.7s linear infinite;
  flex-shrink: 0;
}

.ocr-result {
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

.ocr-result-header {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-success-dark);
}

.ocr-result-header svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--color-success);
}

.ocr-failed {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--color-danger-light);
  border: 1px solid rgb(239 68 68 / 0.2);
  border-radius: var(--radius-lg);
  font-size: var(--text-sm);
  color: var(--color-danger-dark);
}

.ocr-failed svg {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.doc-manual-fields {
  margin-top: var(--space-4);
}

/* ── Selfie area ── */
.selfie-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.selfie-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.selfie-img {
  width: 240px;
  height: 240px;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 3px solid var(--color-primary);
  box-shadow: var(--shadow-lg);
}

.selfie-camera-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.selfie-camera-wrapper {
  position: relative;
  width: 100%;
  max-width: 400px;
  aspect-ratio: 1;
  border-radius: var(--radius-full);
  overflow: hidden;
  background: #000;
  box-shadow: var(--shadow-xl);
}

.selfie-camera-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scaleX(-1);
}

.selfie-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.selfie-frame-circle {
  width: 90%;
  height: 90%;
  border-radius: var(--radius-full);
  border: 3px solid var(--color-accent);
  box-shadow: 0 0 0 9999px rgb(0 0 0 / 0.4);
}

.selfie-liveness-hint {
  font-size: var(--text-sm);
  color: var(--color-gray-600);
  text-align: center;
  margin: 0;
}

.selfie-controls {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* ── Contract ── */
.contract-text-wrapper {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: auto;
  max-height: 260px;
  margin-bottom: var(--space-5);
  background: var(--color-gray-50);
}

.contract-text {
  padding: var(--space-5);
  font-size: var(--text-sm);
  color: var(--color-gray-700);
  line-height: var(--leading-relaxed);
}

/* ── Signature section ── */
.signature-section {
  margin-bottom: var(--space-5);
}

.signature-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-2);
}

.signature-pad-wrapper {
  position: relative;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-white);
  overflow: hidden;
}

.signature-pad {
  display: block;
  width: 100%;
  height: 160px;
  cursor: crosshair;
  touch-action: none;
}

.signature-pad-hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  color: var(--color-gray-300);
  pointer-events: none;
}

/* Confirmation « Signé ✓ » — contraste renforcé (fond vert clair, texte vert
   foncé) pour être clairement visible sous le pavé de signature. */
.signature-status {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--color-success-light);
  border: 1px solid var(--color-success);
  border-radius: var(--radius-md);
  color: var(--color-success-dark);
  font-size: var(--text-sm);
  font-weight: 600;
}

.signature-status svg {
  flex: 0 0 auto;
  width: 1.15rem;
  height: 1.15rem;
  color: var(--color-success);
}

[dir="rtl"] .signature-status {
  flex-direction: row-reverse;
}

/* ── Écran récapitulatif multi-voyageurs ── */
.recap-actions {
  margin-bottom: var(--space-5);
}

.recap-action-hint {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  line-height: 1.5;
}

.recap-link-box {
  margin-top: var(--space-4);
  padding: var(--space-4);
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.recap-link-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-2);
}

.recap-link-row .form-input {
  flex: 1 1 auto;
  min-width: 0;
}

.recap-copied {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-success-dark);
}

.recap-children {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-border);
}

/* ── Summary card ── */
.summary-card {
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}

.summary-list {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.summary-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
  padding: var(--space-2-5, 0.625rem) 0;
  border-bottom: 1px solid var(--color-border-subtle);
}

.summary-item:last-child { border-bottom: none; }

.summary-label {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  flex-shrink: 0;
}

.summary-value {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  text-align: right;
}

[dir="rtl"] .summary-value { text-align: left; }

/* ── Confirm checks ── */
.confirm-checks {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.confirm-check-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-gray-700);
}

.confirm-check-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--color-success);
}

.confirm-terms {
  font-size: var(--text-xs);
  line-height: var(--leading-relaxed);
}

/* ── Footer ── */
.checkin-footer {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: var(--space-4);
}

.checkin-footer-inner {
  max-width: 680px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.footer-security {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}

.footer-security svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.footer-badges {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.footer-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-0-5) var(--space-2);
  font-size: 10px;
  font-weight: var(--font-weight-bold);
  border-radius: var(--radius-sm);
  letter-spacing: 0.04em;
}

.footer-badge--cndp {
  background: var(--color-primary-50);
  color: var(--color-primary-ink);
}

.footer-badge--voyageur {
  background: var(--color-accent-50);
  color: var(--color-accent-strong);
}

.footer-badge--ssl {
  background: var(--color-success-light);
  color: var(--color-success-dark);
}

.footer-badge--ssl svg {
  width: 12px;
  height: 12px;
}

/* ── Alert variants for checkin ── */
.alert--top {
  position: fixed;
  top: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-toast);
  max-width: 480px;
  width: calc(100% - var(--space-8));
  animation: slideDown var(--transition-base) ease;
}

.alert--success {
  background: var(--color-success-light);
  border-color: rgb(34 197 94 / 0.2);
  color: var(--color-success-dark);
}

.alert--error {
  background: var(--color-danger-light);
  border-color: rgb(239 68 68 / 0.2);
  color: var(--color-danger-dark);
}

.alert--dismissible {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
  font-size: var(--text-sm);
  box-shadow: var(--shadow-lg);
}

.alert-close {
  margin-left: auto;
  background: none;
  border: none;
  font-size: var(--text-lg);
  line-height: 1;
  color: currentColor;
  opacity: 0.6;
  cursor: pointer;
  padding: 0 var(--space-1);
  flex-shrink: 0;
}

.alert-close:hover { opacity: 1; }

.alert-message { flex: 1; }

/* ==========================================================================
   33. BRIDGE — Sidebar Navigation (HTML uses sidebar-nav-* BEM naming)
   ========================================================================== */

/* Sidebar open/close — JS uses .is-open / .is-visible */
@media (max-width: 1023px) {
  .sidebar.is-open {
    transform: translateX(0);
  }
  [dir="rtl"] .sidebar.is-open {
    transform: translateX(0);
  }
  .sidebar-overlay.is-visible {
    display: block;
  }

  /* Le .mobile-header (sticky, z-sticky, après la sidebar dans le DOM)
     peindrait par-dessus la sidebar ouverte : on élève sidebar + overlay
     au-dessus de lui, l'overlay couvrant aussi le header. */
  .sidebar {
    z-index: calc(var(--z-sticky) + 2);
  }
  .sidebar-overlay {
    z-index: calc(var(--z-sticky) + 1);
  }
}

/* Logo inside sidebar */
.sidebar-brand {
  display: flex;
  align-items: center;
  padding: 0 var(--space-5);
  min-height: var(--header-height);
  border-bottom: 1px solid rgb(255 255 255 / 0.08);
  flex-shrink: 0;
}
.sidebar-logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
}
.sidebar-logo-icon {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.sidebar-logo-text {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-white);
  letter-spacing: -0.01em;
  line-height: 1;
}
.sidebar-logo-dot { color: var(--color-accent); }

/* Nav list */
.sidebar-nav {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-4) 0;
  scrollbar-width: thin;
  scrollbar-color: rgb(255 255 255 / 0.1) transparent;
}
.sidebar-nav::-webkit-scrollbar { width: 4px; }
.sidebar-nav::-webkit-scrollbar-track { background: transparent; }
.sidebar-nav::-webkit-scrollbar-thumb {
  background: rgb(255 255 255 / 0.1);
  border-radius: var(--radius-full);
}
.sidebar-nav-list {
  list-style: none;
  padding: 0 var(--space-3);
}
.sidebar-nav-item {
  margin-bottom: var(--space-1);
}
.sidebar-nav-divider {
  height: 1px;
  background: rgb(255 255 255 / 0.08);
  margin: var(--space-2) 0;
}
.sidebar-nav-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0.625rem var(--space-3);
  border-radius: var(--radius-md);
  color: rgb(255 255 255 / 0.65);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  transition: background var(--transition-fast), color var(--transition-fast);
  position: relative;
  white-space: nowrap;
}
.sidebar-nav-link:hover {
  background: rgb(255 255 255 / 0.08);
  color: var(--color-white);
}
/* Au doigt, un item de menu est une cible de 44px minimum. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) {
  .sidebar-nav-link { min-height: 44px; }
}
.sidebar-nav-link.is-active {
  background: rgb(255 255 255 / 0.12);
  color: var(--color-white);
}
.sidebar-nav-link.is-active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 60%;
  background: var(--color-accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
[dir="rtl"] .sidebar-nav-link.is-active::before {
  left: auto;
  right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
}
.sidebar-nav-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  opacity: 0.75;
}
.sidebar-nav-link.is-active .sidebar-nav-icon,
.sidebar-nav-link:hover .sidebar-nav-icon { opacity: 1; }
.sidebar-nav-label { flex: 1; }

/* ---- Groupe de menu repliable (« Réception ») ----
   <details>/<summary> natif : repliable sans JavaScript, utilisable au
   clavier. On neutralise le marqueur par défaut du navigateur et on fournit
   notre propre chevron, qui tourne à l'ouverture. */
.sidebar-nav-group > summary {
  cursor: pointer;
  list-style: none;
}
.sidebar-nav-group > summary::-webkit-details-marker,
.sidebar-nav-group > summary::marker {
  display: none;
  content: '';
}
.sidebar-nav-chevron {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  opacity: 0.6;
  transition: transform var(--transition-fast);
}
.sidebar-nav-group[open] > summary .sidebar-nav-chevron {
  transform: rotate(180deg);
}
.sidebar-nav-sublist {
  list-style: none;
  margin: var(--space-1) 0 var(--space-2);
  /* Aligné sous le libellé du parent, pas sous son icône : la hiérarchie se
     lit sans compter les pixels. */
  padding-inline-start: calc(var(--space-3) + 20px + var(--space-3));
}
.sidebar-nav-sublink {
  display: block;
  padding: 0.5rem var(--space-3);
  border-radius: var(--radius-md);
  color: rgb(255 255 255 / 0.55);
  text-decoration: none;
  font-size: var(--text-sm);
  line-height: 1.3;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.sidebar-nav-sublink:hover {
  background: rgb(255 255 255 / 0.08);
  color: var(--color-white);
}
.sidebar-nav-sublink.is-active {
  background: rgb(255 255 255 / 0.12);
  color: var(--color-white);
  font-weight: var(--font-weight-medium);
}
/* Au doigt, une sous-entrée reste une cible de 44px. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) {
  .sidebar-nav-sublink {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
}

/* ---- Saisie au comptoir (mode réception) ----
   Mêmes conventions que la configuration vitrine : chaque section est une
   carte, les champs sont des .form-control, l'aide est un .form-help que
   l'erreur remplace. Ne restent ici que les deux ou trois éléments que ces
   écrans ont en propre. */
.reception-check {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  font-size: var(--text-sm);
  line-height: 1.5;
}
.reception-actions {
  display: flex;
  gap: var(--space-3);
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: var(--space-4);
}
/* Actions qui ne concluent pas un formulaire (choix de signature, navigation) :
   alignées au début de la ligne, pas poussées à droite. */
.reception-actions--start { justify-content: flex-start; }
/* Intitulé d'un groupe de sections (« Voyageur titulaire ») : au-dessus des
   cartes, pas dans l'une d'elles. */
.form-section-heading {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-700);
  margin: 0 0 var(--space-3);
}
/* Au comptoir on vise au doigt sur tablette comme à la souris. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) {
  .reception-actions { justify-content: stretch; }
  .reception-actions .btn { flex: 1; min-height: 44px; }
}

/* Sidebar footer */
.sidebar-footer {
  border-top: 1px solid rgb(255 255 255 / 0.08);
  padding: var(--space-4);
  flex-shrink: 0;
}
.sidebar-lang {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
}
.sidebar-lang .lang-btn {
  color: rgb(255 255 255 / 0.5);
  border-color: transparent;
}
.sidebar-lang .lang-btn:hover {
  background: rgb(255 255 255 / 0.08);
  color: var(--color-white);
}
.sidebar-lang .lang-btn.is-active {
  background: rgb(255 255 255 / 0.15);
  color: var(--color-white);
  border-color: rgb(255 255 255 / 0.2);
}

/* Sidebar user block */
.sidebar-user {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-md);
  transition: background var(--transition-fast);
  min-width: 0;
}
.sidebar-user:hover { background: rgb(255 255 255 / 0.05); }
.sidebar-user-avatar {
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  flex-shrink: 0;
  overflow: hidden;
}
.sidebar-user-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.sidebar-user-name {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-white);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-user-role {
  font-size: var(--text-xs);
  color: rgb(255 255 255 / 0.45);
  text-transform: capitalize;
}
.sidebar-user-info--link {
  text-decoration: none;
  color: inherit;
  border-radius: var(--radius-md);
}
.sidebar-user-logout {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgb(255 255 255 / 0.4);
  border-radius: var(--radius-md);
  transition: background var(--transition-fast), color var(--transition-fast);
  flex-shrink: 0;
  text-decoration: none;
}
.sidebar-user-logout svg {
  width: 16px;
  height: 16px;
  display: block;
  flex-shrink: 0;
}
/* Au doigt, les deux icônes du pied de sidebar redeviennent des cibles de
   44px — sans grossir visuellement l'icône. */
@media (max-width: 1023px), (hover: none) and (pointer: coarse) {
  .sidebar-user-logout {
    width: 44px;
    height: 44px;
  }
}
.sidebar-user-logout:hover {
  background: rgb(255 255 255 / 0.1);
  color: var(--color-white);
}

/* ==========================================================================
   34. BRIDGE — Mobile Header
   ========================================================================== */

.mobile-header {
  display: none;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  min-height: 56px;
  gap: var(--space-3);
}
@media (max-width: 1023px) {
  .mobile-header { display: flex; }
}
/* Le bouton menu est la cible la plus utilisée du mobile : 44px. */
.hamburger-btn {
  width: 44px;
  height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--transition-fast);
  border: none;
  background: none;
  flex-shrink: 0;
  padding: 0;
}
.hamburger-btn:hover { background: var(--color-gray-100); }
.hamburger-line {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--color-gray-700);
  border-radius: 1px;
  transition: transform var(--transition-fast), opacity var(--transition-fast);
}
.mobile-header-title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.01em;
}
.mobile-header-spacer {
  width: 40px;
  flex-shrink: 0;
}

/* ==========================================================================
   35. BRIDGE — Page Header & Breadcrumb
   ========================================================================== */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-8);
  flex-wrap: wrap;
}
.page-header-inner {
  flex: 1;
  min-width: 0;
}
.page-title {
  font-size: var(--text-display);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
  line-height: var(--leading-tight);
}
.page-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
  flex-wrap: wrap;
}
@media (max-width: 640px) {
  /* G20 : flex-shrink:0 protège les actions contre le titre sur desktop,
     mais sur mobile — où .page-actions passe seule sur sa propre ligne via
     le wrap de .page-header — il gardait sa taille "max-content" (boutons
     côte à côte) au lieu de se caler sur la largeur réelle disponible, d'où
     le bouton "Exporter CSV" hors écran. flex-basis:100% force la largeur
     de ligne réelle ; les boutons s'empilent alors proprement en pleine
     largeur (flex-wrap seul aurait laissé 2 boutons par ligne, encore trop
     serré sur 360/414px). */
  .page-actions {
    flex-basis: 100%;
    flex-direction: column;
    align-items: stretch;
  }
  .page-actions > .btn,
  .page-actions > a {
    width: 100%;
    justify-content: center;
  }
}
.breadcrumb { margin-bottom: var(--space-2); }
.breadcrumb-list {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  flex-wrap: wrap;
}
.breadcrumb-item {
  display: flex;
  align-items: center;
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}
.breadcrumb-item a {
  color: var(--color-primary-lighter);
  text-decoration: none;
  transition: color var(--transition-fast);
}
.breadcrumb-item a:hover {
  color: var(--color-primary-ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.breadcrumb-item + .breadcrumb-item::before {
  content: '/';
  margin-right: var(--space-2);
  color: var(--color-gray-300);
}
[dir="rtl"] .breadcrumb-item + .breadcrumb-item::before {
  margin-right: 0;
  margin-left: var(--space-2);
}
.breadcrumb-item--active {
  color: var(--color-gray-900);
  font-weight: var(--font-weight-medium);
}
.main-inner { /* layout wrapper — inherits from .main-content */ }

/* ==========================================================================
   36. BRIDGE — Alert double-dash variants
   ========================================================================== */

.alert--warning {
  background: var(--color-warning-light);
  border-color: rgb(245 158 11 / 0.2);
  color: var(--color-warning-dark);
}

/* ==========================================================================
   37. DASHBOARD — Grille, tuiles, lignes de réservation
   --------------------------------------------------------------------------
   Principe de la page : trois types d'objets, trois traitements visuels
   DIFFÉRENTS, pour qu'on sache ce qu'on regarde avant de l'avoir lu.

     • Tuile de chiffre (.stat-card)    — liseré gauche coloré, 8px de rayon
     • Ligne de réservation (.booking-row) — rail de statut 4px, fond teinté
       si elle attend une action, pas d'ombre
     • Panneau (.card)                  — bordure seule, 12px de rayon

   Ce qui a été retiré : la barre dégradée navy→or identique en haut de chaque
   tuile, les ombres portées sur tout, et le tableau à six colonnes qui
   obligeait à scroller horizontalement sur téléphone.
   ========================================================================== */

/* --- Grille des tuiles ------------------------------------------------- */
/* 12 colonnes desktop : 4 tuiles de 3 colonnes. En dessous de 1200px on passe
   à 2, puis à 1 sous 420px — jamais de tuile plus étroite que son chiffre. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-8);
}
@media (max-width: 1199px) {
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* On ne passe à UNE colonne que sur les très petits écrans (<360px) : à
   390px, deux tuiles par ligne tiennent sans serrer et évitent de pousser le
   contenu réel quatre écrans plus bas. */
@media (max-width: 1199px) {
  .stat-grid { gap: var(--space-3); }
}
@media (max-width: 359px) {
  .stat-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Tuile : icône | chiffre + label | badge éventuel */
.stat-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.stat-card-body { flex: 1; min-width: 0; }

/* Le liseré gauche porte le SENS de la tuile — c'est le remplaçant de la
   barre dégradée décorative. Nommés par intention, pas par couleur : on sait
   pourquoi la tuile est ambre sans aller lire la feuille de style. */
.stat-card--brand   { border-left-color: var(--color-primary); }
.stat-card--clay    { border-left-color: var(--color-accent); }
.stat-card--pending { border-left-color: var(--rail-pending); }
.stat-card--done    { border-left-color: var(--rail-done); }
[dir="rtl"] .stat-card--brand   { border-right-color: var(--color-primary); }
[dir="rtl"] .stat-card--clay    { border-right-color: var(--color-accent); }
[dir="rtl"] .stat-card--pending { border-right-color: var(--rail-pending); }
[dir="rtl"] .stat-card--done    { border-right-color: var(--rail-done); }

/* Pastille d'icône, accordée au liseré. */
.stat-card-icon--brand   { background: var(--color-primary-50);   color: var(--color-primary-ink); }
.stat-card-icon--clay    { background: var(--color-accent-50);    color: var(--color-accent-strong); }
.stat-card-icon--pending { background: var(--color-warning-light); color: var(--color-warning-dark); }
.stat-card-icon--done    { background: var(--color-success-light); color: var(--color-success-dark); }

/* Chiffre : c'est l'élément que l'œil doit trouver en premier dans la tuile.
   Il descend à 1.75rem (le pas d'affichage) pour laisser respirer le label. */
.stat-card-value {
  font-size: var(--text-display);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: var(--space-1);
  font-variant-numeric: tabular-nums;
}
.stat-card-label {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  font-weight: var(--font-weight-medium);
  line-height: var(--leading-snug);
}

/* Badge de tuile (pastille) */
.stat-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  flex-shrink: 0;
  align-self: flex-start;
}
.stat-badge svg { width: 12px; height: 12px; flex-shrink: 0; }
.stat-badge--up   { background: var(--color-success-light); color: var(--color-success-dark); }
.stat-badge--warn { background: var(--color-warning-light); color: var(--color-warning-dark); }

/* Sur deux colonnes de téléphone, la pastille écrasait le libellé sur trois
   lignes. Elle n'apporte rien là : le liseré ambre de la tuile apparaît sous
   exactement la même condition, et le libellé dit déjà « en attente ». */
@media (max-width: 639px) {
  .stat-badge { display: none; }
}

/* --- Barre d'actions rapides ------------------------------------------ */
.quick-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-8);
}
/* Sur téléphone, les trois actions s'empilent en pleine largeur : trois
   boutons côte à côte à 360px, c'est trois cibles trop petites. */
@media (max-width: 639px) {
  .quick-actions { flex-direction: column; align-items: stretch; }
  .quick-actions > .btn { width: 100%; }
}

/* --- Grille principale ------------------------------------------------ */
/* 12 colonnes : 8 pour le flux opérationnel, 4 pour la colonne de contexte. */
.dashboard-grid {
  display: grid;
  grid-template-columns: minmax(0, 8fr) minmax(280px, 4fr);
  gap: var(--space-6);
  align-items: start;
}
@media (max-width: 1199px) {
  .dashboard-grid { grid-template-columns: minmax(0, 1fr); }
}
.dashboard-sidebar-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* --- En-têtes de panneau --------------------------------------------- */
/* 20px / 600 : le titre de section doit peser nettement plus que le texte
   qu'il coiffe. À 16px il avait le même poids visuel que les données, d'où
   l'effet « plat » signalé. */
.card-title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
  line-height: var(--leading-tight);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1;
}
.card-title--warn { color: var(--color-warning-dark); }
.card-title--warn svg { width: 18px; height: 18px; flex-shrink: 0; }
.card-subtitle {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  line-height: var(--leading-body);
  margin-top: var(--space-1);
}

/* Lien d'en-tête (« Tout voir »). Était en --color-gray-400, soit 3,4:1 :
   sous le seuil AA pour du texte. Il passe en bleu de marque, et le survol
   souligne au lieu d'ajouter une flèche. */
.card-link {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-primary-lighter);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--transition-fast);
  flex-shrink: 0;
}
.card-link:hover {
  color: var(--color-primary-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.card-body--flush { padding: 0; }

/* Alias double-tiret des boutons */
.btn--sm  { padding: 0.4375rem var(--space-3) !important; font-size: var(--text-sm) !important; }
.btn--xs  { padding: 0.3125rem var(--space-2) !important; font-size: var(--text-xs) !important; border-radius: var(--radius-sm) !important; }
.btn--lg  { padding: 0.75rem var(--space-6) !important; font-size: var(--text-base) !important; border-radius: var(--radius-lg) !important; }
.btn--full { width: 100% !important; justify-content: center; }

/* --- Lignes de réservation ------------------------------------------- */
/* Remplace le tableau à six colonnes : sur un téléphone il imposait un
   scroll horizontal, et sur desktop six colonnes d'égale importance ne
   disaient pas laquelle regarder.
   Ici le rail gauche donne le statut, la propriété et le voyageur forment
   l'identité, les dates la logistique, et le CTA reste à droite. */
.booking-list { list-style: none; }

.booking-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-3) var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-left: var(--rail-width) solid var(--rail-neutral);
  border-bottom: 1px solid var(--color-border-subtle);
  transition: background var(--transition-fast);
}
.booking-row:last-child { border-bottom: none; }
.booking-row:hover { background: var(--color-gray-50); }
[dir="rtl"] .booking-row {
  border-left: none;
  border-right: var(--rail-width) solid var(--rail-neutral);
}

/* Statut du rail. --attention va plus loin que la couleur : un fond
   légèrement ambré, parce qu'une réservation qui attend une action doit se
   voir depuis l'autre bout de l'écran. */
.booking-row--attention {
  border-left-color: var(--rail-pending);
  background: var(--color-warning-light);
}
.booking-row--attention:hover { background: #FBF0D2; }
.booking-row--done     { border-left-color: var(--rail-done); }
.booking-row--blocked  { border-left-color: var(--rail-blocked); }
.booking-row--progress { border-left-color: var(--color-info); }
[dir="rtl"] .booking-row--attention { border-right-color: var(--rail-pending); }
[dir="rtl"] .booking-row--done      { border-right-color: var(--rail-done); }
[dir="rtl"] .booking-row--blocked   { border-right-color: var(--rail-blocked); }
[dir="rtl"] .booking-row--progress  { border-right-color: var(--color-info); }

.booking-row-main { min-width: 0; }
.booking-row-property {
  display: block;
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.booking-row-guest {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-gray-600);
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dates : on compte dessus pour planifier une journée, donc chiffres à
   largeur fixe (tabular-nums) pour que les colonnes s'alignent à l'œil.
   Pas de police monospace : le poids et la couleur suffisent. */
.booking-row-dates {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.booking-row-date {
  color: var(--color-gray-900);
  font-weight: var(--font-weight-medium);
}
.booking-row-nights {
  color: var(--color-gray-500);
  font-size: var(--text-xs);
}
.booking-row-aside {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  justify-content: flex-end;
}

/* Téléphone : la ligne se replie en deux niveaux — identité au-dessus,
   dates + statut + action en dessous. Aucun scroll horizontal. */
@media (max-width: 639px) {
  .booking-row {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--space-4);
  }
  .booking-row-dates { flex-direction: row; align-items: baseline; gap: var(--space-2); }
  .booking-row-aside { justify-content: space-between; }
}

/* --- Colonnes de tableau (vues qui gardent un tableau) --------------- */
.table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
}
.td-property { max-width: 160px; overflow: hidden; }
.td-guest    { max-width: 140px; overflow: hidden; }
.td-date     { white-space: nowrap; font-variant-numeric: tabular-nums; }
.td-actions  { width: 1%; white-space: nowrap; text-align: right; }
[dir="rtl"] .td-actions { text-align: left; }

/* --- Badges ---------------------------------------------------------- */
.badge--neutral { background: var(--color-gray-100); color: var(--color-gray-700); }
.badge--primary { background: var(--color-primary-50); color: var(--color-primary-ink); }
.badge--info    { background: var(--color-info-light); color: var(--color-info-dark); }
.badge--warn    { background: var(--color-warning-light); color: var(--color-warning-dark); }
.badge--success { background: var(--color-success-light); color: var(--color-success-dark); }
.badge--error   { background: var(--color-danger-light); color: var(--color-danger-dark); }
.badge--neutral::before,
.badge--primary::before,
.badge--info::before,
.badge--warn::before,
.badge--success::before,
.badge--error::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
/* Pas de point quand le badge sert de compteur dans un titre. */
.card-title .badge--warn::before { display: none; }
/* Sur une ligne déjà teintée en ambre, le badge ambre disparaîtrait. */
.booking-row--attention .badge--warn {
  background: var(--color-surface);
  border: 1px solid var(--color-warning);
}

/* --- État vide ------------------------------------------------------- */
.empty-state--sm {
  padding: var(--space-8) var(--space-6);
  text-align: center;
}
.empty-state--sm svg {
  width: 40px;
  height: 40px;
  color: var(--color-gray-400);
  margin: 0 auto var(--space-3);
}
.empty-state--sm p {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  margin: 0 auto;
}

/* --- Revenus --------------------------------------------------------- */
.revenue-amount {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.revenue-value {
  font-size: var(--text-display);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.revenue-currency {
  font-size: var(--text-base);
  color: var(--color-gray-500);
  font-weight: var(--font-weight-medium);
}

/* --- Liste d'alertes (check-ins en retard) --------------------------- */
/* Même grammaire que .booking-row : rail ambre + fond teinté. Une alerte
   sur ce tableau de bord veut dire « un voyageur est arrivé et sa fiche
   n'est pas faite » — c'est de l'ambre, pas une ligne de liste neutre. */
.alert-list { list-style: none; }
.alert-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-left: var(--rail-width) solid var(--rail-pending);
  border-bottom: 1px solid var(--color-border-subtle);
  transition: background var(--transition-fast);
}
.alert-list-item:last-child { border-bottom: none; }
.alert-list-item:hover { background: var(--color-warning-light); }
[dir="rtl"] .alert-list-item {
  border-left: none;
  border-right: var(--rail-width) solid var(--rail-pending);
}
.alert-list-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.alert-list-property {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.alert-list-guest {
  font-size: var(--text-xs);
  color: var(--color-gray-600);
}
/* Était en --color-gray-400 (3,4:1) : une date se lit, donc elle monte au
   niveau 500 (4,6:1). */
.alert-list-date {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  font-variant-numeric: tabular-nums;
}

/* --- Jauge de conformité -------------------------------------------- */
.compliance-gauge { margin-bottom: var(--space-4); }
.compliance-gauge-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.compliance-gauge-value {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.compliance-gauge-bar {
  height: 8px;
  background: var(--color-gray-100);
  border-radius: var(--radius-full);
  overflow: hidden;
  margin-bottom: var(--space-2);
}
.compliance-gauge-fill {
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--color-gray-400);
  transition: width var(--transition-slow);
}
.compliance-gauge-fill--good { background: var(--color-success); }
.compliance-gauge-fill--warn { background: var(--color-warning); }
.compliance-gauge-fill--bad  { background: var(--color-danger); }
.compliance-gauge-label {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
  line-height: var(--leading-body);
}

/* --- Liens rapides (colonne latérale du dashboard superadmin) --------- */
/* Remplace deux <a> stylés en ligne qui portaient un « → » décoratif. Ici
   c'est l'icône qui annonce la destination et le survol qui dit « cliquable ».
   44px de haut : c'est aussi une cible tactile correcte. */
.quick-link-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
.quick-link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-700);
  text-decoration: none;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}
.quick-link svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--color-gray-500);
}
.quick-link:hover {
  border-color: var(--color-primary);
  color: var(--color-primary-ink);
  text-decoration: none;
}
.quick-link:hover svg { color: var(--color-primary-ink); }

/* --- Tableau de bord agent ------------------------------------------- */
/* Trois panneaux empilés (arrivées du jour, départs du jour, semaine à
   venir) : un agent travaille dans l'ordre chronologique, pas en colonnes. */
.agent-panels {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* --- L'UNIQUE moment orchestré de la page --------------------------- */
/* Au chargement, les objets opérationnels arrivent décalés de 50ms, de haut
   en bas, sur 8px. C'est tout : rien ne rejoue au scroll, rien ne bouge au
   survol, et aucune autre section de l'app n'a d'entrée animée.
   Entièrement sous « no-preference » : si le système demande moins de
   mouvement, les éléments sont simplement là, sans opacité de départ. */
@media (prefers-reduced-motion: no-preference) {
  .stagger-in > * {
    animation: riseIn 260ms cubic-bezier(0, 0, 0.2, 1) backwards;
  }
  .stagger-in > *:nth-child(1) { animation-delay: 0ms; }
  .stagger-in > *:nth-child(2) { animation-delay: 50ms; }
  .stagger-in > *:nth-child(3) { animation-delay: 100ms; }
  .stagger-in > *:nth-child(4) { animation-delay: 150ms; }
  .stagger-in > *:nth-child(5) { animation-delay: 200ms; }
  .stagger-in > *:nth-child(6) { animation-delay: 250ms; }
  /* Au-delà de 6 éléments on arrête d'échelonner : une 12e ligne qui
     apparaîtrait 600ms après la 1re serait du retard, pas du style. */
  .stagger-in > *:nth-child(n+7) { animation-delay: 300ms; }
}

/* ==========================================================================
   38. BRIDGE — Auth / Login Page
   ========================================================================== */

body.layout-auth {
  min-height: 100vh;
  background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-lighter) 60%, var(--color-primary-light) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.auth-wrapper {
  width: 100%;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}
.auth-card {
  width: 100%;
  background: var(--color-surface);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-xl);
  padding: var(--space-8);
  animation: fadeInUp var(--transition-slow) ease;
}
@media (max-width: 480px) {
  .auth-card { padding: var(--space-6); border-radius: var(--radius-xl); }
}
.auth-brand {
  text-align: center;
  margin-bottom: var(--space-8);
}
.auth-logo {
  width: 56px;
  height: 56px;
  margin: 0 auto var(--space-4);
  border-radius: var(--radius-xl);
  overflow: hidden;
}
.auth-logo svg { width: 100%; height: 100%; display: block; }
.auth-app-name {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: var(--space-2);
}
.auth-app-dot { color: var(--color-accent-strong); }
.auth-tagline {
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}
.auth-form { display: flex; flex-direction: column; gap: 0; }
.auth-form .form-group { margin-bottom: var(--space-5); }

/* Input with icon */
.input-icon-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}
.input-icon {
  position: absolute;
  left: var(--space-3);
  width: 18px;
  height: 18px;
  color: var(--color-gray-400);
  pointer-events: none;
  flex-shrink: 0;
}
[dir="rtl"] .input-icon {
  left: auto;
  right: var(--space-3);
}
.input-with-icon {
  padding-left: 2.5rem !important;
}
[dir="rtl"] .input-with-icon {
  padding-left: var(--space-3) !important;
  padding-right: 2.5rem !important;
}
.input-toggle-password {
  position: absolute;
  right: var(--space-3);
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-gray-400);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: color var(--transition-fast);
}
.input-toggle-password:hover { color: var(--color-gray-700); }
.input-toggle-password svg { width: 18px; height: 18px; }
[dir="rtl"] .input-toggle-password {
  right: auto;
  left: var(--space-3);
}

/* Form label row (label + forgot link) */
.form-label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.form-label-row .form-label { margin-bottom: 0; }
.form-label-link {
  font-size: var(--text-xs);
  color: var(--color-primary-lighter);
  text-decoration: none;
  transition: color var(--transition-fast);
  white-space: nowrap;
}
.form-label-link:hover { color: var(--color-accent-strong); }

/* Checkbox in form-group */
.form-group--checkbox { margin-bottom: var(--space-6); }

/* Auth lang switcher */
.auth-lang {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.auth-lang .lang-btn {
  color: rgb(255 255 255 / 0.6);
  border-color: transparent;
}
.auth-lang .lang-btn:hover {
  background: rgb(255 255 255 / 0.1);
  color: var(--color-white);
}
.auth-lang .lang-btn.is-active {
  background: rgb(255 255 255 / 0.15);
  color: var(--color-white);
  border-color: rgb(255 255 255 / 0.25);
}
.lang-sep {
  color: rgb(255 255 255 / 0.3);
  font-size: var(--text-sm);
}

/* ==========================================================================
   39. BRIDGE — Guest Layout (used by checkin public page)
   ========================================================================== */

body.layout-guest {
  min-height: 100vh;
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
}
.guest-header {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
}
.guest-header-inner {
  max-width: var(--container-max);
  margin-inline: auto;
  padding: var(--space-4) var(--space-6);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.guest-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
}
.guest-logo-icon {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.guest-logo-text {
  font-size: var(--text-lg);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
}
.guest-logo-dot { color: var(--color-accent-strong); }
.guest-lang {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.guest-main {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
}
.guest-footer {
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding: var(--space-5) var(--space-4);
}
.guest-footer-inner {
  max-width: var(--container-max);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
}
.guest-footer-security {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.security-icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--color-gray-400); }
.security-text { font-size: var(--text-sm); color: var(--color-gray-500); }
.guest-footer-badges {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.guest-footer-copy {
  font-size: var(--text-xs);
  color: var(--color-gray-400);
}

/* ==========================================================================
   40. BRIDGE — form-input alias (HTML uses .form-input instead of .form-control)
   ========================================================================== */

.form-input {
  display: block;
  width: 100%;
  padding: 0.625rem var(--space-3);
  font-size: var(--text-sm);
  font-family: inherit;
  font-weight: var(--font-weight-normal);
  color: var(--color-gray-900);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  line-height: var(--leading-normal);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast), background var(--transition-fast);
  appearance: none;
  -webkit-appearance: none;
}
.form-input::placeholder { color: var(--color-gray-400); }
.form-input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--shadow-focus);
  background: var(--color-white);
}
.form-input:disabled {
  background: var(--color-gray-50);
  color: var(--color-gray-400);
  cursor: not-allowed;
}
.form-input.is-invalid { border-color: var(--color-danger); box-shadow: 0 0 0 3px rgb(239 68 68 / 0.12); }
.form-input--lg { font-size: var(--text-base) !important; padding: 0.75rem var(--space-4) !important; }

/* ==========================================================================
   41. GLOBAL SVG SIZE CONSTRAINT (buttons & nav icons)
   ========================================================================== */

/* Prevent SVGs inside buttons from stretching due to img max-width:100% reset */
.btn svg,
.sidebar-nav-link svg,
.sidebar-user-logout svg,
.hamburger-btn svg,
.modal-close svg,
.alert-icon,
.dropdown-item svg {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}
/* Preserve explicit overrides */
.sidebar-nav-icon { width: 20px !important; height: 20px !important; }
.stat-card-icon svg { width: 24px !important; height: 24px !important; }
.step-icon svg { width: 28px !important; height: 28px !important; }

/* ==========================================================================
   42. MISSING SVG CONSTRAINTS — booking/compliance/timeline components
   ========================================================================== */

/* Timeline dot icons */
.timeline-dot svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

/* Compliance checklist check icons (bookings/show) */
.compliance-check svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

/* Inline icon svgs in consent, doc-type cards, capture placeholders that
   may appear outside already-covered containers */
.doc-type-card svg {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
}
.capture-placeholder svg {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
}


/* ==========================================================================
   43. GLOBAL SVG SAFETY NET
   Un SVG inline sans width/height hérite de max-width:100% (reset ligne ~283)
   et peut s'étendre à la largeur de son conteneur. On contraint ici tous les
   SVG à leur taille déclarée et on fournit un fallback raisonnable.
   ========================================================================== */

svg {
  overflow: hidden;
  vertical-align: middle;
}
/* Fallback : un svg inline sans attribut width explicite ne doit jamais
   dépasser 24px (les tailles voulues sont posées via attributs ou classes). */
svg:where(:not([width])) {
  width: 24px;
  height: 24px;
}
/* ==========================================================================
   44. PROPERTIES LIST PAGE (list-toolbar, property-grid, property-card)
   Ces classes étaient utilisées par views/properties/index.php mais
   n'existaient pas dans la feuille de style — d'où icônes géantes et
   mise en page cassée.
   ========================================================================== */

.list-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3, 0.75rem);
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}
.list-toolbar-left  { display: flex; align-items: center; gap: 0.75rem; }
.list-toolbar-right { display: flex; align-items: center; gap: 0.75rem; }

/* Mobile : les groupes de boutons ("Synchroniser" + "Ajouter") dépassent
   la largeur de l'écran s'ils ne peuvent pas passer à la ligne. */
@media (max-width: 639px) {
  .list-toolbar-left,
  .list-toolbar-right {
    flex-wrap: wrap;
  }
}
.list-count {
  font-size: 0.875rem;
  color: var(--color-gray-500, #5E7183);
  font-weight: 500;
}

/* ---------------------------------------------------------------------------
   Filter bar (bookings list, etc.)
   Mobile-first : champs empilés en pleine largeur (bon comportement mobile).
   Dès la tablette (>= 640px) : disposition horizontale en flex-wrap, champs
   alignés sur la même hauteur, et actions (Filtrer / Annuler) regroupées à la
   fin de la rangée.
--------------------------------------------------------------------------- */
.filter-bar {
  margin-bottom: var(--space-5, 1.25rem);
}
.filter-bar-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 0.75rem);
}
.filter-group {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.filter-group > .form-select,
.filter-group > .form-input,
.filter-group .input-icon-wrapper {
  width: 100%;
}
/* Plage de dates : les deux champs côte à côte avec le séparateur. */
.filter-group--date {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2, 0.5rem);
}
.filter-group--date .form-input {
  flex: 1 1 0;
}
.filter-date-sep {
  color: var(--color-gray-400, #7E8D9A);
  flex-shrink: 0;
}
.filter-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2, 0.5rem);
}
/* Mobile : les deux actions se partagent la largeur, sur la même ligne. */
.filter-actions .btn {
  flex: 1 1 auto;
}

@media (min-width: 640px) {
  .filter-bar-inner {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
  }
  .filter-group {
    flex: 1 1 12rem;
  }
  /* La plage de dates a besoin d'un peu plus de place que les selects. */
  .filter-group--date {
    flex: 1 1 16rem;
  }
  /* Le champ de recherche prend l'espace restant et pousse les actions à droite. */
  .filter-group--search {
    flex: 2 1 14rem;
  }
  .filter-actions {
    flex: 0 0 auto;
    margin-inline-start: auto;
  }
  .filter-actions .btn {
    flex: 0 0 auto;
  }
}

.view-toggle {
  display: inline-flex;
  border: 1px solid var(--color-gray-200, #E2DDD4);
  border-radius: var(--radius-md, 8px);
  overflow: hidden;
}
.view-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 32px;
  background: var(--color-white, #fff);
  border: none;
  cursor: pointer;
  color: var(--color-gray-400, #7E8D9A);
}
.view-toggle-btn.is-active {
  background: var(--color-gray-100, #f3f4f6);
  color: var(--color-gray-700, #374151);
}
.view-toggle-btn svg { width: 16px; height: 16px; flex-shrink: 0; }

.property-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 1.25rem;
}
.property-grid.is-list-view { grid-template-columns: 1fr; }

.property-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 1.25rem 0;
}
.property-card-icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: var(--radius-md, 8px);
  background: var(--color-primary-50, #EDF2F6);
  color: var(--color-primary, #1B4965);
}
.property-card-icon svg {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  color : #c9a84c !important;
}
.property-type-badge {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-gray-500, #5E7183);
  background: var(--color-gray-100, #f3f4f6);
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
}

.property-card-location svg,
.property-card-sync svg,
.property-bookings-count svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  display: inline-block;
}
.property-card-location {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.85rem;
  color: var(--color-gray-500, #5E7183);
  margin: 0.25rem 0 0.75rem;
}
.property-card-sync {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.75rem;
  color: var(--color-gray-400, #7E8D9A);
  margin: 0.5rem 0 0;
}

.ical-status {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}
.ical-status-item {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  color: var(--color-gray-500, #5E7183);
}
.ical-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
}
.ical-dot--active   { background: var(--color-success, #10b981); }
.ical-dot--inactive { background: var(--color-gray-300, #d1d5db); }

.property-bookings-count {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8rem;
  color: var(--color-gray-500, #5E7183);
}
.property-card-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.property-card-actions svg { width: 16px; height: 16px; flex-shrink: 0; }

/* ==========================================================================
   42. JS-INJECTED DIALOGS (keyboard shortcuts, confirm)
   app.js crée #keyboard-shortcuts-modal et #app-confirm-dialog sans classe
   de layout : sans ces règles ils se rendent en flux normal en bas de page
   (visibles sur mobile sous le footer). Cachés par défaut, affichés en
   overlay plein écran quand .modal-open est posée par showModal()/confirm().
   ========================================================================== */

#keyboard-shortcuts-modal,
#app-confirm-dialog {
  display: none;
}

#keyboard-shortcuts-modal.modal-open,
#app-confirm-dialog.modal-open {
  display: flex;
  position: fixed;
  inset: 0;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: var(--z-modal);
}

#keyboard-shortcuts-modal .modal-backdrop,
#app-confirm-dialog .confirm-backdrop {
  position: absolute;
  inset: 0;
  background: rgb(44 62 80 / 0.3);
  backdrop-filter: blur(2px);
}

#keyboard-shortcuts-modal .modal-box,
#app-confirm-dialog .confirm-box {
  position: relative;
  z-index: 1;
  background: var(--color-surface);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
  width: 100%;
  max-width: 420px;
  max-height: 85vh;
  overflow-y: auto;
}

#keyboard-shortcuts-modal .modal-box .modal-body {
  padding: var(--space-4) var(--space-6) var(--space-6);
}

#app-confirm-dialog .confirm-box {
  padding: var(--space-6);
}

#app-confirm-dialog .confirm-message {
  margin-bottom: var(--space-5);
  color: var(--color-gray-800);
}

#app-confirm-dialog .confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
}

/* Empêche le contenu de défiler derrière un modal ouvert */
body.modal-active {
  overflow: hidden;
}

/* ==========================================================================
   43. MOBILE — GARDE-FOUS DE LARGEUR (grilles & tableaux)
   Un enfant de grid/flex a min-width:auto : un tableau large à l'intérieur
   étire alors la colonne, puis toute la page (viewport de layout > écran =
   rendu "dézoomé" sur mobile). min-width:0 laisse le conteneur .table-wrapper /
   .table-responsive faire défiler le tableau au lieu d'étirer la page.
   ========================================================================== */

.grid-2 > *,
.grid-3 > *,
.grid-4 > *,
.dashboard-grid > *,
.main-inner [style*="display:grid"] > * {
  min-width: 0;
}

/* La sidebar repliée hors-écran (translateX(±100%)) étire le viewport de
   layout sur mobile (surtout en RTL où elle sort à droite) : la page entière
   devient scrollable horizontalement. body.layout-checkin a déjà cette
   protection ; on l'applique aux autres layouts. Les tableaux gardent leur
   défilement : il se fait dans .table-wrapper/.table-responsive, pas sur body. */
body.layout-app,
body.layout-guest,
body.reception-mode {
  overflow-x: hidden;
}

/* RTL mobile : la section "RTL comprehensive overrides" (plus haut) remet
   margin-right:260px sur .main-content à égalité de spécificité — placé en
   fin de fichier, ce reset reprend la main sous le breakpoint mobile. */
@media (max-width: 1023px) {
  [dir="rtl"] .main-content {
    margin-left: 0;
    margin-right: 0;
  }
}

/* En RTL, un tableau nowrap plus large que son conteneur overflow-x:auto
   décale la peinture de toute la page vers la droite (bug de clipping
   Chrome). contain:paint force le clip au niveau du wrapper et isole le
   débordement ; le défilement horizontal interne reste fonctionnel. */
.table-wrapper,
.table-responsive,
.main-inner [style*="overflow-x"] {
  contain: paint;
}

/* Les vues utilisent des grilles inline "grid-template-columns:1fr 360px",
   "1fr 1fr", etc. sans media query : sous 768px on les replie en une seule
   colonne. Les grilles déjà responsives (repeat(auto-fit,…)) et le calendrier
   (repeat(7,1fr)) ne commencent pas par "1fr" et ne sont pas touchés. */
@media (max-width: 767px) {
  .main-inner [style*="grid-template-columns:1fr"] {
    grid-template-columns: 1fr !important;
  }
}

/* ==========================================================================
   45. FICHE RÉSERVATION — Résumé séjour, blocs, hiérarchie label/valeur
   --------------------------------------------------------------------------
   Utilise les tokens sémantiques (tokens.css). Objectif : sortir de l'effet
   « liste plate » — une signature de séjour en tête, puis des blocs séparés
   (Voyageur, Paiement) avec une vraie hiérarchie labels (petit gris) /
   valeurs (gras encre) et une icône par donnée.
   ========================================================================== */

/* ---- En-tête de page ------------------------------------------------- */
.booking-show-header {
  margin-bottom: var(--space-6);
}
.booking-show-title-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.booking-show-guest {
  font-size: var(--text-2xl);
  font-weight: var(--title-weight);
  color: var(--ink-900);
  letter-spacing: -0.02em;
  line-height: var(--leading-tight);
  margin-right: auto;
}
[dir="rtl"] .booking-show-guest { margin-right: 0; margin-left: auto; }
.booking-show-title-row .btn { flex-shrink: 0; }
.booking-show-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  color: var(--slate-500);
}
.booking-show-meta .meta-sep { color: var(--hairline); }

/* ---- Grille deux colonnes ------------------------------------------- */
.booking-show-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: var(--space-6);
  align-items: start;
}
.booking-show-left,
.booking-show-right {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}
@media (max-width: 1023px) {
  .booking-show-grid { grid-template-columns: 1fr; }
}

/* ---- Carte résumé : liseré doré (signature de marque) --------------- */
.res-card {
  position: relative;
  overflow: hidden;
}
.res-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--navy-900), var(--gold-500));
}
.res-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--block-gap);            /* espacement GÉNÉREUX entre blocs */
  padding-top: var(--space-7);
}

/* ---- Bloc générique -------------------------------------------------- */
.res-block { min-width: 0; }
.res-block + .res-block {
  padding-top: var(--block-gap);
  border-top: 1px solid var(--hairline-subtle);
}
.res-block__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--label-size);
  font-weight: var(--value-weight);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--slate-500);
  margin-bottom: var(--space-4);
}
.res-block__title svg { color: var(--navy-900); flex-shrink: 0; }

/* ---- Bloc Séjour : propriété ---------------------------------------- */
.res-property {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  text-decoration: none;
  margin-bottom: var(--space-5);
}
.res-property__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 42px;
  flex-shrink: 0;
  border-radius: var(--radius-lg);
  background: var(--navy-50);
  color: var(--navy-900);
}
.res-property__text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.res-property__label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  color: var(--slate-500);
}
.res-property__name {
  font-size: var(--text-lg);
  font-weight: var(--value-weight);
  color: var(--ink-900);
  line-height: var(--leading-snug);
}
.res-property:hover .res-property__name { color: var(--navy-900); }

/* ---- Bloc Séjour : billet dates / nuits ----------------------------- */
.res-trip {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--paper-50);
}
.res-trip__point {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.res-trip__point--end { text-align: right; align-items: flex-end; }
[dir="rtl"] .res-trip__point--end { text-align: left; align-items: flex-start; }
.res-trip__cap {
  font-size: var(--text-xs);
  font-weight: var(--label-weight);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate-500);
}
.res-trip__date {
  font-size: var(--text-base);
  color: var(--ink-900);
  font-weight: var(--value-weight);
  white-space: nowrap;
}
.res-trip__date strong {
  font-size: var(--text-2xl);
  font-weight: var(--title-weight);
  letter-spacing: -0.02em;
  margin-right: 2px;
}
[dir="rtl"] .res-trip__date strong { margin-right: 0; margin-left: 2px; }
.res-trip__year {
  font-size: var(--text-xs);
  color: var(--slate-400);
}

/* Rail « billet » : ligne + pastille nuits au centre, façon trajet */
.res-trip__track {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  height: 100%;
}
.res-trip__track::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 2px;
  transform: translateY(-50%);
  background-image: linear-gradient(90deg, var(--hairline) 0 60%, transparent 60%);
  background-size: 8px 2px;
  background-repeat: repeat-x;
  z-index: 0;
}
/* pointe de flèche vers le départ (miroir auto en RTL) */
.res-trip__track::after {
  content: '';
  position: absolute;
  right: 0; top: 50%;
  width: 7px; height: 7px;
  border-top: 2px solid var(--hairline);
  border-right: 2px solid var(--hairline);
  transform: translateY(-50%) rotate(45deg);
  z-index: 0;
}
[dir="rtl"] .res-trip__track::after {
  right: auto; left: 0;
  transform: translateY(-50%) rotate(225deg);
}
.res-trip__nights {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--gold-50);
  color: var(--gold-500);
  border: 1px solid var(--gold-100);
  font-size: var(--text-xs);
  font-weight: var(--value-weight);
  white-space: nowrap;
}
.res-trip__nights svg { flex-shrink: 0; }

/* ---- Grille de champs (2 colonnes, icône par ligne) ----------------- */
.res-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4) var(--space-5);
}
@media (max-width: 479px) {
  .res-grid { grid-template-columns: 1fr; }
}
.res-field {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-width: 0;
}
.res-field__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px; height: 34px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--navy-50);
  color: var(--navy-900);
  margin-top: 1px;
}
.res-field__icon svg { width: 18px; height: 18px; }
.res-field__text { min-width: 0; }
.res-field__label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  color: var(--slate-500);
  margin-bottom: 1px;
}
.res-field__value {
  font-size: var(--text-sm);
  font-weight: var(--value-weight);
  color: var(--ink-900);
  line-height: var(--leading-snug);
}
.res-field__value a { color: inherit; text-decoration: none; }
.res-field__value a:hover { color: var(--navy-900); text-decoration: underline; }
.res-field__value--truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.res-field__value--amount {
  font-size: var(--text-lg);
  letter-spacing: -0.01em;
}
.res-field__unit {
  font-size: var(--text-xs);
  font-weight: var(--label-weight);
  color: var(--slate-500);
}

/* ==========================================================================
   45b. STANDARD label/valeur — s'applique partout (info-list génériques)
   ========================================================================== */
.info-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.info-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.info-label {
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  color: var(--slate-500);
}
.info-value {
  font-size: var(--text-sm);
  font-weight: var(--value-weight);
  color: var(--ink-900);
}
.info-value a { color: inherit; text-decoration: none; }
.info-value a:hover { color: var(--navy-900); text-decoration: underline; }

/* ==========================================================================
   45c. TIMELINE — état "done" aligné sur le vert succès du système
   ========================================================================== */
.timeline-item--done .timeline-dot {
  background: var(--success-500);
  border-color: var(--success-500);
  color: var(--color-white);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 0 0 3px var(--success-50);
}
.timeline-item--done .timeline-dot svg { color: var(--color-white); }
.timeline-content .timeline-title {
  font-weight: var(--value-weight);
  color: var(--ink-900);
}
.timeline-date {
  font-size: var(--text-xs);
  color: var(--slate-500);
  margin-top: 2px;
}
.timeline-item:not(.timeline-item--done) .timeline-title { color: var(--slate-500); }

/* ==========================================================================
   45d. BADGES — variante large + plateformes (sur le système de couleurs)
   ========================================================================== */
.badge--lg {
  font-size: var(--text-sm);
  padding: var(--space-1) var(--space-3);
}
.badge--airbnb  { background: #ffe8ec; color: #c31b46; }
.badge--booking { background: var(--navy-50); color: var(--navy-900); }
.badge--abritel { background: #e0f2fe; color: #0369a1; }
.badge--whatsapp{ background: #dcfce7; color: #15803d; }
.badge--facebook{ background: #e7f0fe; color: #1a53b0; }
@media (prefers-color-scheme: dark) {
  .badge--airbnb  { background: rgba(195,27,70,.18);  color: #ff8fa8; }
  .badge--abritel { background: rgba(3,105,161,.22);  color: #7dd3fc; }
  .badge--whatsapp{ background: rgba(37,211,102,.18); color: #6ee7a8; }
  .badge--facebook{ background: rgba(24,119,242,.20); color: #93b4f8; }
}

/* ==========================================================================
   45e. PANNEAU CONFORMITÉ (colonne droite de la fiche réservation)
   ========================================================================== */
.compliance-checklist {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  list-style: none;
  margin: 0; padding: 0;
}
.compliance-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.compliance-check {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
}
.compliance-label {
  font-size: var(--text-sm);
  font-weight: var(--value-weight);
  color: var(--ink-900);
  min-width: 0;
}
.compliance-item--done {
  border-color: var(--success-50);
  background: color-mix(in srgb, var(--success-50) 45%, var(--surface));
}
.compliance-item--done .compliance-check {
  background: var(--success-500);
  color: var(--color-white);
}
.compliance-item--pending .compliance-check {
  background: var(--warning-50);
  color: var(--warning-600);
}
.compliance-item--pending .compliance-label { color: var(--slate-500); }

/* Divider & sub-labels réutilisés dans le panneau */
.card-divider {
  border: 0;
  border-top: 1px solid var(--hairline);
  margin: var(--space-5) 0;
}
.section-label {
  font-size: var(--label-size);
  font-weight: var(--value-weight);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--slate-500);
  margin-bottom: var(--space-3);
}

/* Statut / expiry du lien de check-in */
.checkin-link-status { margin-bottom: var(--space-3); }
.checkin-link-info {
  font-size: var(--text-sm);
  color: var(--slate-500);
}
.checkin-link-info strong { color: var(--ink-900); font-weight: var(--value-weight); }
.checkin-link-expiry { font-size: var(--text-xs); margin-top: 2px; }

/* Rangée input + bouton (copier le lien, renvoyer par email) */
.input-btn-row {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
}
.input-btn-row .form-input { flex: 1; min-width: 0; }
.input-btn-row .btn { flex-shrink: 0; }
.send-link-form { margin-top: 0; }

/* Téléchargements documents */
.compliance-downloads .compliance-download-btns {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.compliance-download-btns .btn { justify-content: flex-start; }
.compliance-download-btns .btn.disabled,
.compliance-download-btns .btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
}

@media (max-width: 479px) {
  .input-btn-row { flex-direction: column; }
  .input-btn-row .btn { width: 100%; justify-content: center; }
}

/* Résultat des tests iCal & import Airbnb (aperçu de lien) */
.ical-test-result {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  line-height: 1.4;
}
.ical-test-result--success { color: var(--color-success, #16a34a); }
.ical-test-result--error   { color: var(--color-danger, #dc2626); }
.ical-test-result--warning { color: var(--color-warning, #d97706); }

/* ==========================================================================
   ONBOARDING LÉGER (quick setup) — popup, banner, formulaire minimal, CTA
   Mobile-first : trafic majoritairement mobile via Meta Ads.
   ========================================================================== */

/* ---- Formulaire quick-setup ---- */
.onboarding-wrap {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--space-2) 0 var(--space-8);
}
.onboarding-intro {
  text-align: center;
  margin-bottom: var(--space-6);
}
.onboarding-step-badge,
.onboarding-badge {
  display: inline-block;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold, 600);
  color: var(--color-primary-ink);
  background: var(--navy-50, #eef2f7);
  border-radius: 999px;
  padding: 0.25rem 0.75rem;
  margin-bottom: var(--space-3);
}
.onboarding-heading {
  font-size: var(--text-xl);
  font-weight: var(--title-weight, 700);
  color: var(--ink-900, #111827);
  margin: 0 0 var(--space-2);
  line-height: 1.25;
}
.onboarding-sub {
  color: var(--slate-500, #5E7183);
  font-size: var(--text-sm);
  margin: 0;
}
.onboarding-form .onboarding-card { margin-bottom: var(--space-4); }
.onboarding-hint { margin: 0 0 var(--space-3); }
.onboarding-photo { margin-top: var(--space-3); }
.onboarding-photo img {
  max-width: 100%;
  max-height: 200px;
  width: 100%;
  object-fit: cover;
  border-radius: var(--radius-md);
  display: block;
}
.onboarding-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.onboarding-skip-link {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--slate-500, #5E7183);
  font-size: var(--text-sm);
  text-decoration: underline;
  padding: var(--space-2);
}
.onboarding-skip-link:hover { color: var(--ink-700, #374151); }

/* ---- Popup post-inscription ---- */
.onboarding-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.onboarding-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgb(44 62 80 / 0.3);
}
.onboarding-modal-card {
  position: relative;
  background: var(--color-surface, #fff);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  padding: var(--space-6);
  max-width: 26rem;
  width: 100%;
  text-align: center;
  animation: onboarding-pop 0.18s ease-out;
}
@keyframes onboarding-pop {
  from { transform: translateY(8px) scale(0.98); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.onboarding-modal-icon {
  width: 3.25rem;
  height: 3.25rem;
  margin: 0 auto var(--space-4);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-primary-ink);
  background: var(--navy-50, #eef2f7);
}
.onboarding-modal-icon svg { width: 1.6rem; height: 1.6rem; }
.onboarding-modal-title {
  font-size: var(--text-lg);
  font-weight: var(--title-weight, 700);
  color: var(--ink-900, #111827);
  margin: 0 0 var(--space-3);
  line-height: 1.3;
}
.onboarding-modal-text {
  color: var(--slate-500, #5E7183);
  font-size: var(--text-sm);
  margin: 0 0 var(--space-6);
  line-height: 1.5;
}
.onboarding-modal-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

/* ---- Banner de mise en avant (navy + accent doré) ----
   Volontairement bien visible pour se démarquer des cartes KPI qui
   l'entourent tant qu'aucune propriété n'est configurée. */
.onboarding-banner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  background: linear-gradient(135deg, var(--navy-900, #1a2e4a), var(--navy-700, #243d61));
  border: 1px solid var(--navy-900, #1a2e4a);
  border-inline-start: 4px solid var(--gold-500, #c9a84c);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5, 1.25rem);
  margin-bottom: var(--space-6);
  box-shadow: var(--shadow-md);
}
.onboarding-banner-icon {
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--navy-900, #1a2e4a);
  background: var(--gold-500, #c9a84c);
  border-radius: 50%;
}
.onboarding-banner-icon svg { width: 1.35rem; height: 1.35rem; }
.onboarding-banner-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}
.onboarding-banner-title {
  font-weight: var(--font-weight-bold, 700);
  color: #fff;
  font-size: var(--text-base, 1rem);
}
.onboarding-banner-text {
  color: var(--navy-100, #d5e0ed);
  font-size: var(--text-sm, 0.875rem);
}
/* CTA doré pour ressortir sur le fond navy (le btn-primary navy s'y fondrait). */
.onboarding-banner-cta {
  flex-shrink: 0;
  white-space: nowrap;
  background: var(--gold-500, #c9a84c) !important;
  border-color: var(--gold-500, #c9a84c) !important;
  color: var(--navy-900, #1a2e4a) !important;
  font-weight: var(--font-weight-semibold, 600);
}
.onboarding-banner-cta:hover {
  background: var(--gold-300, #e8cf95) !important;
  border-color: var(--gold-300, #e8cf95) !important;
}

/* ---- Carte « Terminez la configuration » sur le dashboard ---- */
.onboarding-complete-card { margin-bottom: var(--space-6); }
.onboarding-complete-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.onboarding-complete-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--hairline-subtle, #eee);
}
.onboarding-complete-item:first-child { border-top: none; }
.onboarding-complete-item.is-new { background: var(--warning-50, #fffbeb); }
.onboarding-complete-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.onboarding-complete-name {
  font-weight: var(--font-weight-semibold, 600);
  color: var(--ink-900, #111827);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.onboarding-complete-meta {
  color: var(--slate-500, #5E7183);
  font-size: var(--label-size, 0.8rem);
}
.onboarding-complete-item .btn { flex-shrink: 0; white-space: nowrap; }

/* ---- Carte propriété « à compléter » (liste des propriétés) ---- */
.property-type-badge--incomplete {
  background: var(--warning-50, #fffbeb);
  color: var(--warning-600, #b45309);
}
.property-card--incomplete { border-color: var(--warning-500, #f59e0b); }
.property-complete-cta { margin-top: var(--space-3); }

/* ---- Mobile : banner en colonne ---- */
@media (max-width: 640px) {
  .onboarding-banner { flex-wrap: wrap; }
  .onboarding-banner-cta { width: 100%; }
  .onboarding-complete-item { flex-wrap: wrap; }
  .onboarding-complete-item .btn { width: 100%; }
}

/* ==========================================================================
   LOT F — COMPOSANTS PARTAGÉS (états, actions, confirmation, alertes, champs)
   --------------------------------------------------------------------------
   S'appuie UNIQUEMENT sur les tokens existants (section 1) — aucune nouvelle
   couleur. Objectif : distinguer à l'œil les ÉTATS (pastilles non cliquables)
   des ACTIONS (vrais boutons), une confirmation unique qui reste à l'écran,
   des alertes lisibles sur mobile, et des cibles tactiles de 44 px.
   ========================================================================== */

/* ---- Cibles tactiles : 44 px minimum sur mobile (F2/F7) ---- */
@media (max-width: 640px) {
  .btn:not(.btn--xs):not(.btn-icon) { min-height: 44px; }
  .actions .btn,
  .actions-zone .btn { min-height: 44px; }
}

/* ---- Zone « Actions » séparée (F2) ---- */
.actions,
.actions-zone {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
}
.actions-zone__title,
.actions__title {
  width: 100%;
  margin: 0 0 var(--space-1);
  font-size: var(--label-size, 0.8rem);
  font-weight: var(--font-weight-semibold);
  color: var(--slate-500, #5E7183);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.actions-zone > form { margin: 0; }
/* Un bouton destructif ne colle jamais un bouton principal : marge auto qui
   pousse le groupe destructif à l'opposé quand ils partagent la même rangée. */
.actions-zone .actions-danger { margin-left: auto; }
[dir="rtl"] .actions-zone .actions-danger { margin-left: 0; margin-right: auto; }

/* Sur mobile : deux colonnes (chaque action ≈ moitié de rangée), les boutons
   remplissent leur cellule ; une action « pleine largeur » prend toute la
   rangée (ex. Annuler avec motif). */
@media (max-width: 640px) {
  .actions-zone .actions-danger { margin-left: 0; }
  .actions-zone > a.btn,
  .actions-zone > form {
    flex: 1 1 calc(50% - var(--space-3));
  }
  .actions-zone > form .btn { width: 100%; }
  .actions-zone .actions-full { flex-basis: 100%; }
}

/* ---- Groupe d'ÉTATS : pastilles NON cliquables sous le titre (F2) ---- */
.state-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin: var(--space-1) 0 var(--space-2);
}
.state-badges .badge { cursor: default; }

/* ---- Bouton destructif « contour » (alternative à btn-danger plein) ---- */
.btn-outline-danger {
  background: transparent;
  color: var(--color-danger-dark);
  border: 1px solid var(--color-danger);
}
.btn-outline-danger:hover {
  background: var(--color-danger-light);
  color: var(--color-danger-dark);
}

/* ---- Confirmation unique : titre de la modale (F1) ---- */
#app-confirm-dialog .confirm-title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--font-weight-bold);
  color: var(--color-gray-900);
}
#app-confirm-dialog .confirm-actions .btn { min-height: 44px; }
@media (max-width: 480px) {
  #app-confirm-dialog .confirm-actions {
    flex-direction: column-reverse; /* Confirmer en bas, Annuler accessible au pouce */
  }
  #app-confirm-dialog .confirm-actions .btn { width: 100%; }
}

/* ---- Alerte : robuste sur mobile (F4) ---- */
/* Le message prend toute la largeur restante, la croix reste à droite. */
.alert { align-items: flex-start; }
.alert .alert-message { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.alert .alert-close { flex-shrink: 0; }
[dir="rtl"] .alert .alert-close { margin-left: 0; margin-right: auto; }

/* Undo « Fait — Annuler l'action » (F1, actions réversibles) */
.alert-undo-form { flex-shrink: 0; margin: 0; }
.alert-undo-btn {
  background: none;
  border: none;
  padding: 0 var(--space-2);
  font: inherit;
  font-weight: var(--font-weight-semibold);
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}
.alert-undo-btn:hover { opacity: .85; }

/* ---- Erreur SOUS un champ (F4 / F5) ---- */
.field-error {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-danger-dark);
  font-size: var(--text-sm);
}
.form-input.input-error,
.form-select.input-error,
.form-input--error {
  border-color: var(--color-danger);
}
.form-input.input-error:focus,
.form-input--error:focus {
  box-shadow: 0 0 0 3px rgb(239 68 68 / 0.18);
}

/* ---- Champ date : rendre l'affordance visible sur mobile (F5) ---- */
/* Hint « jj/mm/aaaa » sous le champ + icône native conservée. */
.field-date-hint {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--slate-400, #7E8D9A);
}
input[type="date"] { min-height: 44px; }
input[type="date"]::-webkit-calendar-picker-indicator { opacity: 1; cursor: pointer; }

/* ---- Grille Adultes / Enfants alignée (F5) ---- */
.persons-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  align-items: end; /* les champs s'alignent même si un libellé fait 2 lignes */
}
.persons-grid .form-label { min-height: 2.4em; } /* réserve 2 lignes de libellé */

/* ---- Consentement : case plus grande, alignée, focus/erreur (F5) ---- */
.consent-box .checkbox-custom { width: 24px; height: 24px; }
.consent-box .checkbox-input:focus-visible + .checkbox-custom {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.consent-box.has-error {
  border-color: var(--color-danger);
  background: var(--color-danger-light);
}

/* ---- Tableaux → cartes lisibles sur mobile (F6) ---- */
/* Chaque <td> porte data-label ; on empile en cartes sous 640 px, avec
   l'étiquette de colonne à gauche et la valeur à droite. Les actions
   principales restent visibles sans défilement horizontal. */
@media (max-width: 640px) {
  /* G18 : table/tbody restaient display:table/table-row-group pendant que tr/td
     passaient en block/flex — le navigateur régénère alors des boîtes de
     tableau anonymes autour du <tr> (fixup de la spec CSS2 §17.2.1) au lieu
     d'appliquer le display demandé, d'où des lignes réduites à ~25px et des
     cartes qui se chevauchent. table et tbody doivent aussi sortir du mode
     tableau pour que tr/td (block/flex) prennent effet normalement. */
  .table--cards { display: block; border: 0; }
  .table--cards tbody { display: block; }
  .table--cards thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table--cards tr {
    display: block;
    margin-bottom: var(--space-4);
    /* --hairline / --surface ne sont définis nulle part : la carte retombait
       sur les valeurs claires en dur (#E2DDD4 / #fff) et restait blanche en
       thème sombre. Les jetons réels portent les deux thèmes. */
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface);
    box-shadow: var(--shadow-xs);
  }
  .table--cards tr:last-child { margin-bottom: 0; }
  .table--cards td {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border: 0;
    border-bottom: 1px solid var(--color-border-subtle);
    text-align: right;
  }
  .table--cards td:last-child { border-bottom: 0; }
  /* .table tbody tr:last-child td { border-bottom:none } (règle bureau, qui
     clôt proprement le bas du tableau) effaçait tous les filets internes de
     la DERNIÈRE carte : la dernière réservation s'affichait sans aucune
     séparation entre ses lignes. En vue carte, chaque ligne garde son filet
     et seule la dernière cellule de la carte en est dispensée. */
  .table--cards tbody tr:last-child td { border-bottom: 1px solid var(--color-border-subtle); }
  .table--cards tbody tr:last-child td:last-child { border-bottom: 0; }
  .table--cards td::before {
    content: attr(data-label);
    font-size: var(--label-size, 0.8rem);
    font-weight: var(--font-weight-semibold);
    color: var(--slate-500, #5E7183);
    text-align: left;
    flex: 0 0 auto;
  }
  .table--cards td[data-label=""]::before { content: none; }
  /* La cellule d'actions : boutons alignés à droite, cibles 44 px.
     .td-actions { width:1%; white-space:nowrap } (règle desktop, pour que la
     colonne actions se réduise à son contenu dans le <table> normal) reste
     appliquée ici et écrase la cellule à ~1 % de la largeur de la carte — les
     boutons se retrouvent alors superposés/coupés au lieu de s'aligner à
     droite. On neutralise les deux dans la vue carte. */
  .table--cards td.td-actions { width: auto; white-space: normal; flex-wrap: wrap; justify-content: flex-end; }
  [dir="rtl"] .table--cards td { text-align: left; }
  [dir="rtl"] .table--cards td::before { text-align: right; }

  /* Cellules à texte long : libellé sur sa propre ligne, valeur en dessous.
     .td-property { max-width:160px } / .td-guest { max-width:140px } (règles
     desktop) restaient appliquées dans la carte : le nom du logement se
     pliait sur 4-5 lignes dans une colonne étroite, en face d'un libellé
     court — une carte encombrée pour une seule information. Placé en fin de
     bloc pour passer après les surcharges [dir="rtl"] ci-dessus ; `start`
     vaut gauche en LTR et droite en RTL, sans surcharge supplémentaire. */
  .table--cards td.td-property,
  .table--cards td.td-guest,
  .table--cards td.td-stack {
    /* display:block plutôt que flex en colonne : les badges du voyageur
       (« 2 check-ins », « archivée »…) restent alors dans le flux inline
       derrière le nom, comme en vue bureau. En flex, chaque badge devient un
       item et s'étire sur toute la largeur de la carte. */
    display: block;
    max-width: none;
    overflow: visible;
    text-align: start;
  }
  .table--cards td.td-property::before,
  .table--cards td.td-guest::before,
  .table--cards td.td-stack::before {
    display: block;
    margin-bottom: var(--space-1);
    text-align: start;
  }
  /* Le .text-truncate du nom de propriété n'a plus de colonne à protéger :
     la valeur occupe toute la largeur de la carte et s'enroule. */
  .table--cards td.td-property .text-truncate,
  .table--cards td.td-stack .text-truncate {
    display: block;
    max-width: none;
    overflow: visible;
    white-space: normal;
    text-overflow: clip;
  }

  /* Le panneau .card qui enveloppe la table s'efface sous 640 px : sinon la
     carte blanche de chaque ligne se pose sur un panneau blanc de même
     couleur et les réservations se fondent les unes dans les autres (seul un
     filet gris les séparait). Sans panneau, la gouttière entre deux lignes
     laisse voir le fond de page : la séparation redevient lisible. */
  .card--table-cards {
    background: transparent;
    border: 0;
    border-radius: 0;
    overflow: visible;
  }
  .card--table-cards > .table-wrapper {
    overflow: visible;
    border: 0;
    border-radius: 0;
    /* contain:paint (§ 43) rognerait l'ombre des cartes une fois le
       défilement horizontal devenu inutile. */
    contain: none;
  }
}

/* ==========================================================================
   41. BOOKINGS CALENDAR (rendu par la classe BookingCalendar d'app.js)
   La grille /bookings/calendar est hydratée côté client ; ces styles la
   rendent lisible. Propriétés logiques pour rester correct en RTL.
   ========================================================================== */

.booking-calendar {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.calendar-title {
  font-size: var(--text-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  text-transform: capitalize;
  margin: 0;
  text-align: center;
  flex: 1 1 auto;
  min-width: 0;
}
/* Boutons de navigation : taille fixe et compacte, indépendante des variantes
   .btn du reste du site (les classes btn-sm/btn-outline du markup JS n'existent
   pas dans ce design system et laissaient le bouton s'étirer → débordement). */
.calendar-header button {
  flex: 0 0 auto;
  width: 40px;
  min-width: 40px;
  height: 36px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-lg);
  line-height: 1;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-gray-700);
  cursor: pointer;
}
.calendar-header button:hover { background: var(--color-gray-100); }

.calendar-loading {
  padding: var(--space-8);
  text-align: center;
  color: var(--color-gray-500);
  font-size: var(--text-sm);
}

.cal-day-names,
.cal-days {
  display: grid;
  /* minmax(0,1fr) : sans le min 0, les libellés `nowrap` forcent chaque colonne
     plus large que le conteneur → débordement horizontal (barre de défilement). */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}
.cal-day-names { margin-bottom: 4px; }
.cal-day-name {
  text-align: center;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-500);
  padding: var(--space-1) 0;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.cal-cell {
  min-height: 92px;
  min-width: 0; /* autorise le contenu à rétrécir sous sa taille intrinsèque */
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-1);
  background: var(--color-surface);
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.cal-cell.cal-empty {
  background: transparent;
  border-color: transparent;
}
.cal-cell.cal-today {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}
.cal-day-number {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-600);
  align-self: flex-end;
}
.cal-cell.cal-today .cal-day-number { color: var(--color-primary-ink); }

.cal-bookings {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  overflow: hidden;
}
.cal-booking {
  font-size: 11px;
  line-height: 1.3;
  color: #fff;
  padding: 2px var(--space-1);
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-booking:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}
.cal-booking-name {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
}

.calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border-subtle);
}
.legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-gray-600);
}
.legend-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}

.booking-popover {
  position: absolute;
  z-index: var(--z-popover, 60);
  width: 260px;
  max-width: calc(100vw - 2 * var(--space-4));
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-4);
}
.popover-close {
  position: absolute;
  inset-block-start: var(--space-2);
  inset-inline-end: var(--space-2);
  background: none;
  border: none;
  font-size: var(--text-lg);
  line-height: 1;
  color: var(--color-gray-400);
  cursor: pointer;
}
.popover-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding-inline-start: var(--space-2);
  margin-bottom: var(--space-2);
}
.popover-header .badge {
  color: #fff;
  font-size: var(--text-xs);
  padding: 2px var(--space-2);
  border-radius: var(--radius-full);
}
.popover-details {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px var(--space-3);
  margin: var(--space-2) 0;
  font-size: var(--text-sm);
}
.popover-details dt { color: var(--color-gray-500); }
.popover-details dd { color: var(--color-gray-900); margin: 0; text-align: end; }

@media (max-width: 600px) {
  .cal-cell { min-height: 68px; }
  .cal-booking { font-size: 10px; }
  .cal-day-name { font-size: 10px; }
}

/* ==========================================================================
   46. FORMULAIRE PROPRIÉTÉ — mise en colonnes, radios, panneaux d'onglets
   --------------------------------------------------------------------------
   Cette section comble un trou : le gabarit du formulaire de propriété
   utilisait dix-sept classes (.form-two-col, .form-col, .radio-group,
   .radio-label, .radio-custom, .radio-text, .form-divider,
   .form-submit-panel, .danger-zone…) dont AUCUNE n'avait de règle. D'où
   l'impression de page « trop chargée » : la mise en deux colonnes prévue
   dans le HTML ne s'appliquait pas, tout s'empilait sur une seule colonne
   pleine largeur, et les boutons radio — dont la pastille .radio-custom
   n'était qu'un <span> vide invisible — se retrouvaient décalés.
   ========================================================================== */

.property-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* --- Deux colonnes ---------------------------------------------------- */
/* 12 colonnes : 7 pour la saisie principale, 5 pour les réglages. Sous
   1024px on repasse à une colonne — deux colonnes de 400px forceraient les
   libellés à casser. */
.form-two-col {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--space-6);
  align-items: start;
}
@media (max-width: 1023px) {
  .form-two-col { grid-template-columns: minmax(0, 1fr); }
}
.form-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}

/* --- Panneaux d'onglets ----------------------------------------------- */
/* Amélioration progressive, dans ce sens-là et pas l'autre : par défaut la
   barre d'onglets est MASQUÉE et tous les panneaux sont VISIBLES, précédés de
   leur titre. Le formulaire reste donc entièrement utilisable et
   enregistrable si le script ne charge pas — ce qui compte pour un écran où
   l'on configure une propriété entière.
   Le script ajoute .js-tabs-ready sur le conteneur : la barre apparaît, les
   titres de panneaux s'effacent (l'onglet les porte désormais) et seul le
   panneau actif reste affiché. */
.form-tabs { display: none; }
.form-tabpanel + .form-tabpanel { margin-top: var(--space-8); }
.form-tabpanel-title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.02em;
  margin-bottom: var(--space-4);
}

.js-tabs-ready .form-tabs { display: flex; }
.js-tabs-ready .form-tabpanel { display: none; margin-top: 0; }
.js-tabs-ready .form-tabpanel.is-active { display: block; }
.js-tabs-ready .form-tabpanel-title { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .js-tabs-ready .form-tabpanel.is-active {
    animation: fadeIn 150ms cubic-bezier(0, 0, 0.2, 1);
  }
}

/* --- Groupes de boutons radio ----------------------------------------- */
/* En ligne tant que ça tient, empilés sinon. La pastille est dessinée en
   CSS (comme .checkbox-custom) et l'input natif reste présent, juste
   masqué visuellement — le clavier et les lecteurs d'écran le voient. */
.radio-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.radio-group--stack {
  flex-direction: column;
  flex-wrap: nowrap;
}

.radio-label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.radio-label:hover { border-color: var(--color-primary-100); }

/* L'option choisie se voit à la BORDURE et au fond, pas seulement à la
   pastille : à trois options côte à côte, repérer une pastille de 18px
   demandait de regarder deux fois. */
.radio-label:has(.radio-input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
}

.radio-input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.radio-custom {
  width: 18px;
  height: 18px;
  border: 2px solid var(--color-gray-300);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  flex-shrink: 0;
  display: block;
  position: relative;
  transition: border-color var(--transition-fast);
}
.radio-input:checked + .radio-custom {
  border-color: var(--color-primary);
}
.radio-input:checked + .radio-custom::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
}
.radio-input:focus-visible + .radio-custom {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.radio-text {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-700);
  line-height: var(--leading-snug);
}
.radio-label:has(.radio-input:checked) .radio-text { color: var(--color-primary-ink); }

/* --- Case à cocher « réglage » ---------------------------------------- */
/* Un interrupteur de réglage, avec son explication SOUS le libellé et non
   dans un paragraphe détaché : la case, son libellé et sa conséquence sont
   un seul bloc cliquable. */
.setting-toggle {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.setting-toggle:hover { border-color: var(--color-primary-100); }
.setting-toggle:has(.checkbox-input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
}
.setting-toggle .checkbox-custom { margin-top: 0; }
.setting-toggle-body { min-width: 0; }
.setting-toggle-label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  line-height: var(--leading-snug);
}
.setting-toggle-hint {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-gray-600);
  line-height: var(--leading-body);
  max-width: var(--measure);
}

/* --- Liste d'agents à cocher ------------------------------------------ */
.agents-checklist {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.agent-check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  user-select: none;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.agent-check:hover { border-color: var(--color-primary-100); }
.agent-check:has(.checkbox-input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-50);
}
.agent-check-body { min-width: 0; }
.agent-check-name {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* L'adresse e-mail passe en dessous, en gris : accolée au nom derrière un
   tiret cadratin, elle se lisait comme une partie du nom. */
.agent-check-email {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Divers éléments de formulaire ------------------------------------ */
.form-textarea {
  display: block;
  width: 100%;
  padding: 0.5625rem var(--space-3);
  font-size: var(--text-sm);
  font-family: inherit;
  line-height: var(--leading-body);
  color: var(--color-gray-900);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  resize: vertical;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.form-textarea:focus {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-focus);
}

.form-divider {
  border: none;
  border-top: 1px solid var(--color-border-subtle);
  margin: var(--space-6) 0 var(--space-5);
}

.form-section-title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  letter-spacing: -0.01em;
  margin-bottom: var(--space-4);
}

/* Ligne « champ + bouton » (test d'une URL iCal, import Airbnb) : le bouton
   garde sa largeur, le champ prend le reste. */
.ical-input-row {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
}
.ical-input-row .btn { flex-shrink: 0; }
.ical-url-input { min-width: 0; flex: 1; }
@media (max-width: 479px) {
  .ical-input-row { flex-direction: column; }
  .ical-input-row .btn { width: 100%; justify-content: center; }
}

/* Suffixe d'unité (MAD) accolé au champ, plutôt que flottant à sa droite. */
.input-group-addon {
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  background: var(--color-gray-50);
  border: 1px solid var(--color-border);
  border-left: none;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-600);
  white-space: nowrap;
  flex-shrink: 0;
}
.input-group:has(.input-group-addon) .form-input {
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}
[dir="rtl"] .input-group-addon {
  border-left: 1px solid var(--color-border);
  border-right: none;
  border-radius: var(--radius-md) 0 0 var(--radius-md);
}
[dir="rtl"] .input-group:has(.input-group-addon) .form-input {
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
}

/* Barre d'enregistrement : collée en bas de l'écran tant qu'on édite, pour
   ne pas avoir à remonter toute la page pour sauver. */
.form-submit-panel {
  position: sticky;
  bottom: 0;
  z-index: var(--z-raised);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
@media (max-width: 639px) {
  .form-submit-panel { flex-direction: column-reverse; }
  .form-submit-panel .btn { width: 100%; justify-content: center; }
}

/* Zone de suppression : rail rouge à gauche, même grammaire que les cartes
   de statut du tableau de bord. Elle est en dehors des onglets — une action
   irréversible ne se cache pas derrière un onglet. */
.danger-zone {
  border-left: var(--rail-width) solid var(--color-danger);
}
[dir="rtl"] .danger-zone {
  border-left: 1px solid var(--color-border);
  border-right: var(--rail-width) solid var(--color-danger);
}
.card-title--danger { color: var(--color-danger-dark); }

/* ==========================================================================
   47. LISTE DE MÉTADONNÉES (contexte en lecture seule)
   --------------------------------------------------------------------------
   Paires libellé / valeur d'un objet qu'on CONSULTE sans le modifier : dates
   de création, dernière connexion, statuts calculés. Le libellé est discret
   et la valeur porte le poids — l'inverse de ce que fait un formulaire, parce
   qu'ici la valeur est l'information et le libellé n'est qu'un repère.
   ========================================================================== */

.meta-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
}
.meta-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}
.meta-row + .meta-row {
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border-subtle);
}
.meta-row > dt {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-500);
  flex-shrink: 0;
}
.meta-row > dd {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  text-align: right;
  min-width: 0;
  overflow-wrap: anywhere;
}
[dir="rtl"] .meta-row > dd { text-align: left; }

/* Sur téléphone, libellé et valeur s'empilent : côte à côte dans une colonne
   de 300px, une valeur un peu longue (une phrase d'explication) se retrouvait
   compressée sur dix lignes de trois mots. */
@media (max-width: 639px) {
  .meta-row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }
  .meta-row > dd { text-align: left; }
  [dir="rtl"] .meta-row > dd { text-align: right; }
}

/* Identifiants, numéros, adresses IP : chiffres à largeur fixe pour qu'ils
   s'alignent et se comparent à l'œil. Pas de police monospace — la graisse et
   la tabulation des chiffres suffisent. */
.meta-value-num {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* Précision secondaire sous une valeur (IP d'une connexion, nom derrière un
   numéro) : elle passe à la ligne et s'efface. */
.meta-sub {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-normal);
  color: var(--color-gray-500);
  line-height: var(--leading-body);
  margin-top: 2px;
  max-width: var(--measure);
  /* La valeur est alignée à droite dans .meta-row ; une phrase, elle, se lit
     alignée au début de ligne — sinon chaque ligne démarre ailleurs. */
  text-align: left;
}
[dir="rtl"] .meta-sub { text-align: right; }

/* « (facultatif) » accolé à un libellé de champ. */
.form-label-optional {
  font-weight: var(--font-weight-normal);
  font-size: var(--text-xs);
  color: var(--color-gray-500);
}

/* Accès à la fiche de check-in depuis la réservation (« Voir le check-in »,
   « Voir la fiche ») : bouton plein, bien visible. Contraste blanc / #1d6e87
   ≈ 5,6:1 (AA). */
.btn-checkin-link {
  width: 100% !important;
  justify-content: center;
  background-color: #1d6e87;
  border-color: #1d6e87;
  color: #fff;
}
.btn-checkin-link:hover,
.btn-checkin-link:focus-visible {
  background-color: #175a6f;
  border-color: #175a6f;
  color: #fff;
}

/* ==========================================================================
   48. MONTANT DE RÉSERVATION — correction rapide depuis la liste (Lot J)
   --------------------------------------------------------------------------
   Les flux iCal d'Airbnb et Booking ne transmettent jamais le prix : le
   montant affiché ici est le plus souvent une ESTIMATION (prix par nuitée du
   logement × nombre de nuits). Le badge « Estimé » le dit, et la colonne est
   éditable sur place pour que corriger un tarif négocié ne demande pas
   d'ouvrir le formulaire complet de la réservation.

   Construit sur <details>/<summary> : sans JavaScript, le clic ouvre le petit
   formulaire et l'enregistrement part en POST classique. Le marqueur natif du
   <summary> est retiré — le crayon le remplace, et il dit mieux ce qui va se
   passer.
   ========================================================================== */

.amount-edit > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  padding: 2px 4px;
  margin: -2px -4px;
  border-radius: var(--radius-sm);
  list-style: none;
}
.amount-edit > summary::-webkit-details-marker { display: none; }
.amount-edit > summary::marker { content: ''; }

.amount-edit > summary:hover { background: var(--color-gray-50); }
.amount-edit > summary:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 1px;
}

.amount-edit__value {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-900);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.amount-edit__unit {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-normal);
  color: var(--color-gray-500);
}

/* Aucun montant en base : une invitation, pas un tiret muet. */
.amount-edit__empty {
  font-size: var(--text-xs);
  color: var(--color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}

/* Le crayon ne s'impose qu'au survol / focus de la ligne : la colonne reste
   lisible comme une colonne de chiffres. */
.amount-edit__pencil {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  color: var(--color-gray-400);
  opacity: 0;
  transition: opacity var(--transition-fast);
}
.amount-edit > summary:hover .amount-edit__pencil,
.amount-edit > summary:focus-visible .amount-edit__pencil,
.amount-edit[open] .amount-edit__pencil { opacity: 1; }

/* Sur écran tactile il n'y a pas de survol : le crayon reste visible. */
@media (hover: none) {
  .amount-edit__pencil { opacity: 1; }
}

/* Le formulaire reste DANS le flux de la cellule : la ligne s'agrandit le
   temps de la saisie. Un panneau flottant (position:absolute) serait rogné —
   .table-wrapper pose overflow-x:auto et contain:paint (§ 43), qui coupent
   tout ce qui dépasse de la cellule. Une ligne qui grandit est honnête ; un
   formulaire à moitié invisible ne l'est pas. */
.amount-edit__form {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: var(--space-2);
  min-width: 11rem;
  max-width: 17rem;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.amount-edit__form .input-group { flex: 1 1 auto; min-width: 0; }
.amount-edit__form .btn { flex-shrink: 0; }

/* Le champ n'a pas besoin de la hauteur d'un champ de formulaire pleine page :
   il s'intercale dans une ligne de tableau. */
.amount-edit__form .form-input {
  padding-block: var(--space-1);
  font-size: var(--text-sm);
}

@media (max-width: 767px) {
  .amount-edit__form { max-width: none; }
}

/* ==========================================================================
   49. BANNIÈRE D'ALERTE RÉUTILISABLE (views/components/alert-banner.php)
   --------------------------------------------------------------------------
   Même traitement visuel que les messages flash (.alert / .alert-warning,
   § 15) : un bandeau d'information n'est pas un nouveau type d'objet, c'est
   un message. S'ajoutent seulement la place du bouton d'action à droite et la
   liste de liens quand le message concerne plusieurs objets nommés.
   ========================================================================== */

.alert-banner {
  align-items: center;
  margin-bottom: var(--space-6);
}
.alert-banner__icon {
  flex-shrink: 0;
  font-size: 1rem;
  font-weight: var(--font-weight-semibold);
  line-height: 1.4;
}
.alert-banner__text {
  margin: 0;
  line-height: 1.5;
}
.alert-banner .alert-title + .alert-banner__text { margin-top: 2px; }

/* Les logements concernés, nommés : l'hôte va droit au bon formulaire au lieu
   de rouvrir sa liste et de chercher lesquels il a oubliés. */
.alert-banner__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
}
.alert-banner__links a {
  color: inherit;
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.alert-banner__cta {
  flex-shrink: 0;
  white-space: nowrap;
}

@media (max-width: 639px) {
  .alert-banner { align-items: flex-start; flex-wrap: wrap; }
  .alert-banner__cta { width: 100%; justify-content: center; }
}

/* ==========================================================================
   50. BANDEAU « VIREMENT BANCAIRE » (views/components/billing-banner.php)
   --------------------------------------------------------------------------
   La version précédente alignait montant, banque, RIB et référence dans une
   seule rangée flex : les quatre informations avaient le même poids visuel,
   et le RIB — la donnée qu'on vient précisément CHERCHER ici — se lisait
   comme une note de bas de page. Le bandeau est redécoupé en deux blocs
   nommés et iconographiés : « où virer » (coordonnées du compte) puis « quoi
   virer » (montant et référence), chacun avec son bouton de copie.

   Deux valeurs seulement se recopient dans une application bancaire : le RIB
   et la référence. Ce sont les seules en monospace, encadrées, à chiffres
   tabulaires — on les repère sans lire. Tout le reste (titulaire, banque) est
   du contexte : libellé discret, valeur en ardoise.

   Aucune couleur en dur : les anciens #eff6ff / #fef2f2 inline restaient des
   taches claires en thème sombre. Les tokens de statut (§ 1 et § 2) basculent
   seuls.
   ========================================================================== */

.pay-transfer {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  /* Le rail de statut porte l'urgence sans colorer tout le panneau : bleu
     « à régler », terre cuite « en retard ». */
  border-inline-start: var(--rail-width, 4px) solid var(--color-info);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: var(--space-6);
}
.pay-transfer--late {
  border-inline-start-color: var(--color-danger);
}

/* --- En-tête : statut + intitulé ------------------------------------- */

.pay-transfer__head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--color-info-light);
  border-bottom: 1px solid var(--color-border);
}
.pay-transfer--late .pay-transfer__head {
  background: var(--color-danger-light);
}
.pay-transfer__head-icon {
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: var(--color-surface);
  color: var(--color-info-dark);
}
.pay-transfer--late .pay-transfer__head-icon { color: var(--color-danger-dark); }
.pay-transfer__head-icon svg { width: 1.15rem; height: 1.15rem; }
.pay-transfer__head-body { min-width: 0; }
.pay-transfer__title {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-snug);
  color: var(--color-info-dark);
}
.pay-transfer--late .pay-transfer__title { color: var(--color-danger-dark); }
.pay-transfer__subtitle {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  color: var(--color-gray-600);
  max-width: var(--measure);
}

/* --- Les deux blocs : où virer / quoi virer --------------------------- */

.pay-transfer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}
.pay-transfer__block {
  padding: var(--space-5);
  min-width: 0;
}
/* Séparateur entre les deux blocs quand ils tiennent côte à côte ; il passe
   en horizontal dès qu'ils s'empilent (media query plus bas). */
.pay-transfer__block + .pay-transfer__block {
  border-inline-start: 1px solid var(--color-border-subtle);
}
.pay-transfer__block-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-gray-700);
}
.pay-transfer__block-icon {
  flex-shrink: 0;
  width: 1.75rem;
  height: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-100);
  color: var(--color-primary-ink);
}
.pay-transfer__block-icon svg { width: 1rem; height: 1rem; }
.pay-transfer__block-hint {
  margin: 0 0 var(--space-4);
  font-size: var(--text-xs);
  line-height: var(--leading-body);
  color: var(--color-gray-500);
  max-width: var(--measure);
}

/* --- Paires libellé / valeur ----------------------------------------- */

.pay-transfer__fields {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
}
.pay-transfer__field + .pay-transfer__field {
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border-subtle);
}
.pay-transfer__label {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  color: var(--color-gray-500);
  margin-bottom: var(--space-1);
}
.pay-transfer__value {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-gray-900);
  overflow-wrap: anywhere;
}

/* --- Valeurs à recopier : RIB et référence --------------------------- */

/* Le monospace n'est pas décoratif : il sert à relire un numéro chiffre par
   chiffre et à repérer une faute de frappe. On le réserve donc à ces deux
   valeurs. */
.pay-transfer__copyline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.pay-transfer__code {
  flex: 1 1 14rem;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--color-gray-900);
  /* La règle globale `code` (§ 5) impose fond, padding et rayon en
     !important : ici le <code> n'est pas un extrait de code au fil du texte
     mais un champ qu'on vient lire et recopier, il lui faut sa propre boîte.
     C'est la seule façon de reprendre la main sans toucher à la règle
     globale, utilisée partout ailleurs. */
  background: var(--color-gray-50) !important;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md) !important;
  padding: var(--space-2) var(--space-3) !important;
  overflow-wrap: anywhere;
  /* Un double-clic sélectionne le numéro entier, pas un groupe de chiffres :
     la copie manuelle reste possible si le presse-papiers est refusé. */
  user-select: all;
  -webkit-user-select: all;
  /* En arabe, l'algorithme bidi réordonne les groupes d'un RIB écrit avec des
     espaces : « 022 480 0002610009030618 02 » s'affichait à l'envers, donc se
     recopiait faux. Le numéro est isolé en LTR, quel que soit le sens de la
     page. */
  direction: ltr;
  unicode-bidi: isolate;
  text-align: left;
}
.pay-transfer__code--ref {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  color: var(--color-info-dark);
  background: var(--color-info-light) !important;
  border-color: var(--color-info-dark);
  text-align: center;
  flex-basis: 10rem;
}
.pay-transfer__copy { flex-shrink: 0; }
/* Confirmation de copie : vert de statut, le temps du retour (2 s). */
.pay-transfer__copy.is-copied,
.pay-transfer__copy.is-copied:disabled {
  color: var(--color-success-dark);
  border-color: var(--color-success-dark);
  opacity: 1;
}

/* --- Montant à régler ------------------------------------------------- */

/* C'est le chiffre qu'on cherche en premier : il monte en taille et en
   graisse plutôt que de partager une ligne avec trois autres données. */
.pay-transfer__amount {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.pay-transfer__amount-value {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  color: var(--color-gray-900);
}

/* Référence oubliée = virement non rattachable : l'avertissement est dans le
   bloc, pas en pied de page. */
.pay-transfer__warn {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  line-height: var(--leading-body);
  color: var(--color-warning-dark);
}
.pay-transfer__warn svg {
  flex-shrink: 0;
  width: 0.95rem;
  height: 0.95rem;
  margin-top: 0.15rem;
}

/* --- Pied : confirmation du virement ---------------------------------- */

.pay-transfer__foot {
  padding: var(--space-5);
  background: var(--color-gray-50);
  border-top: 1px solid var(--color-border);
}
.pay-transfer__foot-text {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
  color: var(--color-gray-600);
  max-width: var(--measure);
}
.pay-transfer__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
/* Le champ fichier natif ne se style pas : on habille son <label> en zone
   discrète et on garde l'input à l'intérieur, cliquable. */
.pay-transfer__file {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1 1 18rem;
  min-width: 0;
  font-size: var(--text-xs);
  color: var(--color-gray-600);
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
}
.pay-transfer__file:hover { border-color: var(--color-primary-100); }
.pay-transfer__file svg { flex-shrink: 0; width: 1rem; height: 1rem; }
.pay-transfer__file input[type="file"] {
  font-size: var(--text-xs);
  color: var(--color-gray-500);
  min-width: 0;
  flex: 1 1 8rem;
}
/* Le bouton natif « Choose File » arrive non stylé et en anglais du système :
   on le rhabille a minima pour qu'il ne casse pas la ligne d'actions. */
.pay-transfer__file input[type="file"]::file-selector-button {
  font: inherit;
  font-size: var(--text-xs);
  color: var(--btn-secondary-fg);
  background: var(--color-surface);
  border: 1px solid var(--btn-secondary-border);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  margin-inline-end: var(--space-2);
  cursor: pointer;
}
.pay-transfer__file input[type="file"]::file-selector-button:hover {
  background: var(--btn-secondary-bg-hover);
}
.pay-transfer__file-label { white-space: nowrap; }
.pay-transfer__wa {
  background: #25D366;
  border-color: #25D366;
  color: #0b3d20;
}
.pay-transfer__wa:hover,
.pay-transfer__wa:focus-visible {
  background: #1da851;
  border-color: #1da851;
  color: #fff;
}
.pay-transfer__receipt {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  color: var(--color-success-dark);
}
.pay-transfer__receipt svg { flex-shrink: 0; width: 1rem; height: 1rem; }
.pay-transfer__note {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  line-height: var(--leading-body);
  color: var(--color-gray-500);
  max-width: var(--measure);
}

/* --- Empilement ------------------------------------------------------- */

/* Dès que les blocs s'empilent (une colonne), le séparateur vertical devient
   horizontal — sinon il reste un trait orphelin sur le côté. */
@media (max-width: 47.9375rem) {
  .pay-transfer__block + .pay-transfer__block {
    border-inline-start: 0;
    border-top: 1px solid var(--color-border-subtle);
  }
}

@media (max-width: 39.9375rem) {
  .pay-transfer__head,
  .pay-transfer__block,
  .pay-transfer__foot { padding: var(--space-4); }
  /* Au doigt, un bouton de copie à côté d'un numéro long devient illisible :
     il prend sa propre ligne, pleine largeur. */
  .pay-transfer__code { flex-basis: 100%; }
  .pay-transfer__copy,
  .pay-transfer__submit,
  .pay-transfer__wa { width: 100%; }
  /* Le champ fichier natif a une largeur intrinsèque (bouton système + nom du
     fichier) qui débordait de l'écran : il passe sous son libellé. */
  .pay-transfer__file { flex-basis: 100%; flex-wrap: wrap; }
  .pay-transfer__file input[type="file"] { flex-basis: 100%; max-width: 100%; }
}

/* ==========================================================================
   51. VITRINE DU LOGEMENT — côté HÔTE (demandes reçues, réglages)
   --------------------------------------------------------------------------
   La page PUBLIQUE (/v/{slug}) a sa propre feuille, vitrine.css. Ici on
   n'habille que les deux écrans de l'espace hôte :
     - views/vitrine/demandes.php  (liste des demandes à traiter)
     - views/vitrine/reglages.php  (galerie, description, équipements, slug)

   Aucune couleur ni police nouvelle : uniquement les tokens de tokens.css.
   Le rail de statut reprend la convention de la section 37 (.booking-row--*)
   — un liseré de 4px qui DOUBLE toujours un badge texte, jamais seul.
   ========================================================================== */

.vh-list { display: flex; flex-direction: column; gap: var(--space-4); }

.vh-item {
  padding: var(--space-5);
  border-left: var(--rail-width, 4px) solid var(--rail-neutral);
}
[dir="rtl"] .vh-item { border-left: none; border-right: var(--rail-width, 4px) solid var(--rail-neutral); }

/* Une demande en attente appelle une action : fond légèrement ambré, comme
   .booking-row--attention, pour se voir depuis l'autre bout de l'écran. */
.vh-item.rail--pending { border-left-color: var(--rail-pending); background: var(--color-warning-light); }
.vh-item.rail--done    { border-left-color: var(--rail-done); }
.vh-item.rail--neutral { border-left-color: var(--rail-neutral); }
[dir="rtl"] .vh-item.rail--pending { border-right-color: var(--rail-pending); }
[dir="rtl"] .vh-item.rail--done    { border-right-color: var(--rail-done); }
[dir="rtl"] .vh-item.rail--neutral { border-right-color: var(--rail-neutral); }

.vh-item__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-3); margin-bottom: var(--space-4);
}
.vh-item__name {
  margin: 0;
  font-size: var(--text-base); font-weight: var(--value-weight); color: var(--ink-900);
}
.vh-item__property { margin: var(--space-0-5) 0 0; font-size: var(--label-size); color: var(--slate-500); }

.vh-item__facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--space-4); margin: 0 0 var(--space-4);
}
.vh-item__facts dt { font-size: var(--label-size); font-weight: var(--label-weight); color: var(--slate-500); margin-bottom: var(--space-0-5); }
.vh-item__facts dd { margin: 0; font-weight: var(--value-weight); color: var(--ink-900); overflow-wrap: anywhere; }

.vh-item__warn {
  display: flex; align-items: flex-start; gap: var(--space-2);
  margin: 0 0 var(--space-4); padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-warning-light); color: var(--warning-600);
  font-size: 0.85rem;
}
.vh-item__warn svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; }

.vh-item__note { margin: 0 0 var(--space-4); font-size: 0.85rem; }

.vh-item__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.vh-inline-form { display: contents; }

/* Détail du calcul de prix d'une demande, replié : il n'intéresse l'hôte que
   s'il doute du total, mais il doit alors être là — c'est ce montant-là qui a
   été annoncé au voyageur, même si les saisons ont changé depuis. */
.vh-price-detail { margin-top: var(--space-1); font-weight: var(--font-weight-regular, 400); }
.vh-price-detail summary {
  font-size: var(--label-size); color: var(--navy-700);
  cursor: pointer;
}
.vh-price-detail ul {
  margin: var(--space-2) 0 0; padding-inline-start: var(--space-4);
  font-size: 0.8rem; color: var(--slate-500);
}

/* ---------- Réglages : hiérarchie et rythme (lot du 19/10) ------------ */
/* Trois niveaux et trois seulement : TITRE DE SECTION (encre, gras),
   LIBELLÉ DE CHAMP (encre atténuée, medium), AIDE (ardoise, petite). Avant
   ce lot, le titre de section et le libellé de champ avaient presque le même
   poids : l'écran se lisait comme une suite de paragraphes sans relief.

   Aucun fond décoratif, aucun dégradé, aucune animation : c'est un écran de
   saisie, et chaque couleur en plus y coûte de la lisibilité. */

.vh-settings .card { margin-bottom: var(--block-gap); }
.vh-settings .card:last-child { margin-bottom: 0; }

.vh-settings .card-header-title {
  font-size: var(--text-lg);
  font-weight: var(--title-weight);
  color: var(--ink-900);
  /* Icône et mot sur une ligne, alignés sur leur MILIEU : l'icône fait 20px
     pour un titre de 1.125rem, et un alignement sur la ligne de base la
     posait un demi-pixel trop haut sur deux tracés sur trois. */
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* Icône du titre de section (components/vitrine-section-icon). Elle ILLUSTRE
   le titre : encre atténuée, jamais le bleu des boutons — sans quoi huit
   taches de marque se disputeraient l'écran avec le seul bouton qui compte.
   `flex: 0 0 auto` l'empêche d'être écrasée quand le titre se casse en deux
   lignes sur un téléphone. */
.vh-section__icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  color: var(--slate-500);
}

/* L'aide d'un champ, en texte SECONDAIRE. `.form-help` n'était jusqu'ici
   qu'une largeur de ligne : rendue par la règle de <p>, elle sortait à 16 px
   dans la même encre que le libellé du champ — d'où un écran qui se lisait
   comme une suite de paragraphes, sans distinguer ce qu'on remplit de ce qui
   l'explique. Le contrat appliqué ici est celui de `.form-hint`, qui le porte
   déjà ailleurs dans l'application. PORTÉE VOLONTAIREMENT LIMITÉE à cet
   écran : `.form-help` est employée dans toute l'administration, et la
   corriger globalement dépasse ce lot. */
.vh-settings .form-help {
  margin-top: var(--space-1-5, 0.375rem);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--slate-500);
}

/* Sous-titre d'un formulaire interne (« Ajouter une saison », « Dupliquer une
   année ») : sous le titre de section, au-dessus des libellés. */
.vh-subtitle {
  margin: 0 0 var(--space-3);
  font-size: var(--text-base);
  font-weight: var(--value-weight);
  color: var(--ink-900);
}

/* Texte secondaire d'une section (état vide, valeur absente, période d'une
   saison). Remplace .text-muted, qui porte un !important et empêchait tout
   ajustement local. */
.vh-note {
  font-size: var(--text-sm);
  color: var(--slate-500);
}

/* Rappel du NOM INTERNE sous le champ « Titre de l'annonce ». Atténué à
   dessein : c'est une information de repère, pas un champ à remplir — il se
   modifie dans la fiche du logement. Le voyageur ne le voit jamais. */
.vh-titre-interne {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--slate-500);
}

/* Séparateur interne d'une section : filet discret et marges RÉGULIÈRES,
   là où un `hr.mt-4.mb-4` donnait des écarts différents selon la section. */
.vh-rule {
  margin: var(--space-5) 0;
  border: 0;
  border-top: 1px solid var(--hairline-subtle);
}

/* Bloc replié : textes alternatifs, suppression de photo, « En savoir plus ».
   Le chevron natif est conservé — il dit déjà qu'on peut ouvrir. */
.vh-fold { margin-top: var(--space-4); }
.vh-fold > summary {
  cursor: pointer;
  font-size: var(--text-sm);
  font-weight: var(--label-weight);
  color: var(--ink-700);
}
.vh-fold > summary:hover { color: var(--ink-900); }
.vh-fold > summary:focus-visible {
  outline: 2px solid var(--navy-500);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.vh-fold[open] > summary { margin-bottom: var(--space-3); }

/* « En savoir plus » : le paragraphe long d'une section. Détaché du dernier
   champ par un filet, pour qu'on ne le prenne pas pour son aide. */
.vh-fold--more {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--hairline-subtle);
}

/* Barre d'enregistrement du formulaire de réglages : un seul bouton pour
   toutes les sections qu'il porte. Aligné à droite, au bord des cartes, pour
   se lire comme l'action DU FORMULAIRE et non comme celle de la dernière
   section. Pleine largeur sous 480 px, où un bouton au bord se rate. */
.vh-save {
  display: flex; justify-content: flex-end;
  margin-bottom: var(--block-gap);
}
@media (max-width: 480px) {
  .vh-save .btn { width: 100%; justify-content: center; }
}

/* ---------- Récapitulatif des pages par logement ---------------------- */
/* En tête de la liste des demandes. Présent même quand rien n'est publié :
   c'est le cas où l'hôte a le plus besoin de savoir ce qui lui manque. */

.vh-pages { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-3); }

.vh-page {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
}
.vh-page__head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-2);
}
.vh-page__name { font-weight: var(--value-weight); color: var(--ink-900); overflow-wrap: anywhere; }
.vh-page__blockers {
  margin: var(--space-2) 0 0; padding-inline-start: var(--space-4);
  font-size: 0.85rem; color: var(--warning-600);
}
.vh-page__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

/* ---------- Réglages de la vitrine ------------------------------------ */

/* Texte alternatif d'une photo : le champ et son bouton sur une ligne, un
   formulaire par photo (un POST ne porte qu'une action, et les formulaires
   HTML ne s'imbriquent pas — celui de l'ordre des photos englobe la grille). */
.vh-alt-form { margin-bottom: var(--space-3); }
.vh-alt-row { display: flex; gap: var(--space-2); align-items: flex-start; }
.vh-alt-row > input { flex: 1 1 auto; min-width: 0; }
.vh-alt-row > .btn { flex: 0 0 auto; }

@media (max-width: 480px) {
  .vh-alt-row { flex-wrap: wrap; }
  .vh-alt-row > input { flex-basis: 100%; }
}

/* Le lien partagé est une VALEUR à lire et à copier, pas un encart : fond de
   surface et filet plein. Le bleu de marque reste aux boutons, aux liens et
   aux états actifs — un aplat bleu de plus faisait de cet écran une page
   bleue sur laquelle plus rien ne ressortait. */
.vh-url {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.vh-url__value {
  flex: 1 1 240px; min-width: 0;
  font-family: var(--font-mono, monospace); font-size: 0.85rem;
  color: var(--ink-900); overflow-wrap: anywhere;
}

/* Grille de la galerie côté hôte : la position 0 est signalée « Couverture ». */
.vh-photos {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3); margin: 0 0 var(--space-4); padding: 0; list-style: none;
}
.vh-photo { position: relative; border-radius: var(--radius-md); overflow: hidden; background: var(--color-gray-100); }
.vh-photo img { display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.vh-photo__cover {
  position: absolute; top: var(--space-2); inset-inline-start: var(--space-2);
  padding: 2px var(--space-2); border-radius: var(--radius-full);
  background: var(--clay-500); color: var(--ink-900);
  font-size: 0.7rem; font-weight: var(--value-weight);
}
.vh-photo__tools {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-1);
  padding: var(--space-2);
}
.vh-photo__pos {
  width: 4.5rem; padding: var(--space-1);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink-900);
  font-family: inherit; font-size: 0.85rem;
}

/* Récapitulatif de la sélection du champ d'envoi multiple de photos : la
   liste des noms de fichiers choisis, rempli par vitrine-host.js. Même encre
   et même taille qu'une aide de champ — c'est du texte de service, pas une
   valeur à lire. `overflow-wrap` parce qu'un nom d'appareil photo
   (« IMG_20261019_143512.jpg ») ne se coupe sur aucune espace. */
.vh-upload-note {
  margin-top: var(--space-1-5, 0.375rem);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--slate-500);
  overflow-wrap: anywhere;
}
/* Plus de fichiers choisis que de places restantes : le surplus sera refusé
   par le serveur, et l'avertissement le dit avant l'envoi. */
.vh-upload-note--warn { color: var(--warning-600); }

.vh-blockers { margin: 0 0 var(--space-4); padding-inline-start: var(--space-5); font-size: 0.875rem; color: var(--warning-600); }
.vh-blockers li { margin-bottom: var(--space-1); }

.vh-equip-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--space-2) var(--space-4);
}
.vh-equip-check { display: flex; align-items: center; gap: var(--space-2); font-size: 0.9rem; color: var(--ink-700); }

/* Titre de catégorie dans la liste à cocher de l'hôte. Même ordre et mêmes
   libellés que la page publique : l'hôte coche la liste telle que le
   voyageur la lira. Discret — il ordonne, il ne découpe pas la section. */
.vh-equip-cat {
  margin: var(--space-5) 0 var(--space-2);
  font-size: var(--label-size);
  font-weight: var(--label-weight);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--slate-500);
}
.vh-equip-cat:first-of-type { margin-top: 0; }

.vh-counter { font-size: 0.78rem; color: var(--slate-500); }

@media (max-width: 640px) {
  .vh-item__head { flex-direction: column; }
  .vh-item__actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* ---------- Réglages de la page multi-annonces (/vitrine/profil) ------- */
/* Une ligne par logement : son nom à gauche, son bouton à droite. Pas de
   carte ni de rail de couleur comme .vh-item — ces lignes ne portent aucun
   état à signaler, ce sont des entrées de liste. */

.vp-liste { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }

.vp-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--hairline-subtle);
}
.vp-row:last-child { border-bottom: none; }

/* À l'étroit, le bouton passe sous le nom plutôt que de le comprimer en
   colonne de deux caractères. */
@media (max-width: 480px) {
  .vp-row { flex-direction: column; align-items: stretch; gap: var(--space-2); }
}

/* ==========================================================================
   ADMIN — LOT 2026-10-28 : tuiles de chiffre, tableaux larges, troncatures
   --------------------------------------------------------------------------
   Les écrans d'administration affichent des nombres courts sous des libellés
   longs (« Nouvelles propriétés (30 j) »), dans des grilles qui descendaient
   jusqu'à 160px. En dessous d'environ 180px, « 1 285 DH » se brisait en
   trois lignes et le libellé partait en colonne d'un caractère. Ces règles
   fixent la largeur plancher d'une tuile, empêchent le nombre de se couper,
   et bornent le libellé à deux lignes.
   ========================================================================== */

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-4, 1rem);
  margin-bottom: 1.5rem;
}

/* La tuile EMPILE : icône, puis chiffre, puis libellé.
   `display:flex` + `flex-direction:column` sont indispensables et non
   décoratifs : `.stat-card` (section 37) pose `display:flex` en ligne, et une
   tuile qui porte les deux classes héritait de cette ligne — icône, chiffre et
   libellé côte à côte dans 170px, avec `overflow:hidden` sur .stat-card qui
   tranchait le chiffre en plein milieu (« 12| » pour 128, « 85| » pour 852).
   Cette règle est déclarée APRÈS .stat-card dans le fichier : à spécificité
   égale (une classe), c'est elle qui l'emporte. Ne pas la déplacer plus haut. */
.kpi-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 0;
  padding: 1.25rem 0.75rem;
  text-align: center;
  min-width: 0; /* sans ça, le contenu impose sa largeur et la grille déborde */
  /* .stat-card coupe ce qui dépasse ; ici le chiffre doit rester entier. */
  overflow: visible;
}

.kpi-tile__icon { font-size: 1.75rem; margin-bottom: 0.5rem; line-height: 1; }

/* Le nombre ne se coupe jamais : il rétrécit (clamp) plutôt que de passer à
   la ligne au milieu d'un montant. */
.kpi-tile__value {
  /* Largeur pleine + nombres à chasse fixe : le chiffre occupe toute la
     tuile et ne peut plus être rogné par un voisin de ligne. */
  width: 100%;
  font-size: clamp(1.25rem, 4.5vw, 2rem);
  font-weight: 800;
  line-height: 1.15;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  /* Un montant exceptionnellement long (« 1 285 000 DH ») rétrécit plutôt
     que de déborder ; il reste lisible, et jamais tronqué en plein chiffre. */
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Libellé sous le nombre, deux lignes au maximum puis « … ». */
.kpi-tile__label {
  width: 100%;
  font-size: 0.8rem;
  color: var(--color-gray-500);
  margin-top: 0.25rem;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Un écran très étroit (390px) tient deux tuiles par ligne plutôt qu'une
   seule tuile énorme suivie de six autres. */
@media (max-width: 480px) {
  .kpi-grid { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.6rem; }
  .kpi-tile { padding: 0.9rem 0.6rem; }
  .kpi-tile__icon { font-size: 1.35rem; }
}

/* Tout tableau d'administration défile horizontalement plutôt que de
   comprimer ses colonnes d'action jusqu'à couper « Demander justific… ». */
.admin-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Une adresse e-mail longue coupe où elle peut : c'est une suite de
   caractères sans espace, elle élargirait la ligne indéfiniment. */
.cell-email { word-break: break-all; }

/* Nom de logement / libellé long : tronqué proprement, texte complet au
   survol via l'attribut title (que les vues posent systématiquement). */
.cell-truncate {
  display: block;
  max-width: 22ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Colonne d'actions : les boutons s'empilent au lieu de déborder. En
   grand écran ils restent côte à côte. */
.actions-stack {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
}
@media (max-width: 1100px) {
  .actions-stack { flex-direction: column; align-items: stretch; }
  .actions-stack > * { width: 100%; }
  .actions-stack .btn { width: 100%; justify-content: center; }
}

/* Recherche rapide globale de l'administration, dans l'en-tête de page.
   Elle partage la ligne avec le titre et les actions ; à l'étroit elle passe
   sur sa propre ligne et prend toute la largeur plutôt que de comprimer les
   boutons d'action. */
.admin-quick-search {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex: 1 1 260px;
  max-width: 420px;
  min-width: 0;
}
.admin-quick-search .form-input { flex: 1; min-width: 0; }

@media (max-width: 900px) {
  .admin-quick-search { flex-basis: 100%; max-width: none; order: 10; }
}
