/* ============================================================================
   Cabinet ORL — feuille de style applicative
   ----------------------------------------------------------------------------
   Bootstrap 5.1 fournit la base ; ce fichier porte l'identité visuelle.

   Auparavant, la couleur #0d6efd (le bleu primaire par défaut de Bootstrap)
   était répétée en dur sur le bandeau, les en-têtes de cartes, les en-têtes de
   tables et les onglets actifs. Deux conséquences : aucune identité propre, et
   une saturation telle que plus rien ne ressortait — quand tout est mis en
   avant, rien ne l'est.

   La palette ci-dessous est centralisée dans des variables CSS : changer une
   teinte se fait à un seul endroit.
   ========================================================================== */

/* ------------------------------------------------------------- Police ---- */
/* « Helvetica » a été la demande de départ, mais c'est une police
   propriétaire (Linotype/Monotype) : ni Google Fonts, ni fichier à
   redistribuer sans licence, alors que le cabinet doit rester fonctionnel
   sans accès Internet (même contrainte que Bootstrap et Bootstrap Icons,
   servis localement eux aussi).

   Inter la remplace : dessinée pour l'écran, dans le même registre neutre
   et sans empattement, avec une licence libre (OFL) qui autorise
   l'hébergement local. Servie en .woff2 — un seul format, largement
   suffisant pour les navigateurs que ce cabinet utilise, et plus léger que
   le .ttf qu'Open Sans occupait ici avant elle.

   Cinq graisses — 400, 400 italique, 500, 600, 700. Le 500 manquait :
   neuf règles le demandent (boutons, onglets du menu, termes des fiches) et
   le navigateur ne synthétise pas une graisse intermédiaire, il retombe sur
   la plus proche en dessous. Boutons et menu s'affichaient donc en 400,
   aussi maigres que le texte courant. Les fichiers sont ceux d'Inter 4
   publiés par l'auteur (rsms.me/inter) : le 400 et le 600 déjà présents y
   sont identiques octet pour octet. */

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Italic.woff2') format('woff2');
    font-weight: 400;
    font-style: italic;
    font-display: swap;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Inter';
    src: url('../fonts/Inter-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* Readex Pro, la police de la marque Kalma : celle du logo, reprise pour les
   titres (h1 à h3) et donc pour celui de l'écran de connexion. Elle couvre le
   latin et l'arabe dans un même dessin rond et ouvert, ce qui laisse « Kalma »
   et « كلمة » se répondre. Le texte courant reste en Inter : la chasse large
   de Readex coûterait de la place dans l'agenda, les tableaux et les
   formulaires, et Inter a les chiffres tabulaires des montants et des heures.

   Licence OFL, hébergée ici comme Inter, pour la même raison : le cabinet doit
   fonctionner sans Internet, et une connexion instable ne doit pas laisser les
   titres attendre un serveur de polices. Chaque fichier est la police
   variable entière (graisses 160 à 700) réduite à un seul alphabet ; le
   navigateur ne télécharge l'arabe que si une page en affiche. */
@font-face {
    font-family: 'Readex Pro';
    src: url('../fonts/ReadexPro-Latin.woff2') format('woff2');
    font-weight: 160 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
        U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
        U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Readex Pro';
    src: url('../fonts/ReadexPro-Arabic.woff2') format('woff2');
    font-weight: 160 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
        U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
        U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

/* IBM Plex Sans Arabic : l'arabe du texte courant. Inter n'a aucun glyphe
   arabe ; un nom de patient ou une adresse saisis en arabe tombaient donc sur
   la police du système — Segoe UI sous Windows, une autre sur un Mac ou un
   téléphone —, et le même dossier changeait d'allure d'un poste à l'autre.
   Plex a été préférée à Noto Sans Arabic, prévue par la décision de marque
   du 26 septembre, pour sa présence à côté de Readex Pro (choix du
   2026-09-29).

   Elle ne remplace Inter pour rien d'autre : l'« unicode-range », repris de
   Readex Pro, la réserve aux caractères arabes, et le navigateur ne
   télécharge un fichier que si la page en affiche. Quatre graisses, celles
   qu'Inter sert au latin, pour qu'un mot arabe dans un bouton ou un titre de
   tableau garde la graisse de son voisin latin. Fichiers du paquet officiel
   @ibm/plex-sans-arabic 1.1.0, licence OFL. */
@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
        U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
        U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
        U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
        U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
        U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
        U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

@font-face {
    font-family: 'IBM Plex Sans Arabic';
    src: url('../fonts/IBMPlexSansArabic-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891,
        U+0897-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41,
        U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

/* ─── La charte ───────────────────────────────────────────────────────────
   Troisième version de la charte, celle de la marque Kalma : la palette
   Casbah, retenue par le client le 26 septembre 2026. Le principe de la
   deuxième version ne change pas — le bleu reste la seule couleur qui
   signale « ceci est actif, ceci est cliquable », l'encre ne sert qu'au
   texte, et une carte, une barre de navigation, un en-tête restent blancs,
   un filet tenant lieu d'aplat. Ce sont les teintes qui changent.

     #1D5C96   le bleu Casbah (action)       #0F2E4A   l'encre de nuit
     #164A7A   le Casbah profond (survol)    #FBFAF7   le lin sable (fond de
     #D9E6F2   le voile (bleu clair)         page ; le sable #F7F4EE reste la
     #7A3C8F   la prune (« Arrivé »)         couleur de marque, hors app)
                                              #EDF3F9   la brume (fond doux)
                                              #B3261E   le grenat (danger)

   Le bleu Casbah est un bleu de Prusse éclairci, celui des volets d'Alger :
   deux fois moins saturé que le bleu #2563EB qu'il remplace, tiré de vingt
   degrés vers le pétrole. Il prolonge l'encre au lieu de la contredire, et
   dit le calme plutôt que le numérique. Les cartes restent blanches sur un
   fond de page couleur sable ; filets et fonds neutres passent au beige, et
   le gris atténué à l'ardoise de l'agence (#4A5560).

   Les neutres suivent toujours une seule échelle, du plus soutenu (texte) au
   plus clair (fond de page) — désormais chaude plutôt que gris ardoise : c'est
   elle qui évite qu'un filet de tableau et un fond de carte semblent sortir
   de deux palettes différentes.

   La palette a été calculée pour tenir le seuil AA de 4,5:1 partout où la
   précédente échouait. Blanc sur le bleu Casbah : 6,95:1 ; sur le Casbah
   profond : 9,15:1. Le bleu Casbah sur blanc, fond, brume et voile : 6,95,
   6,65, 6,21 et 5,47:1. Le gris atténué sur les mêmes fonds : 7,61, 7,29,
   6,81 et 6,00:1 — il ne descend plus sous 5,8:1, même sur un filet.

   La version précédente échouait sur les fonds clairs (#2563EB sur #DBEAFE,
   4,24:1 ; le gris #64748B sur #EFF6FF, 4,37:1) : un texte posé sur ces fonds
   y prenait le bleu foncé ou l'encre secondaire, y compris quand le fond
   n'apparaît qu'au survol — une ligne de tableau, une suggestion de la
   recherche, dont les conteneurs redéfinissent --orl-muted pour leurs
   enfants. Casbah n'en a plus besoin, mais la règle reste : elle ne coûte
   rien et garde une marge si une teinte bouge demain.

   Les liens prennent --orl-accent-text, un jeton à part : dans Casbah il vaut
   le bleu d'action lui-même (6,95:1 sur blanc), mais une palette dont le bleu
   des boutons ne tiendrait pas sur les fonds clairs pourra l'assombrir pour
   le seul texte sans toucher aux aplats. --orl-night, l'encre la plus
   profonde, est réservée au bandeau de marque et au logo en négatif.

   La prune (#7A3C8F) n'habille que la pastille « Arrivé » : répétée sur des
   dizaines de lignes de liste, elle pèserait autant que le bleu d'action et
   donnerait l'impression que tout, sur l'écran, est de la même couleur —
   l'avatar reste donc neutre, comme le reste d'une ligne de tableau (voir plus
   bas). La prune attend un usage isolé, qui n'apparaît qu'une fois par écran :
   c'est le seul statut qui appelle un geste dans la minute. Elle porte du
   texte blanc à 7,32:1 (nuance sombre, en bordure : 10,09:1), là où l'ancien
   indigo #585BE3 se confondait avec les liserés violets des praticiens sur la
   même ligne (revue de marque, 4.3.0).

   Les couleurs sémantiques plus bas — vert, ambre — ne sont pas de la charte
   et n'ont pas à s'y plier : elles portent un sens, pas une identité. Le
   rouge, lui, devient le grenat de l'agence : il garde le sens du danger,
   mais dans le registre de la marque, et il gagne en lisibilité (6,54:1 sous
   le blanc, 5,35:1 sur son fond rose). Le rouge et le bleu de l'audiogramme
   ne bougent pas : ce sont les couleurs conventionnelles de l'oreille droite
   et de l'oreille gauche.
   ───────────────────────────────────────────────────────────────────────── */
:root {
    /* Encre — le texte, les titres, ce qui n'est pas une action. La brume est
       le fond doux des survols et des éléments retenus. */
    --orl-brand: #0f2e4a;
    --orl-brand-soft: #edf3f9;

    /* L'encre la plus profonde. Sans emploi dans l'application elle-même —
       pas de bandeau de marque, pas de thème sombre ici — mais reprise comme
       fond des blocs de code et du bandeau du manuel d'aide, et dans les
       supports marketing où le logo se pose en négatif : blanc dessus,
       16,4:1. Gardé déclaré pour que ces surfaces, hors de cette feuille de
       style, restent alignées sur la même encre. */
    --orl-night: #0b2135;

    /* Action — le bleu Casbah, réservé à ce qui est cliquable. Le voile est
       son fond clair : pastille « Confirmé », créneau survolé. */
    --orl-accent: #1d5c96;
    --orl-accent-dark: #164a7a;
    --orl-accent-soft: #d9e6f2;

    /* Le bleu d'un texte de lien (règle « a » plus bas). Identique au bleu
       d'action dans Casbah, qui tient 5,47:1 jusque sur le voile ; distinct
       pour qu'une palette future puisse l'assombrir sans toucher aux aplats. */
    --orl-accent-text: #1d5c96;

    /* Identité — la prune, réservée à la pastille « Arrivé » (revue de marque,
       4.3.0) : c'est le seul statut qui appelle un geste dans la minute, et il
       doit rester le seul élément aussi vif de l'écran. La nuance sombre sert
       de bordure (10,09:1 sous le blanc) ; la nuance très claire n'a aucun
       emploi aujourd'hui, gardée si une pastille prune plus douce apparaît un
       jour. */
    --orl-accent2: #7a3c8f;
    --orl-accent2-dark: #5e2d6f;
    --orl-accent2-soft: #f3e9f5;

    /* Neutres, une seule échelle chaude, de l'encre au lin sable. --orl-page et
       --orl-line-soft ont été éclaircis (retour client, 4.3.0) : le sable
       #F7F4EE d'origine se lisait « trop sombre » huit heures par jour ; il
       reste la couleur de marque hors application (logo, planche, marketing). */
    --orl-ink: #0f2e4a;
    --orl-ink-2: #333f4b;
    --orl-muted: #4a5560;
    --orl-line: #e6e1d7;
    --orl-line-soft: #f4f1ec;
    /* Contour d'un champ ou d'une case : il dit « on peut écrire ici », il
       doit donc atteindre 3:1 (WCAG 1.4.11). --orl-line n'y faisait que 1,30:1
       et reste pour les filets de séparation, qui ne portent pas de sens.
       3,55:1 sur blanc, 3,23:1 sur sable (audit A11Y-07). */
    --orl-line-champ: #8f877a;
    --orl-surface: #ffffff;
    --orl-page: #fbfaf7;

    /* Sémantique — la couleur porte du sens, elle ne décore pas */
    --orl-success: #16a34a;
    --orl-success-soft: #dcfce7;
    --orl-warning: #f59e0b;
    --orl-warning-soft: #fef3c7;
    /* Le grenat de l'agence : un rouge qui garde le sens du danger, dans le
       registre de la marque. */
    --orl-danger: #b3261e;
    --orl-danger-soft: #fee2e2;
    /* L'encre de ces teintes quand elles écrivent du texte sur leur fond clair
       — les pastilles de statut. Les teintes pleines ci-dessus restaient sous
       le contraste AA en 12 px : 1,93:1 pour l'ambre, 3,00:1 pour le vert,
       3,95:1 pour l'ancien rouge (audit UX, A11Y-01). Assombries, elles passent
       à 6,4 et 6,5:1 sans changer de famille. Le grenat n'a pas besoin de
       nuance plus sombre : il tient déjà 5,35:1 sur son fond, et sert aux
       deux. */
    --orl-success-ink: #166534;
    --orl-warning-ink: #92400e;
    --orl-danger-ink: #b3261e;
    /* Le filet d'un bouton de danger : la teinte pleine ferait un cadre plus
       lourd que le bouton primaire, pour une action qu'on ne veut pas mettre
       en avant — seulement rendre reconnaissable. */
    --orl-danger-line: #fca5a5;

    /* Le filet du pense-bete accroche au rendez-vous. La teinte pleine servirait
       d'alerte, ce que la note n'est pas : elle se remarque sans reclamer. */
    --orl-warning-line: #fde68a;

    /* Le filet d'une alerte de succès (voir la section Bootstrap 5.1, en fin
       de fichier) : même logique que --orl-warning-line et --orl-danger-line
       ci-dessus. */
    --orl-success-line: #bbf7d0;

    /* Texte et liens sur un aplat de couleur plein (bouton, pastille active) :
       toujours blanc, seule teinte qui tienne le contraste sur les trois
       couleurs d'action de la charte. */
    --orl-on-brand: #ffffff;

    /* 10px passait inaperçu sur les grandes surfaces (une carte de tableau de
       bord, un panneau de liste) : le rayon reste identique en pixels, mais un
       petit bouton de 34px de haut en fait un dixième quand une carte de
       300px n'en fait qu'un centième — l'œil ne lit alors plus aucune courbe.
       --orl-radius-sm ne bouge pas : boutons et champs se lisaient déjà
       arrondis. */
    --orl-radius: 14px;
    --orl-radius-sm: 7px;
    --orl-shadow: 0 1px 2px rgba(15, 46, 74, .06), 0 4px 12px rgba(15, 46, 74, .06);
    /* Ce qui flotte au-dessus de la page (notifications, listes, bandeau de
       session, lien d'évitement) : --orl-shadow est trop faible pour s'en
       détacher. */
    --orl-shadow-flottant: 0 .5rem 1.25rem rgba(15, 46, 74, .16);

    /* ------------------------------------------------------- Couches -------
       Ce qui passe devant quoi, de bas en haut, pour les éléments qui flottent
       au-dessus de la page entière. Deux d'entre eux partageaient 1080 — les
       résultats de la recherche et le bandeau « session ouverte sur un autre
       poste » — et c'était alors l'ordre du HTML qui décidait : le bandeau
       pouvait disparaître sous une liste de suggestions. Il passe désormais
       devant, et seules les notifications le couvrent.

       Les listes restent à 1080, au-dessus de la barre de navigation collante
       et des fenêtres modales de Bootstrap (1020 à 1055), comme avant.

       Les petites valeurs (1, 2, 4) écrites en dur plus bas ne sont pas des
       couches : elles ordonnent deux éléments voisins dans un même composant
       — un coin de tableau, un bouton dans un groupe — et n'ont de sens que
       là. */
    --orl-z-barre-collante: 5;
    --orl-z-liste-deroulante: 1080;
    --orl-z-bandeau: 1085;
    --orl-z-notifications: 1090;
    --orl-z-aller-contenu: 2000;

    /* ------------------------------------------------------- Largeurs ------
       Trois largeurs, et trois seulement. Elles vivaient jusqu'ici écrites en
       dur — 46rem, 76rem, 97.5rem, plus un calc(97.5rem - 7rem) recopié dans
       la barre de navigation — sous sept noms de classe dont plusieurs
       disaient la même valeur (.orl-form et .orl-rdv-form, .orl-form-large et
       .orl-param-form). Deux écrans ont fini par ne plus s'aligner sur ce
       qu'ils surmontaient, et c'est exactement ce que l'échelle typo plus bas
       annonce : une valeur écrite en dur est un écart, pas un réglage fin.

       Les noms de classe hérités restent, en alias : les renommer aurait
       touché quarante-trois vues pour aucun gain visible. Ce qui change, c'est
       qu'ils lisent tous ici, et ne peuvent plus diverger. */

    /* Un formulaire qu'on remplit : au-delà, l'œil perd la ligne entre
       l'étiquette et son champ. */
    --orl-largeur-saisie: 46rem;

    /* Une page qui pose des blocs côte à côte — consultation, paramètres,
       facture. Assez large pour deux colonnes, assez étroite pour rester
       lisible. */
    --orl-largeur-contenu: 76rem;

    /* La page entière : au-delà de 1560px, l'œil peine à suivre une ligne de
       tableau d'un bord à l'autre. */
    --orl-largeur-page: 97.5rem;

    /* La respiration de chaque côté de la page. La barre de navigation s'en
       sert aussi : elle doit s'arrêter là où s'arrête le contenu. */
    --orl-marge-page: 3.5rem;

    /* ----------------------------------------------------- Échelle typo ----
       Vingt et une tailles distinctes cohabitaient ici, dont sept entre .8rem
       et .9rem — .78, .8, .8125, .82, .85, .86, .875. Personne ne distingue un
       demi-pixel, mais l'œil voit très bien que deux tableaux voisins ne sont
       pas réglés pareil : c'est ce qui donne à une application l'air d'avoir
       été assemblée par morceaux.

       Neuf échelons, écartés d'assez pour que la différence porte du sens.
       Toute nouvelle règle prend un de ces jetons ; une valeur écrite en dur
       est un écart, pas un réglage fin. */
    /* Plancher en px sur les trois plus petits : sous 768 px, la base passe à
       14 px et les rem les faisaient tomber à 9,6, 10,5 et 11,4 px, sous le
       seuil de lecture. Au-dessus, max() ne change rien. */
    --orl-fs-2xs: max(.6875rem, 11px);  /* 11px — mentions légales, exposants */
    --orl-fs-xs: max(.75rem, 12px);     /* 12px — pastilles, légendes */
    --orl-fs-sm: max(.8125rem, 12px);   /* 13px — aide, cellules denses */
    --orl-fs-md: .875rem;    /* 14px — tableaux, texte secondaire */
    --orl-fs-base: 1rem;     /* 16px — corps de page */
    --orl-fs-lg: 1.125rem;   /* 18px — sous-titres */
    --orl-fs-xl: 1.25rem;    /* 20px — titres de bloc */
    --orl-fs-2xl: 1.5rem;    /* 24px — titres de page */
    --orl-fs-3xl: 1.75rem;   /* 28px — titre principal */
    /* Hors échelle, un seul usage : le nom du cabinet sur l'écran de
       connexion, à partir de 992 px (30 à 38 px selon la largeur). */
    --orl-fs-affichage: clamp(1.875rem, 2.6vw, 2.375rem);
}

/* 3,5rem de chaque côté, c'est l'air d'un écran de bureau. Sur une tablette
   ou un téléphone, la même marge prenait un quart de la largeur : les
   tableaux défilaient de côté pendant que les bords restaient vides. */
@media (max-width: 991.98px) {
    :root { --orl-marge-page: 1.5rem; }
}

@media (max-width: 575.98px) {
    :root { --orl-marge-page: 1rem; }
}

/* ---------------------------------------------------------------- Base ---- */

/* Reserve la place de la barre de defilement, qu'elle soit affichee ou non.
   Sans cela, la largeur utile perd 15 a 17 pixels des que la page depasse
   l'ecran : une page vide tient sur une ligne, la meme page remplie fait
   passer a la ligne le dernier groupe d'une barre de filtres (les raccourcis
   de periode des Statistiques), et tout l'ecran saute d'un cote a l'autre en
   passant d'une page a l'autre. La gouttiere montre le fond de body, que le
   canevas reprend puisque html n'a pas de fond propre. */
html { scrollbar-gutter: stable; }

/* Colonne pleine hauteur : l'en-tete, le contenu qui s'etire, puis le pied de
   page. Il reste ainsi collé en bas des pages courtes sans etre sorti du flux
   — ce que faisait le montage d'origine, au prix d'un pied de page pose
   par-dessus le contenu, qui interceptait les clics des boutons proches. */
body {
    background-color: var(--orl-page);
    color: var(--orl-ink);
    font-family: 'Inter', 'IBM Plex Sans Arabic', 'Segoe UI', Roboto, -apple-system, Arial, sans-serif;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Pousse le pied de page vers le bas quand la page est courte, et laisse
   toujours de l'air avant lui : le dernier element d'un formulaire — un bouton,
   un lien de retour — venait sinon toucher le filet du pied de page. */
.orl-contenu {
    flex: 1 0 auto;
    padding-bottom: 2.5rem;
}


h1, h2, h3, h4, h5 {
    color: var(--orl-ink);
    text-wrap: balance;
    font-weight: 600;
    letter-spacing: -.01em;
}

/* Les trois premiers niveaux de titre prennent la police de la marque (voir
   plus haut) ; h4 et h5, qui titrent un bloc de formulaire ou une carte, se
   lisent avec le texte et restent en Inter. Inter reste aussi en second :
   c'est elle qui écrit un caractère que Readex n'aurait pas. */
h1, h2, h3 {
    font-family: 'Readex Pro', 'Inter', 'IBM Plex Sans Arabic', 'Segoe UI', Roboto, -apple-system, Arial, sans-serif;
}

/* Un titre de section en petite taille (.h6) garde la graisse d'un titre :
   laissé au 500 de Bootstrap, il paraissait plus maigre que les libellés des
   champs qu'il annonce. */
h6, .h5, .h6 { font-weight: 600; }

/* Le titre de page est le seul élément appuyé de l'écran : Readex Pro
   demi-gras, légèrement resserré — à 24 px,
   l'approche d'origine laisse les lettres flotter. Tout le reste de la page
   reste calme, c'est lui qui dit où l'on est. La classe de taille (.h3, .h4)
   garde la taille ; elle ne décide plus de la graisse.

   600 et non plus le 700 qu'avait Inter : Readex a le trait plus épais à
   graisse égale, et son gras, large comme il est, pesait sur un titre de
   formulaire autant qu'un bandeau. Resserrée de -.015em plutôt que -.022,
   une chasse dessinée large garde ses contre-formes ouvertes. */
h1, h1.h2, h1.h3, h1.h4 {
    font-weight: 600;
    letter-spacing: -.015em;
}

/* Une seule taille de titre de page, celle de la charte (--orl-fs-2xl, 24 px).
   Chaque écran la choisissait par sa classe Bootstrap : .h3 donnait 28 px
   (Patients, Statistiques, Abonnement), .h4 24 px (Consultations, Stock),
   .orl-account-title 20 px (Mon compte, Paramètres), un h1 nu jusqu'à 40 px.
   D'un écran à l'autre, le titre changeait de taille sans raison.
   La classe de taille garde sa marge (mb-*) ; elle ne décide plus de la
   taille. Les titres dessinés à part (.orl-consult-quand,
   .orl-connexion-titre) gardent la leur : leur classe l'emporte sur h1. */
h1, h1.h2, h1.h3, h1.h4 {
    font-size: var(--orl-fs-2xl);
}

/* Les chiffres qu'on compare d'une ligne à l'autre — heures, téléphones,
   âges, montants — s'alignent en colonne. Inter porte des chiffres à chasse
   fixe : inutile de changer de police, et la chasse fixe d'une police de
   code donnait à une heure l'air d'un extrait de programme. */
.orl-chiffres,
.table > tbody > tr > td {
    font-variant-numeric: tabular-nums;
}

/* Un créneau ou un numéro se lit d'un bloc : coupé en « 08:30 / - / 08:50 »
   sur trois lignes, il ne se lit plus du tout. */
.table td.orl-chiffres { white-space: nowrap; }

/* Une rubrique vide se lit comme vide, pas comme une ligne qui manque : sans
   tiret, le libellé suivant remontait contre elle et deux rubriques
   semblaient n'en faire qu'une. */
/* Dans une fiche, c'est la valeur qu'on cherche des yeux, pas le libellé :
   Bootstrap mettait le libellé en gras et la valeur en maigre, la fiche se
   lisait à l'envers. Le libellé passe au gris, la valeur garde l'encre. */
dl.row > dt {
    font-weight: 500;
    color: var(--orl-muted);
}

dl.row > dd:empty::before {
    content: "—";
    color: var(--orl-muted);
}

/* Le jeton propre aux liens, et non plus --orl-accent-dark : ce dernier est la
   nuance du survol des boutons pleins, et une palette qui l'assombrirait pour
   un aplat n'a pas à assombrir tous les liens avec (voir la charte). */
a {
    color: var(--orl-accent-text);
    text-underline-offset: 2px;
}

/* Casbah profond, et non l'encre : l'encre est la couleur de « ce qui n'est
   pas une action », et un lien qui y virait au survol avait l'air de se
   désactiver (retour client, 4.3.0). */
a:hover { color: var(--orl-accent-dark); }

/* Bootstrap colore <code> en rose par défaut — une couleur sémantique que la
   charte n'a jamais eue, qui ressortait sur les rares pages citant un nom de
   fichier (SAUVEGARDE.md, .env.example…) sans qu'aucune autre page n'en
   affiche l'équivalent. Un fond neutre, comme un extrait de code plutôt
   qu'une alerte. */
code {
    color: var(--orl-ink-2);
    background-color: var(--orl-line-soft);
    padding: .1rem .35rem;
    border-radius: var(--orl-radius-sm);
    font-size: .875em;
}

/* La navbar : même carte que le reste de l'application — coin arrondi
   --orl-radius, ombre --orl-shadow — et non une pilule entièrement ronde,
   qui aurait détonné à côté des cartes et panneaux d'action de chaque
   section. */
/* Retrait intérieur de 21 px, celui du texte d'une carte (20 px de .card-body
   et son filet de 1 px). Il cumulait .75rem ici et autant sur le
   .container-fluid de Bootstrap : le symbole Kalma tombait 24 px à
   l'intérieur, les titres de page au bord, et l'on croyait les titres
   décalés vers la gauche (retour mainteneur, 28/09/2026). Désormais, les
   bords de la barre, des titres et des cartes s'alignent, et le symbole
   s'aligne sur le texte des cartes. */
.orl-navbar-pilule {
    background-color: var(--orl-surface);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: .35rem 21px;
    /* Même plafond que .orl-page-large : la barre suit la largeur du contenu
       qu'elle surmonte, elle ne fixe pas la sienne à part. Les deux lisent
       désormais les mêmes jetons — auparavant la valeur était recopiée ici, et
       corriger l'une sans l'autre décalait la barre du contenu. */
    max-width: calc(var(--orl-largeur-page) - 2 * var(--orl-marge-page));
    margin: 14px auto;
    width: calc(100% - 2 * var(--orl-marge-page));
}

.orl-navbar-pilule > .container-fluid {
    padding-left: 0;
    padding-right: 0;
}

/* white-space + flex-shrink: 0 : sans eux, un onglet dont la largeur manque
   ne s'efface pas en entier, il casse entre l'icône et le libellé — l'icône
   seule sur une ligne, le mot en dessous. C'est la recherche patient qui doit
   céder de la place en premier (elle est faite pour se rétrécir), jamais un
   onglet. */
.navbar .nav-link {
    position: relative;
    display: flex;
    align-items: center;
    gap: .4rem;
    font-weight: 500;
    color: var(--orl-ink-2) !important;
    border-radius: var(--orl-radius-sm);
    padding: .45rem .75rem !important;
    white-space: nowrap;
}

.navbar-nav .nav-item { flex-shrink: 0; }

/* Le bouton du menu replié ne doit jamais céder sa place à la marque : à 390 px,
   rien ne doit pouvoir le repousser hors champ. */
.navbar-toggler { flex-shrink: 0; }

/* Taille Bootstrap (56 × 40 px) : le bouton pesait plus que le symbole
   Kalma d'en face et que tout le reste de la barre. Pas moins haut qu'un
   .btn normal (33,8 px sur la base de 14 px) : c'est le plancher de la charte
   pour les zones cliquables (CHARTE-GRAPHIQUE.md, § 6, point 3). */
.orl-navbar-pilule .navbar-toggler {
    padding: .3rem .5rem;
    min-height: 2.5rem;
    font-size: 1.1rem;
    border-color: var(--orl-line);
}

/* Le symbole Kalma, tout à gauche de la barre : la seule marque visible sur
   l'écran de travail. Il mène à l'accueil, comme l'onglet voisin, et reste
   sans le nom du cabinet, que le cabinet connaît et
   qui figure déjà dans le titre de l'onglet et le pied de page (retour
   client, 27/09/2026). Une marge à droite le détache des onglets. */
.orl-navbar-marque {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    margin-right: .75rem;
}

.orl-navbar-marque img {
    display: block;
    width: 22px;
    height: 22px;
}

/* De l'air entre les onglets, la recherche et le compte : serrés contre
   l'arrondi de la pilule, ils donnaient une barre dense plutôt qu'aérée. */
.navbar-nav.me-auto { gap: .15rem; }
.orl-navbar-pilule .navbar-collapse > .navbar-nav:last-child { margin-left: .5rem; }

.navbar .nav-link:hover {
    color: var(--orl-accent-dark) !important;
}

/* Onglet correspondant à la page courante : le fond plein a cédé la place au
   trait sous le libellé — la pilule est déjà blanche, un aplat de couleur à
   l'intérieur aurait fait deux formes arrondies imbriquées. */
.navbar .nav-link.is-current {
    color: var(--orl-accent) !important;
    font-weight: 600;
}

.navbar .nav-link.is-current::after {
    content: "";
    position: absolute;
    left: 1rem;
    right: 1rem;
    bottom: -.3rem;
    height: 2px;
    border-radius: 2px;
    background-color: var(--orl-accent);
}

/* Menu replié (tablette, téléphone) : les onglets s'empilent et chaque lien
   prend toute la largeur. Le trait sous « Patients » devenait alors un filet
   d'un bord à l'autre, lu comme un séparateur entre deux entrées. En colonne,
   la page courante se signale par un trait vertical à gauche — celui du menu
   des Paramètres (.orl-account-nav), qui est déjà une liste verticale. */
@media (max-width: 991.98px) {
    .navbar .nav-link.is-current::after {
        left: 0;
        right: auto;
        top: .45rem;
        bottom: .45rem;
        width: 2px;
        height: auto;
    }

    /* La marge qui détache le compte de la recherche sur une ligne le
       décalait, empilé, d'un demi-rem par rapport aux onglets au-dessus. */
    .orl-navbar-pilule .navbar-collapse > .navbar-nav:last-child { margin-left: 0; }
}

/* Après un clic, Bootstrap laissait un épais cadre gris autour du bouton du
   menu, comme s'il restait enfoncé. Le focus clavier garde son anneau
   (button:focus-visible, plus bas) ; seul le focus laissé par la souris ou
   le doigt disparaît. */
.navbar-toggler:focus:not(:focus-visible) { box-shadow: none; }

.navbar .nav-link i { opacity: .8; font-size: 1.05em; }

/* L'icône suit le texte quand l'entrée est active ou survolée : atténuée au
   repos, elle reprend sa pleine couleur en même temps que le libellé. */
.navbar .nav-link:hover i,
.navbar .nav-link.is-current i { opacity: 1; }

/* Agenda : un lien qui mène au planning, accolé à une flèche qui déplie le
   choix entre RDV et sans rendez-vous. Deux liens côte à côte plutôt qu'un
   seul dont le clic ouvrirait le sous-menu — cliquer « Agenda » doit ouvrir
   le planning, pas un menu qu'il faudrait rouvrir pour l'atteindre. */
/* flex-wrap + flex-basis : dans le menu replié, le sous-menu n'est plus
   flottant mais dans le flux ; resté sur la ligne du lien et de la flèche,
   il s'ouvrait à côté d'« Agenda », tassé dans la même rangée. Il passe
   désormais dessous, comme toute liste verticale. */
.orl-nav-agenda { display: flex; flex-wrap: wrap; align-items: center; gap: 0; }
.orl-nav-agenda > .dropdown-menu { flex-basis: 100%; }
.navbar .nav-link.orl-nav-agenda-fleche {
    padding: .45rem .5rem !important;
    margin-left: -.3rem;
    /* Cible de 24 px au moins (WCAG 2.5.8) : la flèche seule en faisait 18. */
    display: inline-flex;
    align-items: center;
    min-height: 1.5rem;
    min-width: 1.5rem;
}

/* Une légende masquée (visually-hidden) est en position absolue : sans
   ancêtre positionné, elle se place par rapport à la page et non au tableau
   qui défile, et fait déborder l'écran entier sur téléphone (Utilisateurs). */
fieldset:has(> legend.visually-hidden),
th:has(> .visually-hidden) { position: relative; }

/* Le sous-menu s'affiche au survol : demande explicite, pour ne pas imposer
   un clic juste pour voir le choix entre RDV et sans rendez-vous. La fleche
   garde son data-bs-toggle (voir _Layout.cshtml) pour le tactile, ou le
   clavier, ou tout appareil sans survol — la regle ci-dessous ne fait
   qu'ajouter l'affichage au survol, elle ne retire rien.

   Popper ne calcule la position du menu que lorsque Bootstrap l'ouvre par
   clic : ouvert seulement par ce survol-ci, sans que le JS s'en mêle, il
   lui faut sa propre position — sinon il retombe à l'endroit par défaut
   d'un élément absolu dans une barre flex, tout en haut de la page.

   Colle contre l'onglet (pas de marge) : un intervalle, meme petit, sortait
   du survol pile entre les deux — la souris quittait « Agenda » avant
   d'atteindre le menu, qui se refermait avant le clic.

   Pas de « :focus-within » : le menu s'ouvrait dès que le Tab passait sur
   « Agenda », restait ouvert malgré Échap tant que le focus était dedans, et
   annonçait aria-expanded="false" en étant affiché. Au clavier, c'est la
   flèche (Entrée, ↓) qui l'ouvre, par Bootstrap, avec Échap et l'état exact.

   Réservé aux appareils qui survolent vraiment : sur tablette, le toucher
   laisse un :hover collé après le tap, et le menu restait ouvert par-dessus
   la page. Là, seule la flèche l'ouvre. */
@media (hover: hover) and (pointer: fine) {
    .orl-nav-agenda:hover > .dropdown-menu {
        display: block;
        position: absolute;
        top: 100%;
        left: 0;
        margin-top: 0;
    }
}

/* Meme couleur de survol que le reste de l'application (tableaux, recherche
   patient, menu du compte) : le gris par defaut de Bootstrap pour
   .dropdown-item détonnait, seul endroit du menu à ne pas réagir en bleu. */
.orl-nav-agenda .dropdown-item:hover,
.orl-nav-agenda .dropdown-item:focus {
    background-color: var(--orl-brand-soft);
    color: var(--orl-accent-dark);
}

/* La page courante se signale par la couleur, jamais par un aplat — c'est
   ainsi que .navbar .nav-link.is-current le fait deja pour les onglets :
   le sous-menu suit la meme regle plutot que d'inventer un second langage
   visuel pour dire la meme chose. */
.orl-nav-agenda .dropdown-item.active {
    background-color: transparent;
    color: var(--orl-accent-dark);
    font-weight: 600;
}

/* --------------------------------------------------------------- Cartes ---- */

.card {
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    /* Sans ceci, le fond plein de .card-header et .card-body déborde tout
       droit dans les angles arrondis de .card : les coins semblent carrés
       alors que la bordure, elle, est bien arrondie. */
    overflow: hidden;
}

.card-header {
    background-color: var(--orl-surface);
    color: var(--orl-ink);
    font-weight: 600;
    font-size: var(--orl-fs-base);
    border-bottom: 1px solid var(--orl-line);
    border-top-left-radius: calc(var(--orl-radius) - 1px);
    border-top-right-radius: calc(var(--orl-radius) - 1px);
}

/* --orl-accent-text (500) et non --orl-accent-dark (600, la graisse du titre
   de carte) : les deux couleurs se confondaient à côté d'un titre tout aussi
   sombre et tout aussi gras — seul le soulignement les distinguait (revue de
   marque, 4.3.0). Le survol reprend --orl-accent-dark, qu'une règle générique
   plus bas ne pouvait plus fournir à spécificité égale. */
.card-header a { color: var(--orl-accent-text); font-weight: 500; }
.card-header a:hover { color: var(--orl-accent-dark); text-decoration-thickness: 2px; }

.card-body {
    background-color: var(--orl-surface);
    padding: 20px;
}

/* Le pied de carte n'avait aucune règle : il gardait le gris translucide de
   Bootstrap (rgba(0,0,0,.03)) et son filet gris, alors que l'en-tête et le
   corps sont sur la surface de la charte. Une carte à pied se lisait en trois
   tons ; la seule vue qui en pose un (les consultations précédentes) contournait
   le défaut par bg-white. Même surface, et le filet beige de l'en-tête, en haut
   cette fois. */
.card-footer {
    background-color: var(--orl-surface);
    border-top: 1px solid var(--orl-line);
}

/* .section-block a été retiré : troisième recette pour le même objet — surface,
   filet, rayon, ombre — après .card et .orl-rdv-bloc, et plus aucune vue ne
   l'employait. Trois noms pour un seul bloc, c'est trois façons de le dessiner
   qui finissent par diverger. */

/* Texte saisi au clavier, restitué avec ses retours à la ligne : antécédents,
   traitement en cours, notes de consultation. Sans cela les alinéas du
   praticien sont avalés et trois lignes deviennent un pavé. */
.orl-texte-libre,
.orl-consult-notes { white-space: pre-line; }

/* ---------------------------------------------------- Dossier patient ---- */
/* Le dossier suit la structure des Paramètres : une barre de navigation — ici
   les onglets — puis un panneau qui porte le contenu. La carte qui enveloppait
   l'ensemble a disparu : elle ajoutait un cadre autour d'un cadre, et son
   en-tête à texte d'encre était le seul de l'application, tout le reste
   annonçant ses blocs par une légende discrète.

   La surface est portée par le panneau et non par le contenu : les huit
   onglets n'ont pas la même forme — une fiche, des listes, un journal, des
   sous-onglets — et leur demander à chacun de se dessiner un cadre aurait
   redonné huit dessins différents. */
.orl-dossier .tab-pane {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    padding: 1.25rem;
}

/* Section à l'intérieur d'un panneau : un titre et du contenu, sans cadre
   propre. Elle emprunte sa légende au bloc ordinaire — même graisse, mêmes
   capitales, même gris — pour qu'un titre de section se lise partout de la
   même façon, qu'il y ait un cadre autour ou non. */
.orl-section {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0;
}

/* Un filet sépare deux sections d'un même panneau. Sans lui, l'état civil et
   le bloc médical se touchent et se lisent comme une seule liste. */
.orl-section + .orl-section {
    border-top: 1px solid var(--orl-line);
    margin-top: 1.5rem;
    padding-top: 1.25rem;
}

/* -------------------------------------------------------------- Boutons ---- */
/* Bootstrap 5.1 code les couleurs des boutons en dur : on les redéfinit
   explicitement plutôt que via --bs-primary, qui n'agit pas ici. */

.btn {
    border-radius: var(--orl-radius-sm);
    padding: .4rem .85rem;
    font-weight: 500;
}

.btn-primary {
    background-color: var(--orl-accent);
    border-color: var(--orl-accent);
}

.btn-primary:hover,
.btn-primary:focus,
.btn-primary:active {
    background-color: var(--orl-accent-dark) !important;
    border-color: var(--orl-accent-dark) !important;
}

.btn-outline-primary {
    color: var(--orl-accent-dark);
    border-color: var(--orl-accent);
}

.btn-outline-primary:hover,
.btn-outline-primary:active {
    background-color: var(--orl-accent) !important;
    border-color: var(--orl-accent) !important;
    color: var(--orl-on-brand) !important;
}

/* --orl-line est taillé pour un filet de carte ou de tableau, posé sur toute
   sa longueur ; sur le contour d'un petit bouton, entre deux boutons pleins
   et colorés (primaire, danger), il devenait quasi invisible — au point que
   « Modifier » disparaissait d'une rangée d'actions. --orl-muted est le gris
   le plus clair qui reste un contour net sur fond blanc. */
.btn-outline-secondary {
    color: var(--orl-ink-2);
    border-color: var(--orl-muted);
}

.btn-outline-secondary:hover {
    background-color: var(--orl-brand-soft);
    border-color: var(--orl-muted);
    color: var(--orl-accent-dark);
}

/* Le bouton plein des confirmations de suppression : Bootstrap le peint en dur
   dans son rouge #DC3545. Laissé tel quel, il aurait fait à côté du grenat du
   bouton à contour deux rouges pour une même action. Le survol assombrit
   l'aplat, comme pour une pastille cliquable, sans ajouter de nuance à la
   charte. */
.btn-danger {
    background-color: var(--orl-danger);
    border-color: var(--orl-danger);
}

.btn-danger:hover,
.btn-danger:focus,
.btn-danger:active {
    background-color: var(--orl-danger);
    border-color: var(--orl-danger);
    filter: brightness(.88);
}

.btn-outline-danger { color: var(--orl-danger); border-color: var(--orl-danger-line); }
.btn-outline-danger:hover { background-color: var(--orl-danger); border-color: var(--orl-danger); }

/* Dans une ligne de tableau, les actions secondaires — modifier, supprimer —
   ne portent que leur icône et leur couleur ; le cadre n'apparaît qu'au
   survol de la ligne ou au clavier. Répété sur cinquante lignes, un cadre par
   bouton dessinait une grille de boîtes plus visible que les noms des
   patients. L'action principale (« Dossier », bouton bleu) garde son cadre :
   c'est elle qu'on cherche. */
.table > tbody > tr > td .btn-sm.btn-outline-secondary,
.table > tbody > tr > td .btn-sm.btn-outline-danger {
    border-color: transparent;
    background-color: transparent;
}

.table > tbody > tr:hover > td .btn-sm.btn-outline-secondary,
.table > tbody > tr > td .btn-sm.btn-outline-secondary:focus-visible {
    border-color: var(--orl-muted);
}

.table > tbody > tr:hover > td .btn-sm.btn-outline-danger,
.table > tbody > tr > td .btn-sm.btn-outline-danger:focus-visible {
    border-color: var(--orl-danger-line);
}

.table > tbody > tr > td .btn-sm.btn-outline-danger:hover {
    background-color: var(--orl-danger);
    border-color: var(--orl-danger);
}

.btn-link { color: var(--orl-accent-dark); }

/* Bootstrap 5.1 code le survol de .btn-link en dur (#0a58ca), à une
   spécificité qui bat « a:hover » : un lien-bouton restait le seul à ne pas
   suivre le Casbah au survol. */
.btn-link:hover,
.btn-link:focus { color: var(--orl-accent-dark); }

/* « button » : les onglets du dossier, l'icône « Colonnes », le menu burger
   sont des <button> sans .btn — ils tombaient sur l'anneau par défaut du
   navigateur, d'une autre couleur que partout ailleurs. */
.btn:focus-visible,
button:focus-visible,
.form-control:focus-visible,
a:focus-visible {
    outline: 2px solid var(--orl-accent);
    outline-offset: 2px;
    box-shadow: none;
}

/* Bootstrap pose son halo sur :focus, donc aussi au clic de souris : quatre
   pixels s'ajoutaient à l'aplat du bouton enfoncé, pour signaler un focus que
   celui qui vient de cliquer connaît déjà. Au clavier, c'est le contour
   juste au-dessus qui montre le focus ; le halo n'y ajoutait qu'un second
   cadre, gris sur un bouton choisi ou enfoncé. Le !important couvre toutes
   les variantes de Bootstrap, dont certaines (« .active:focus »,
   « .dropdown-toggle.show:focus ») sont plus spécifiques que ce sélecteur. */
.btn:focus { box-shadow: none !important; }

/* -------------------------------------------------------------- Tables ---- */

.table {
    border-radius: var(--orl-radius);
    overflow: hidden;
    color: var(--orl-ink);
    /* Bootstrap 5.1 écrit ses séparateurs en #dee2e6, un gris froid (teinte
       256°) jamais repris par la charte, à ΔE 7,4 du filet beige. */
    border-color: var(--orl-line);
}

/* Dans une carte, c'est la carte qui arrondit (overflow: hidden) : son titre
   ouvre le cadre, le tableau n'en est que la suite. Arrondi à son tour, il
   rognait les deux coins hauts de son en-tête, qui semblait commencer une
   seconde carte, en retrait, sous le titre (retour client, 27/09/2026). */
.card .table {
    border-radius: 0;
}

/* Le filet sous l'en-tête restait #333f4b (currentColor) : Bootstrap 5.1 pose
   cette règle à une spécificité (0,3,0) supérieure à border-bottom ci-dessous
   (0,1,2), et l'emportait toujours, laissant la ligne la plus appuyée du
   tableau juste sous les libellés de colonnes. */
.table > :not(:last-child) > :last-child > * {
    border-bottom-color: var(--orl-line);
}

/* En-têtes clairs à texte sombre. L'ancienne règle imposait du blanc sur fond
   bleu vif pour toutes les tables ; combinée à une table à fond clair, elle
   rendait les libellés de colonnes illisibles (blanc sur gris). */
.table thead th {
    background-color: var(--orl-line-soft);
    color: var(--orl-ink-2);
    font-weight: 600;
    font-size: var(--orl-fs-sm);
    border-bottom: 1px solid var(--orl-line);
    white-space: nowrap;
}

/* Le corps du tableau était laissé aux réglages de Bootstrap, c'est-à-dire à la
   taille du texte courant — 16 px. Un en-tête de 13 px surmontant des cellules
   de 16 px se lit à l'envers : la colonne pèse plus lourd que sa donnée. Et
   selon que la vue avait pensé à `table-sm` ou non, deux tableaux voisins
   n'avaient ni la même densité ni la même hauteur de ligne.

   Une seule densité pour toute l'application, écrite ici et nulle part
   ailleurs. `table-sm` reste sans effet visible, ce qui est voulu : la vue n'a
   plus à choisir. */
.table > tbody > tr > td,
.table > tbody > tr > th {
    font-size: var(--orl-fs-md);
    padding: .55rem .75rem;
}

.table > thead > tr > th { padding: .55rem .75rem; }

/* Le gris atténué ne tient pas sur le bleu clair du survol (4,37:1) : les
   durées, les factures annulées et autres mentions discrètes de la ligne
   passent à l'encre secondaire le temps du survol (voir la charte). */
.table tbody tr:hover {
    background-color: var(--orl-brand-soft);
    --orl-muted: var(--orl-ink-2);
}

/* Bootstrap 5.1 peint 7,5 % de noir par-dessus la brume (--bs-table-hover-bg,
   en box-shadow inset) et force le texte à #212529 : la ligne survolée
   devenait un gris froid aussi sombre que les filets — le « survol sale »
   relevé par le client. La brume seule, posée juste au-dessus, suffit. */
.table-hover > tbody > tr:hover {
    --bs-table-accent-bg: transparent;
    color: var(--orl-ink);
}

/* Le nom d'une ligne de tableau n'est pas une invite à cliquer, c'est la ligne
   entière qui l'est (voir .is-clickable) : un lien bleu répété sur chaque
   ligne d'une liste de plusieurs dizaines de patients pèserait plus que le
   texte lui-même, et rendrait le bleu muet le jour où il sert vraiment à
   signaler une action. Le survol suffit à dire qu'une cellule mène quelque
   part ; les boutons de la colonne « Actions » restent seuls en couleur. */
.table td a:not(.btn) { color: var(--orl-ink); }

.table td a:not(.btn):hover {
    color: var(--orl-accent-dark);
    text-decoration: underline;
}

/* Le curseur « main » était appliqué à toutes les lignes, y compris celles qui
   ne sont pas cliquables : il annonçait une interaction inexistante. */
.table tbody tr.is-clickable { cursor: pointer; }

/* Colonnes au choix (DEM-016) : le bouton se pose au-dessus du tableau, à
   droite, discret — on le règle une fois, on ne le cherche pas tous les jours. */
.orl-colonnes-barre { display: flex; justify-content: flex-end; margin-bottom: .5rem; }
.orl-colonnes-menu { min-width: 14rem; }
.orl-colonnes-titre { padding: .25rem 1rem .4rem; font-size: var(--orl-fs-sm); color: var(--orl-muted); }
.orl-colonnes-choix { display: flex; align-items: center; gap: .5rem; cursor: pointer; }
.orl-colonnes-choix .form-check-input { margin: 0; }

/* Ancrée dans un coin déjà là (l'en-tête « Actions », une barre d'outils) :
   une icône nue, pas un bouton — voir data-orl-colonnes-cible. Le z-index
   n'est pas cosmétique : sans lui, les boutons « Imprimer » des lignes du
   corps du tableau se peignent par-dessus le menu ouvert, position:relative
   seul ne suffisant pas à sortir l'en-tête de l'ordre d'empilement des
   lignes qui le suivent. */
.orl-colonnes-coin { position: relative; z-index: 2; }
.orl-colonnes-coin > .dropdown { position: absolute; top: 50%; right: .5rem; transform: translateY(-50%); }
.orl-colonnes-icone {
    background: none; border: 0; padding: .15rem .3rem; line-height: 1;
    color: var(--orl-muted); border-radius: .25rem;
    min-height: 1.5rem; /* cible de 24 px (WCAG 2.5.8) : 18 px sans cela */
}
.orl-colonnes-icone:hover, .orl-colonnes-icone:focus { color: var(--orl-brand); background-color: var(--orl-brand-soft); }

/* Même geste pour un élément de liste, comme les consultations du jour de
   l'accueil (DEM-012) : le survol dit que toute la ligne mène au dossier. */
.list-group-item.is-clickable { cursor: pointer; }
.list-group-item.is-clickable:hover {
    background-color: var(--orl-brand-soft);
    --orl-muted: var(--orl-ink-2);
}

/* Les tableaux qui portent leur propre classe sont des grilles, pas des listes
   — saisie de l'audiogramme, différentiel de l'historique. Ils gardent leur
   densité propre, qui répond à une contrainte de lecture et non à un oubli. */
.orl-audio-tableau > tbody > tr > td,
.orl-journal-diff > tbody > tr > td {
    font-size: var(--orl-fs-sm);
    padding: .3rem .45rem;
}

/* Le caractère du symbole, devant le bouton qui l'arme et devant la ligne de
   saisie qui le porte. En chasse fixe et un peu plus gros que le texte : c'est
   la forme qu'on cherche sur la courbe, pas le mot qui la nomme. */
.orl-audio-symbole {
    font-family: var(--bs-font-monospace, monospace);
    font-weight: 700;
    margin-right: .3rem;
}

/* Weber : la flèche au-dessus, le mot en dessous. La flèche donne le sens de
   lecture d'un coup d'œil, le mot lève l'ambiguïté — l'oreille droite étant
   dessinée à gauche de l'écran, une flèche seule pouvait se lire à l'envers. */
.orl-weber { line-height: 1.1; padding-top: .2rem; padding-bottom: .2rem; }
.orl-weber-fleche { display: block; letter-spacing: -1px; }
.orl-weber-mot { display: block; font-size: var(--orl-fs-xs, .75rem); font-weight: 400; }

/* Une case vide veut dire « non pratiqué ». Sans hauteur minimale elle
   s'écraserait, et la ligne du Weber sauterait à chaque clic. */
.orl-weber:empty { min-height: 2.4rem; min-width: 4.5rem; }

.table-scroll-xs, .table-scroll-s {
    overflow-y: auto;
    overflow-x: hidden;
    display: block;
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    box-shadow: var(--orl-shadow);
    padding: 0;
}

.table-scroll-xs { max-height: 400px; }
.table-scroll-s { max-height: 600px; }

/* Une table plus large que son cadre défile horizontalement — Bootstrap le
   permet déjà via .table-responsive — mais rien ne le signale : la colonne
   Actions sort du cadre sans qu'aucune barre ne le laisse deviner au premier
   coup d'œil, en particulier sur un écran secondaire de cabinet (~1024px).

   Deux ombres portées aux bords, visibles seulement quand il reste du
   contenu à découvrir de ce côté-là : recette CSS pure (sans JavaScript),
   deux dégradés qui défilent avec le contenu (background-attachment: local)
   et deux qui restent fixes aux bords du cadre (scroll), pour que l'ombre
   s'efface d'elle-même en bout de course. */
.table-responsive {
    background-image:
        linear-gradient(to right, var(--orl-surface) 50%, rgba(255, 255, 255, 0)),
        linear-gradient(to left, var(--orl-surface) 50%, rgba(255, 255, 255, 0)),
        linear-gradient(to right, rgba(15, 46, 74, .16), rgba(15, 46, 74, 0)),
        linear-gradient(to left, rgba(15, 46, 74, .16), rgba(15, 46, 74, 0));
    background-repeat: no-repeat;
    background-color: var(--orl-surface);
    background-size: 32px 100%, 32px 100%, 12px 100%, 12px 100%;
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-attachment: local, local, scroll, scroll;
}

/* Voir le commentaire associé dans site.js : le temps qu'un menu déroulant
   reste ouvert, la table et son cadre renoncent à rogner ce qui les dépasse,
   sans quoi le menu d'une dernière ligne — seul cas d'une table à une ligne —
   est coupé à ras au lieu de s'afficher. Les coins de l'en-tête redeviennent
   carrés pendant ce temps-là, ce qui ne se voit pas : le menu couvre la zone. */
.table.orl-dropdown-ouvert,
.table-responsive.orl-dropdown-ouvert,
.card.orl-dropdown-ouvert {
    overflow: visible;
}

/* -------------------------------------------------------------- Onglets ---- */

.nav-tabs {
    border-bottom: 1px solid var(--orl-line);
    gap: .25rem;
}

.nav-tabs .nav-link {
    font-weight: 600;
    padding: .55rem 1rem;
    color: var(--orl-muted);
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}

.nav-tabs .nav-link:hover {
    background-color: var(--orl-brand-soft);
    color: var(--orl-accent-dark);
}

/* Onglet actif souligné plutôt que rempli de bleu : moins lourd, et la couleur
   reste disponible pour signaler ce qui compte vraiment. */
.nav-tabs .nav-link.active {
    background-color: transparent;
    color: var(--orl-accent-dark);
    border-bottom-color: var(--orl-accent);
}

/* --------------------------------------------------------- Formulaires ---- */

.form-control, .form-select {
    border-radius: var(--orl-radius-sm);
    border-color: var(--orl-line-champ);
    color: var(--orl-ink);
}

/* Le gris de Bootstrap (#6c757d) tombait à 4,49:1 sur le fond de page, sous le
   seuil de 4,5:1 : le texte indicatif de la recherche du haut prend le gris
   atténué de la charte. opacity: 1 car Firefox éclaircit encore les
   placeholders par défaut. */
.form-control::placeholder {
    color: var(--orl-muted);
    opacity: 1;
}

.form-check-input { border-color: var(--orl-line-champ); }

/* Champ en erreur (classe posée par jQuery Validate côté client ou par Razor
   côté serveur) : le bord beige ne se distinguait pas d'un champ valide. Le
   message sous le champ (.field-validation-error) porte déjà le sens sans la
   couleur seule ; ce bord ne fait que le renforcer. */
.form-control.input-validation-error,
.form-select.input-validation-error {
    border-color: var(--orl-danger);
}

/* Un champ isolé matchait à la fois :focus et :focus-visible — un texte est
   toujours son propre repère de focus, souris ou clavier confondus, à la
   différence d'un bouton. Cette règle-ci lui donnait son halo rond ; celle du
   dessus, plus loin dans la cascade sur :focus-visible, lui ajoutait un
   contour carré décalé de 2px. Les deux s'affichaient ensemble : un anneau
   dans l'anneau. Le groupe de saisie plus bas avait déjà réglé le même
   problème avec « outline: none » sur ce même halo rond ; il ne restait qu'à
   l'appliquer ici, au champ seul. */
.form-control:focus, .form-select:focus {
    border-color: var(--orl-accent);
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--orl-accent) 20%, transparent);
    outline: none;
}

/* Le fondu de 150 ms de Bootstrap laissait deux champs cerclés au Tab, le
   quitté et le nouveau : une action au clavier ne s'anime pas. */
.form-control, .form-select { transition: none; }

/* Sur téléphone, 16 px dans les champs : en dessous, iOS Safari agrandit la
   page au focus (audit de finition du 2026-09-28, P3-2). */
@media (max-width: 767.98px) {
    .form-control, .form-select,
    .orl-recherche .form-control { font-size: 16px; }
}

/* Un groupe de saisie (icône + champ + select + bouton, voir la recherche des
   patients) : Bootstrap 5.1 pose son propre rayon (0.25rem) sur les deux
   extrémités visibles — l'icône et le dernier bouton — au lieu du rayon des
   champs de l'app, et carre le bouton quand un enfant caché (la liste de
   suggestions) se glisse après lui et lui vole son statut de « dernier
   enfant » aux yeux de Bootstrap. Les deux bornes du groupe sont donc fixées
   par position réelle plutôt que par :first-child/:last-child (retour
   client, écran Patients).

   !important : la règle de Bootstrap qui carre les éléments du milieu,
   « .input-group:not(.has-validation) >
   :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu) », pèse
   (0,5,0) et l'emportait — le bouton restait carré dès que la liste de
   suggestions le suivait, c'est-à-dire dans l'application réelle et jamais
   sur une page de test qui l'omettait. Surenchérir en spécificité serait
   fragile ; ces deux coins-là n'ont aucune autre raison de varier. */
.input-group > .input-group-text:first-child {
    border-top-left-radius: var(--orl-radius-sm) !important;
    border-bottom-left-radius: var(--orl-radius-sm) !important;
}

.input-group > .btn:not(:has(~ .btn)) {
    border-top-right-radius: var(--orl-radius-sm) !important;
    border-bottom-right-radius: var(--orl-radius-sm) !important;
}

/* L'icône de tête d'un groupe de recherche est sur la surface, comme le champ
   qu'elle précède : .input-group-text (plus bas) la teinte en --orl-line-soft,
   ce qui convient à un préfixe « € » ou « % » mais faisait de la loupe une
   case grise devant un champ blanc — la vue le corrigeait par bg-white. Une
   classe explicite, et non un sélecteur global : les autres préfixes gardent
   leur teinte. Spécificité (0,3,0) pour l'emporter sur la règle plus bas.
   Pas « orl-recherche-icone » : ce nom est pris, plus bas, par la loupe posée
   en absolu de la barre du haut, et sortirait l'icône du groupe. */
.input-group > .input-group-text.orl-recherche-prefixe {
    background-color: var(--orl-surface);
}

/* Le bouton secondaire d'un groupe (« Rechercher ») gardait le filet d'encre
   de btn-outline-secondary, alors que l'icône, le champ et le select portent
   le filet beige des champs : collé au bout du groupe, il se lisait comme une
   boîte rapportée. Même filet que ses voisins ; l'encre revient au survol. */
.input-group > .btn-outline-secondary {
    border-color: var(--orl-line);
    color: var(--orl-ink-2);
    background-color: var(--orl-surface);
}

.input-group > .btn-outline-secondary:hover {
    border-color: var(--orl-line);
    color: var(--orl-accent-dark);
    background-color: var(--orl-brand-soft);
}

/* L'anneau de focus générique (outline, plus bas) ne suit pas les coins
   carrés que Bootstrap impose au milieu d'un groupe, et s'ajoute au halo de
   « .form-control:focus » ci-dessus : deux anneaux visibles, l'un carré,
   l'autre rond. Dans un groupe, un seul anneau — le même halo rond que les
   champs seuls — porté au-dessus des voisins pour qu'il ne soit pas coupé par
   leur bordure, qui le chevauche de 1px. */
.input-group > .form-control:focus-visible,
.input-group > .form-select:focus-visible,
.input-group > .btn:focus-visible {
    position: relative;
    z-index: 4;
    outline: none;
    /* !important : sans lui, « .btn:focus { box-shadow: none !important } »
       (plus haut) éteignait ce halo sur le bouton du groupe — « Rechercher »
       n'avait plus aucun repère au clavier. */
    box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--orl-accent) 20%, transparent) !important;
}

/* Une case cochée ou un interrupteur actif : Bootstrap 5.1 les peint en dur
   dans son bleu #0D6EFD. Proche de l'ancien bleu de la charte, l'écart ne se
   voyait pas ; à côté du bleu Casbah, c'était le seul bleu vif de l'écran. */
.form-check-input:checked {
    background-color: var(--orl-accent);
    border-color: var(--orl-accent);
}

.form-check-input:focus { border-color: var(--orl-accent); }

/* Meme raisonnement que .btn:focus plus haut : Bootstrap pose son propre halo
   (rgba(13, 110, 253, .25)) sur :focus, donc aussi au clic de souris. Le halo
   Casbah de site.css ne s'affiche plus qu'au clavier (:focus-visible,
   commit à venir) ; sans cette regle, celui de Bootstrap revenait a sa place
   a chaque clic sur la case. */
.form-check-input:focus:not(:focus-visible) { box-shadow: none; }

label, .form-label {
    font-weight: 600;
    font-size: var(--orl-fs-md);
    color: var(--orl-ink-2);
    margin-bottom: .3rem;
}

/* .form-group a été supprimée en Bootstrap 5 : elle ne produit plus aucun
   espacement. Les vues sont converties en « mb-3 » ; cette règle sert de
   filet pour tout gabarit qui l'utiliserait encore. */
.form-group { margin-bottom: 1rem; }

.text-danger { color: var(--orl-danger) !important; font-size: var(--orl-fs-md); }

/* --------------------------------------------------- Notifications ---- */

.orl-toasts {
    position: fixed;
    top: 1rem;
    right: 1rem;
    z-index: var(--orl-z-notifications);
    display: flex;
    flex-direction: column;
    gap: .5rem;
    max-width: min(24rem, calc(100vw - 2rem));
}

.orl-toast {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-left: 4px solid var(--orl-accent);
    border-radius: var(--orl-radius-sm);
    box-shadow: var(--orl-shadow-flottant);
    padding: .7rem .9rem;
    font-size: var(--orl-fs-md);
    animation: orl-toast-in .18s ease-out;
}

.orl-toast.is-success { border-left-color: var(--orl-success); background: var(--orl-success-soft); }
.orl-toast.is-error   { border-left-color: var(--orl-danger);  background: var(--orl-danger-soft); }
.orl-toast.is-warning { border-left-color: var(--orl-warning); background: var(--orl-warning-soft); }

.orl-toast i { font-size: var(--orl-fs-base); line-height: 1.35; }
.orl-toast.is-success i { color: var(--orl-success); }
.orl-toast.is-error i   { color: var(--orl-danger); }
.orl-toast.is-warning i { color: var(--orl-warning); }

.orl-toast .btn-close { margin-left: auto; font-size: var(--orl-fs-2xs); opacity: .5; }

@keyframes orl-toast-in {
    from { opacity: 0; transform: translateY(-.4rem); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .orl-toast { animation: none; }
    * { transition: none !important; }
}

/* Le refus qui reste dans la page — « ce numéro est déjà pris », « la somme
   dépasse le reste dû ». Il s'affichait en petit texte rouge sans cadre ni
   icône, quand le MÊME refus, quand le contrôleur redirige au lieu de
   réafficher, arrive en bandeau encadré à icône (.orl-toast.is-error).

   Deux apparences pour un seul fait, et la moins visible des deux pour le cas
   où l'utilisateur a justement une saisie à reprendre : une ligne rouge collée
   sous un bouton se confond avec les messages de champ, et se rate. Elle prend
   ici la forme de l'autre — même encadré, même filet gauche, même octogone.

   Une règle de feuille de style plutôt que trente-quatre gabarits retouchés :
   « validation-summary-errors » est posée par ASP.NET lui-même, et seulement
   quand il y a quelque chose à lire — le div vide porte « -valid » et reste
   invisible. */
.validation-summary-errors {
    display: flex;
    gap: .6rem;
    background: var(--orl-danger-soft);
    border: 1px solid var(--orl-line);
    border-left: 4px solid var(--orl-danger);
    border-radius: var(--orl-radius-sm);
    padding: .7rem .9rem;
    margin-bottom: 1rem;
    font-size: var(--orl-fs-md);
    color: var(--orl-danger);
}

.validation-summary-errors::before {
    font-family: bootstrap-icons;
    content: "\f336";
    font-size: var(--orl-fs-base);
    line-height: 1.35;
    flex: none;
}

.validation-summary-errors ul { margin: 0; padding-left: 0; list-style: none; }
.validation-summary-errors li + li { margin-top: .25rem; }

/* ------------------------------------------------------- États vides ---- */

.orl-empty {
    text-align: center;
    padding: 2.5rem 1rem;
    color: var(--orl-muted);
    background: var(--orl-surface);
    border: 1px dashed var(--orl-line);
    border-radius: var(--orl-radius);
}

.orl-empty i {
    font-size: var(--orl-fs-3xl);
    display: block;
    margin-bottom: .5rem;
    opacity: .5;
}

/* ------------------------------------------------------------ Badges ---- */

.orl-pill {
    display: inline-block;
    font-size: var(--orl-fs-xs);
    font-weight: 600;
    padding: .15rem .55rem;
    border-radius: 999px;
    border: 1px solid transparent;
}

/* « background-color » et non le raccourci « background » : ce dernier remet
   à zéro tout ce qu'il ne nomme pas, et effaçait le « background-image » de
   la flèche de .orl-pill-select sur cinq statuts sur six (défaut pré-existant
   à la refonte, revue de marque 4.3.0). */
.orl-pill.is-neutral { background-color: var(--orl-line-soft); color: var(--orl-ink-2); border-color: var(--orl-line); }
.orl-pill.is-success { background-color: var(--orl-success-soft); color: var(--orl-success-ink); }
.orl-pill.is-warning { background-color: var(--orl-warning-soft); color: var(--orl-warning-ink); }
.orl-pill.is-danger  { background-color: var(--orl-danger-soft); color: var(--orl-danger-ink); }
/* Voile bleu, et non plus le turquoise de la charte précédente que ce
   commentaire citait encore : un fait acquis, sans jugement — un rendez-vous
   confirmé n'est ni une réussite (le patient n'est pas encore venu) ni une
   alerte. Le vert et l'ambre restent ainsi disponibles pour ce qui est
   vraiment terminé ou vraiment anormal. */
.orl-pill.is-info    { background-color: var(--orl-accent-soft); color: var(--orl-accent-dark); }

/* Annulé partageait l'aplat ambre #fef3c7 avec le pense-bête (--orl-warning-soft) :
   la même teinte disait deux choses différentes sur le même écran — une note
   qui se remarque sans réclamer, et un fait accompli. Un rendez-vous annulé
   n'est pas une alerte à traiter : le neutre barré le dit sans emprunter au
   pense-bête. Ardoise sur lin sable : 6,75:1. */
.orl-pill.is-annule {
    background-color: var(--orl-line-soft);
    color: var(--orl-muted);
    border-color: var(--orl-line);
    text-decoration: line-through;
}

/* Une pastille qui mène quelque part — le reste à payer, qui ouvre les factures
   du patient. Elle garde exactement l'apparence des autres : c'est la même
   information, et lui donner l'allure d'un lien ferait croire à deux natures de
   pastille. Le curseur et le fait qu'elle s'assombrisse au survol suffisent à
   dire qu'on peut cliquer, une fois la souris dessus. */
a.orl-pill {
    text-decoration: none;
    cursor: pointer;
    transition: filter .12s ease-out;
}

a.orl-pill:hover,
a.orl-pill:focus-visible {
    filter: brightness(.94);
    text-decoration: none;
}

/* Le patient est arrivé et attend derrière la porte. C'est le seul statut qui
   appelle un geste dans la minute, et il doit se voir d'un bout à l'autre du
   planning.
   PLEINE, ET NON UNE SIXIÈME PASTEL. L'indigo clair a été essayé : à côté du
   turquoise de « Confirmé », les deux se confondaient d'un coup d'œil — soit
   exactement ce que ce statut existe pour éviter. Le contraste ne vient donc
   pas de la teinte mais du poids : une pastille pleine au milieu de cinq
   pastels se repère sans être cherchée.

   Voir plus haut pourquoi « background-color » et non le raccourci
   « background » : la flèche du menu déroulant se retrouvait répétée en
   mosaïque et posée sur le texte, parce que la position et le « no-repeat »
   de .orl-pill-select étaient effacés au passage. */
.orl-pill.is-attention {
    /* La prune de la charte elle-même : 7,32:1 sous le blanc, à ΔE 25,9 du
       bleu Casbah et à ΔE 14,4 des liserés violets des praticiens (contre
       9,3 pour l'ancien indigo #585BE3, qui s'y confondait — revue de
       marque, 4.3.0). */
    background-color: var(--orl-accent2);
    color: #fff;
    border-color: var(--orl-accent2-dark);
}

/* Le statut du jour, modifiable sans quitter l'accueil : un <select> habillé
   en pastille plutôt qu'un <span> — même forme, même couleurs par état, mais
   cliquable. Les couleurs elles-mêmes restent celles de .orl-pill.is-*, fixées
   par AppointmentStatus côté serveur puis retouchées par rdv-liste.js au choix. */
.orl-pill-select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    cursor: pointer;
    font: inherit;
    /* Une flèche discrète, pour que la pastille se distingue d'un simple
       texte sans reprendre le chrome natif du navigateur — variable selon
       qu'il est ouvert en clair ou en sombre. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='%234a5560' d='M2.5 4.5 6 8l3.5-3.5z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .3rem center;
    background-size: .6rem;
    padding-right: 1.2rem;
}

.orl-pill-select:focus-visible { outline: 2px solid var(--orl-accent); outline-offset: 1px; }

/* La liste déroulée, elle, n'est pas une pastille.
   LE DÉFAUT. Les options héritent de la couleur et du gras du <select>. Ouvrir
   le statut d'un rendez-vous honoré donnait donc six lignes vertes en gras sur
   fond vert, y compris « Annulé » : la couleur du statut COURANT repeinte sur
   tous les choix, ce qui dit exactement le contraire de ce qu'elle signale.
   La pastille garde sa couleur fermée ; la liste revient au texte ordinaire. */
.orl-pill-select option {
    background-color: var(--orl-surface);
    color: var(--orl-ink);
    font-weight: 400;
}

/* « En salle d'attente » est la seule pastille pleine : sa flèche passe en
   blanc, le gris des autres disparaîtrait sur ce fond-là. Placée après la
   règle générale pour la remplacer. */
.orl-pill-select.is-attention {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='%23fff' d='M2.5 4.5 6 8l3.5-3.5z'/%3E%3C/svg%3E");
}

/* La ligne entière fait ce que fait son bouton principal — sauf sur un lien,
   un bouton ou le statut, que rdv-liste.js laisse gérer leur propre clic.
   Absente d'une ligne qui n'a rien à proposer : une consultation déjà reçue a
   ses propres actions, et cliquer la ligne ne doit pas en offrir une autre. */
.orl-rdv-ligne-cliquable { cursor: pointer; }

/* ----------------------------------------------------------- Utilitaires ---- */

.text-brand { color: var(--orl-brand); }
.text-accent { color: var(--orl-accent-dark); }

/* Bootstrap 5.1 code .rounded, .alert, .modal-content et .dropdown-menu en
   dur a .25rem — une troisieme valeur de rayon qui ne correspond a aucun des
   deux tokens de la charte, et qui aurait fini par recreer sur les alertes et
   le menu du compte le meme defaut que sur l'accueil : un rayon trop petit
   pour se voir a cote d'un bouton ou d'une carte. */
.rounded { border-radius: var(--orl-radius-sm) !important; }
.alert { border-radius: var(--orl-radius-sm); }
/* overflow: hidden — sans lui, le survol du premier ou du dernier lien
   dessine un rectangle qui deborde tout droit du coin arrondi du menu. */
.dropdown-menu { border-radius: var(--orl-radius-sm); overflow: hidden; }
.modal-content { border-radius: var(--orl-radius); }

/* En-tête de dossier patient : le praticien doit savoir en permanence de qui
   il est question, sans remonter en haut de page. */
.orl-patient-bar {
    display: flex;
    align-items: center;
    gap: .9rem;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-left: 4px solid var(--orl-accent);
    border-radius: var(--orl-radius);
    padding: .8rem 1rem;
    margin-bottom: 1rem;
    box-shadow: var(--orl-shadow);
}

/* Pastille d'initiales, utilisable seule (listes) ou dans l'en-tête patient. */
.orl-avatar {
    width: 2.25rem;
    height: 2.25rem;
    flex: 0 0 auto;
    border-radius: 50%;
    background: var(--orl-line-soft);
    color: var(--orl-ink-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: var(--orl-fs-sm);
    letter-spacing: .02em;
}

.orl-patient-bar .orl-avatar {
    width: 2.5rem;
    height: 2.5rem;
    font-size: var(--orl-fs-md);
}

.orl-patient-bar .orl-name {
    font-weight: 700;
    font-size: var(--orl-fs-lg);
    line-height: 1.2;
    color: inherit;
    text-decoration: none;
    display: inline-block;
}

.orl-patient-bar .orl-name:hover {
    text-decoration: underline;
}

.orl-patient-bar .orl-meta {
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
}

/* Allergies connues. Le rouge est justifié ici : c'est la seule information du
   bandeau qui doit interrompre la lecture, et elle n'apparaît que si elle a été
   saisie — un bandeau sans allergie reste calme. */
.orl-allergie {
    display: inline-flex;
    align-items: baseline;
    gap: .4rem;
    margin-top: .35rem;
    padding: .2rem .6rem;
    border-radius: var(--orl-radius-sm);
    background: var(--orl-danger-soft);
    color: var(--orl-danger);
    font-size: var(--orl-fs-md);
}

/* Le bloc « Onglets en cadre » (.orl-frame) a ete supprime avec les iframes.
   Les onglets du dossier patient sont desormais des vues partielles rendues
   dans la page : plus de hauteur a deviner, plus de double barre de defilement,
   et le contenu reprend le flux normal du document. */

/* ------------------------------------------------------------ Footer ---- */
/* Même carte que la navbar (--orl-radius, --orl-shadow) : le pied de page
   ferme la page dans le thème qu'elle a ouvert, plutôt qu'un simple filet
   de séparation. */

.footer {
    background: transparent;
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
    margin-top: 1rem;
}

.orl-footer-carte {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem 1.5rem;
    background-color: var(--orl-surface);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: .85rem 1.25rem;
    margin-bottom: 14px;
}

.orl-footer-marque {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-weight: 600;
    color: var(--orl-ink-2);
    white-space: nowrap;
}

/* L'éditeur signe à droite, à côté de sa version ; le cabinet garde la
   gauche, sans icône devant : « bi-ear-fill » restait un reliquat ORL dans
   une marque devenue multi-spécialités (retour client, 4.3.0). 7 px : la
   zone de protection réduite (0,5 x) qu'autorise la charte en barre
   compacte. */
/* margin-left: auto : quand la largeur manque, la signature passe à la ligne
   et retombait à gauche, sous le nom du cabinet, comme orpheline. Elle reste
   ainsi à droite, sur sa ligne comme sur la ligne des liens. */
.orl-footer-signature {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    margin-left: auto;
}

/* Le logo complet en 24 px, bleu et encre, pesait plus lourd que tout le
   reste du pied (retour client : « c'est grossier »). Le pied n'a pas à
   porter la marque, seulement à la signer : symbole monochrome de 14 px et
   nom en minuscules, dans le gris du texte atténué, à la taille de la
   version qu'il accompagne. */
.orl-footer-kalma {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--orl-muted);
    font-family: 'Readex Pro', Inter, sans-serif;
    font-size: var(--orl-fs-xs);
    font-weight: 500;
    letter-spacing: .01em;
}

.orl-footer-kalma img {
    display: block;
    width: 14px;
    height: 14px;
    opacity: .7;
}

/* flex-wrap : à 390 px de large, les quatre liens mesuraient 402 px et
   faisaient défiler toutes les pages de côté (audit UX, RESP-01). */
.orl-footer-liens {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem 1.25rem;
    margin-right: auto;
}

/* 1,5 rem de haut au moins : à 21 px, un lien du pied se vise mal du doigt
   sur une tablette de comptoir (audit A11Y-21). Le texte reste centré, le
   lien étant déjà un flex. */
.orl-footer-liens a {
    display: inline-flex;
    align-items: center;
    min-height: 1.5rem;
    gap: .35rem;
    color: var(--orl-muted);
    text-decoration: none;
}

.orl-footer-liens a:hover { color: var(--orl-accent-dark); }

/* Encre secondaire et non gris atténué : sur le fond de la pastille, ce dernier
   n'atteint que 4,34:1, trop peu pour du 12 px. */
.orl-footer-version {
    font-variant-numeric: tabular-nums;
    font-size: var(--orl-fs-xs);
    color: var(--orl-ink-2);
    background-color: var(--orl-line-soft);
    border-radius: var(--orl-radius-sm);
    padding: .2rem .5rem;
    white-space: nowrap;
}

/* Le numéro est devenu un lien vers les Nouveautés : il garde son allure de
   pastille discrète, sans le bleu souligné d'un lien ordinaire, et ne se
   révèle cliquable qu'au survol. */
a.orl-footer-version {
    text-decoration: none;
}

a.orl-footer-version:hover,
a.orl-footer-version:focus-visible {
    color: var(--orl-accent-dark);
    background-color: var(--orl-accent-soft);
}

/* ------------------------------------------------- Écran de connexion ---- */
/* Deux volets sur un écran d'ordinateur : le cabinet à gauche, sur le lin
   sable de la page, le formulaire à droite, sur blanc. Sur un téléphone ils
   s'empilent. Auparavant, une carte de 380 px flottait seule au milieu d'un
   écran de 1440 : c'est la page que voit un nouveau client avant toute autre,
   et elle ressemblait au gabarit par défaut de n'importe quel site.

   Le titre reste au cabinet — on se connecte chez soi, pas chez son éditeur.
   Les images sont celles de Kalma, partagées en deux : le symbole au-dessus
   du titre, le logotype seul en pied du formulaire. Aucune
   couleur nouvelle : sable, blanc, filet, voile et encre sont ceux de la
   charte. */
.orl-connexion {
    display: grid;
    grid-template-columns: 1fr;
    /* Empilés, le cabinet prend sa hauteur et le formulaire le reste : sans
       cela, la grille partageait l'écran en deux et le volet du cabinet
       gonflait (250 px pour 140 px de contenu à 375 px). */
    grid-template-rows: auto 1fr;
    min-height: 100dvh;
    /* Le gabarit entoure la page d'un « container-fluid px-3 » : les volets
       vont jusqu'aux bords de l'écran. */
    margin-inline: -1rem;
}

/* Le gabarit réserve de la place sous le contenu pour le pied de page, absent
   ici : sans ce retrait, l'écran défilerait de 56 px pour rien. */
.orl-contenu:has(.orl-connexion),
main:has(> .orl-connexion) { padding-bottom: 0 !important; }

.orl-connexion-cabinet {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 2.25rem 1.5rem 1.75rem;
    background-color: var(--orl-page);
    border-bottom: 1px solid var(--orl-line);
}

/* L'arc du symbole Kalma, très agrandi, en voile : la seule touche décorative
   de l'écran, et elle est tirée du logo plutôt qu'ajoutée. Masqué sur un
   téléphone, où le volet du cabinet n'est plus qu'un bandeau. */
.orl-connexion-arc {
    display: none;
    position: absolute;
    right: -14rem;
    bottom: -16rem;
    width: 44rem;
    height: 44rem;
    color: var(--orl-accent-soft);
    pointer-events: none;
}

.orl-connexion-cabinet > :not(.orl-connexion-arc) { position: relative; }

/* Le symbole Kalma, au-dessus du nom du cabinet. Le logo du cabinet n'est
   plus affiché sur cet écran (voir Login.cshtml). */
.orl-connexion-symbole {
    display: block;
    width: 44px;
    height: 44px;
    margin-bottom: 1.25rem;
}

/* Le nom du cabinet : 16 caractères de large au plus, pour qu'un nom long
   passe sur deux lignes équilibrées plutôt que sur une ligne interminable. */
.orl-connexion-titre {
    font-size: var(--orl-fs-2xl);
    line-height: 1.15;
    letter-spacing: -.02em;
    max-width: 16ch;
    margin-bottom: .5rem;
}

/* Sur téléphone, le volet du cabinet prenait un tiers de l'écran (280 px à
   375×812, 340 px avec un nom long) et repoussait le bouton de connexion vers
   le bas : bandeau resserré, titre d'un cran plus petit. */
@media (max-width: 575.98px) {
    .orl-connexion-cabinet { padding-block: 1.25rem; }
    .orl-connexion-titre { font-size: var(--orl-fs-xl); }
}

.orl-connexion-accroche {
    color: var(--orl-muted);
    max-width: 32ch;
    margin: 0;
}

.orl-connexion-volet {
    display: flex;
    flex-direction: column;
    padding: 2rem 1.5rem 0;
    background-color: var(--orl-surface);
}

/* Le formulaire se pose directement sur le blanc : une carte bordée et ombrée
   ne séparait plus rien, puisqu'il est seul dans son volet. */
.orl-connexion-form {
    width: 100%;
    max-width: 24rem;
    margin-bottom: auto;
}

.orl-connexion-form h2 {
    font-size: var(--orl-fs-xl);
    margin-bottom: 1.5rem;
}

/* Le paragraphe qui explique la page, sous son titre : mot de passe oublié,
   compte verrouillé, code de secours. Rapproché du titre, qu'il complète,
   et éloigné du formulaire, qu'il annonce. */
.orl-connexion-intro {
    color: var(--orl-muted);
    margin: -.75rem 0 1.5rem;
}

.orl-connexion-form .form-control { padding: .625rem .875rem; }

/* Le bouton qui affiche le mot de passe, logé dans le champ. On tape souvent
   ce mot de passe devant un patient, à l'accueil, sur un clavier qui n'est pas
   le sien : pouvoir relire sa saisie évite de la recommencer à l'aveugle. */
.orl-mdp { position: relative; }
.orl-mdp .form-control { padding-right: 2.75rem; }

.orl-mdp-bouton {
    position: absolute;
    inset-block: 0;
    right: 0;
    width: 2.75rem;
    border: 0;
    background: none;
    color: var(--orl-muted);
    border-radius: 0 var(--orl-radius-sm) var(--orl-radius-sm) 0;
    transition: color .15s ease;
}

.orl-mdp-bouton:hover { color: var(--orl-accent); }

.orl-mdp-bouton:focus-visible {
    outline: 0;
    box-shadow: inset 0 0 0 2px var(--orl-accent);
}

.orl-connexion-bouton {
    padding-block: .625rem;
    font-weight: 600;
}

.orl-connexion-bouton:active { transform: translateY(1px); }

/* Le lien secondaire sous le bouton : « Mot de passe oublié ? », « Retour à
   la connexion », « Utiliser un code de secours ». */
.orl-connexion-lien {
    display: inline-block;
    margin-top: 1rem;
    font-size: var(--orl-fs-md);
}

/* Sous le formulaire, le logotype Kalma signe le logiciel sans disputer
   l'en-tête au cabinet. Un filet le sépare du formulaire. Les 14 px au-dessus du logo
   sont sa zone de protection : une hauteur d'x, soit 0,57 × 24 px. Ils sont en
   px et non en rem, parce que le rem change de taille avec l'écran (14 px puis
   16 px) alors que le logo reste à 24 px. */
.orl-signature-editeur {
    display: flex;
    justify-content: flex-start;
    width: 100%;
    max-width: 24rem;
    margin: 2.5rem 0 0;
    padding: 14px 0 1.5rem;
    border-top: 1px solid var(--orl-line);
}

.orl-signature-editeur img {
    display: block;
    height: 24px;
    width: auto;
}

@media (min-width: 992px) {
    .orl-connexion { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); grid-template-rows: 1fr; }

    .orl-connexion-cabinet {
        padding: 4rem clamp(2.5rem, 5vw, 5.5rem);
        border-bottom: 0;
        border-right: 1px solid var(--orl-line);
    }

    .orl-connexion-arc { display: block; }

    .orl-connexion-titre { font-size: var(--orl-fs-affichage); }

    .orl-connexion-volet { padding: 4rem clamp(2.5rem, 6vw, 7rem) 0; }

    /* Centré dans son volet, en hauteur comme en largeur : calé à gauche,
       le formulaire laissait 430 px vides au bord droit d'un écran de
       1920 px, contre 115 à sa gauche. Le texte, lui, reste aligné à
       gauche ; la signature suit le formulaire pour garder le même bord. */
    .orl-connexion-form { margin: auto; }

    .orl-connexion-volet .orl-signature-editeur { margin-inline: auto; }
}

@media (prefers-reduced-motion: reduce) {
    .orl-mdp-bouton { transition: none; }
    .orl-connexion-bouton:active { transform: none; }
}

/* ------------------------------------------------------ Espace compte ---- */
/* Les pages de gestion du compte proviennent du gabarit ASP.NET Identity :
   titres surdimensionnés, bouton « Save » pleine largeur en btn-lg, menu en
   nav-pills bleu vif. Rien de tout cela ne correspond au reste de
   l'application, et l'ensemble criait plus fort que le dossier patient — qui
   est pourtant l'écran qui compte.

   Le parti pris ici : la couleur ne sert qu'à désigner la page courante et
   l'unique bouton d'envoi. Tout le reste est en neutres. */

/* Plafonnée à 76rem auparavant : sur un grand écran, la barre de menu — qui
   suit toute la largeur de la page — dépassait ce plafond, et un grand vide
   apparaissait sous elle. Elle suit maintenant la largeur de la page comme
   le reste des écrans, sans plafond qui lui soit propre. */
.orl-account {
    width: 100%;
}

/* Taille : celle de tous les titres de page (h1, plus haut). */
.orl-account-title {
    font-weight: 600;
    margin-bottom: .15rem;
}

.orl-account-intro {
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
    margin-bottom: 1.5rem;
}

/* Menu latéral : filet de sélection à gauche plutôt qu'une pastille pleine.
   Même principe que les onglets du dossier patient, pour que les deux
   navigations se lisent de la même manière. */
.orl-account-nav {
    list-style: none;
    margin: 0;
    padding: 0;
    border-left: 1px solid var(--orl-line);
}

.orl-account-nav a {
    display: block;
    padding: .45rem .85rem;
    margin-left: -1px;
    border-left: 2px solid transparent;
    color: var(--orl-ink-2);
    font-size: var(--orl-fs-md);
    text-decoration: none;
    transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}

.orl-account-nav a:hover {
    color: var(--orl-accent-dark);
    background-color: var(--orl-brand-soft);
}

.orl-account-nav a.is-current {
    color: var(--orl-accent-dark);
    border-left-color: var(--orl-accent);
    font-weight: 600;
}

/* Panneau de contenu : une simple surface, sans ombre ni en-tête coloré —
   il n'y a qu'un panneau par page, le distinguer n'apporte rien. */
.orl-account-panel {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    padding: 1.5rem;
}

.orl-account-panel h2 {
    font-size: var(--orl-fs-base);
    font-weight: 600;
    margin-bottom: .15rem;
}

/* Texte d'aide sous un champ : explique à quoi il sert, plutôt que de laisser
   deviner. Volontairement discret — on le lit une fois. */
.orl-hint {
    display: block;
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
    margin-top: .3rem;
    line-height: 1.45;
}

/* Champ non modifiable : il doit se lire comme une information, pas comme une
   saisie possible. Bootstrap grise le texte, ce qui ne suffit pas à le dire. */
.orl-account .form-control:disabled,
.orl-account .form-control[readonly] {
    background-color: var(--orl-line-soft);
    color: var(--orl-ink-2);
    border-style: dashed;
}

/* ------------------------------------------------------ Facturation ---- */

/* Ce qui est dû, ce qui est entré, ce qui reste. Ces trois chiffres se lisent
   ensemble : un bandeau d'un seul tenant, et non trois cartes qui leur
   donneraient le poids de trois sections indépendantes. */
.orl-solde {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px;
    background: var(--orl-line);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    overflow: hidden;
    margin-bottom: 1rem;
}

.orl-solde-case {
    background: var(--orl-surface);
    padding: .85rem 1.1rem;
}

.orl-solde-libelle {
    display: block;
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
    margin-bottom: .15rem;
}

/* tabular-nums : sans lui, les chiffres n'ont pas tous la même largeur et
   trois montants empilés ne s'alignent pas sur la virgule. */
.orl-solde-valeur {
    font-size: var(--orl-fs-xl);
    font-weight: 600;
    color: var(--orl-ink);
    font-variant-numeric: tabular-nums;
}

/* Le reste à payer est la seule des trois valeurs qui appelle un geste.
   Écrites en texte, les teintes prennent leur encre (--orl-*-ink) et non
   leur aplat : l'ambre pur tombait à 2,15:1 sur le blanc et le vert à 3,30,
   sous le seuil de 4,5 ; leurs encres tiennent 7,09 et 7,13. */
.orl-solde-case.is-du .orl-solde-valeur { color: var(--orl-warning-ink); }
.orl-solde-case.is-solde .orl-solde-valeur { color: var(--orl-success-ink); }

/* Colonne de montants dans un tableau : alignés à droite, sur la virgule, et
   jamais coupés en deux lignes. */
.orl-montant {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* Comparaison des praticiens (DEM-014) : neuf colonnes de chiffres. Les
   intitulés passent à la ligne, les nombres non — c'est ce qui fait tenir le
   tableau dans la carte sans le faire défiler de côté. */
.orl-stat-comparaison thead th.orl-montant { white-space: normal; vertical-align: bottom; }

/* Une facture annulée reste au livre mais ne doit pas se confondre avec une
   facture due : elle s'efface sans disparaître. */
.orl-facture-annulee { color: var(--orl-muted); }
.orl-facture-annulee td { opacity: .75; }

/* Dans le dossier patient, les factures annulées ne s'affichent qu'à la
   demande — la case "Afficher les factures annulées" ajoute cette classe
   (DEM-021). Le tableau de recherche des factures n'est pas concerné : son
   propre filtre d'état gère déjà ce cas. */
#orlFacturesPatientListe .orl-facture-annulee { display: none; }
#orlFacturesPatientListe.orl-annulees-visibles .orl-facture-annulee { display: table-row; }

@media (max-width: 720px) {
    .orl-solde { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------ Fil d'Ariane ---- */
/* Affiché uniquement sur les écrans situés sous le dossier patient. Sur le
   dossier lui-même, la barre patient porte déjà le retour à la liste : deux
   chemins de retour concurrents se seraient contredits.

   Volontairement discret — c'est un repère, pas une action. */

.orl-fil {
    font-size: var(--orl-fs-sm);
    margin-bottom: .5rem;
    padding: 0;
    background: transparent;
}

.orl-fil .breadcrumb-item + .breadcrumb-item::before {
    content: "›";
    color: var(--orl-muted);
    padding-right: .4rem;
}

.orl-fil a {
    color: var(--orl-muted);
    text-decoration: none;
}

.orl-fil a:hover {
    color: var(--orl-brand);
    text-decoration: underline;
}

.orl-fil .breadcrumb-item.active {
    color: var(--orl-ink-2);
    font-weight: 600;
}

/* ------------------------------------------------ Recherche patient ---- */
/* Champ permanent dans la barre de navigation. Discret au repos — c'est un
   outil, pas une action mise en avant — et souligné d'accent au focus. */

.orl-recherche {
    position: relative;
    flex: 0 1 22rem;
    margin-right: 1rem;
}

.orl-recherche .form-control {
    padding-left: 2.1rem;
    padding-right: 2.2rem;
    height: 2.2rem;
    font-size: var(--orl-fs-md);
    background-color: var(--orl-page);
}

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

.orl-recherche-icone {
    position: absolute;
    left: .7rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
    pointer-events: none;
}

.orl-recherche-raccourci {
    position: absolute;
    right: .55rem;
    top: 50%;
    transform: translateY(-50%);
    background: var(--orl-line-soft);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    color: var(--orl-ink-2); /* le gris atténué n'y fait que 4,34:1 */
    font-size: var(--orl-fs-xs);
    padding: 0 .3rem;
    pointer-events: none;
}

/* Le raccourci disparait des que le champ sert : il n'a plus rien a apprendre. */
.orl-recherche .form-control:focus ~ .orl-recherche-raccourci { display: none; }

/* La même touche affichée, mais posée dans un bouton plutôt que dans un champ :
   pas de position absolue, et un contraste tenu sur fond coloré — sur un
   .btn-primary, le gris de --orl-muted disparaissait. */
.orl-kbd {
    background: rgba(255, 255, 255, .18);
    border: 1px solid rgba(255, 255, 255, .35);
    border-radius: var(--orl-radius-sm);
    color: inherit;
    font-size: var(--orl-fs-xs);
    line-height: 1.3;
    padding: 0 .3rem;
    margin-left: .35rem;
    opacity: .85;
}

/* Sur un bouton bordé, le fond est clair : le blanc translucide y disparaissait.
   La touche prend alors la couleur du texte du bouton, en filet. */
[class*="btn-outline-"] .orl-kbd,
.btn-link .orl-kbd {
    background: transparent;
    border-color: currentColor;
    opacity: .6;
}

/* ------------------------------------------ Raccourcis clavier ------------ */

/* « Aller au contenu » : invisible jusqu'au premier Tab, puis posé en haut à
   gauche, au-dessus de la barre — là où le regard le cherche. */
.orl-aller-contenu:focus {
    position: fixed;
    top: .5rem;
    left: .5rem;
    z-index: var(--orl-z-aller-contenu);
    padding: .5rem .9rem;
    background: var(--orl-surface);
    color: var(--orl-ink);
    border: 2px solid var(--orl-brand, currentColor);
    border-radius: var(--orl-radius-sm);
    box-shadow: var(--orl-shadow-flottant);
}

/* Le contenu reçoit le focus par le lien d'évitement ; un cadre autour de toute
   la page n'apprendrait rien, le lien a déjà dit où l'on arrive. */
main:focus { outline: none; }

/* Étroite : deux colonnes, une touche et une phrase. */
.orl-raccourcis-fenetre { max-width: 34rem; }

.orl-raccourcis-groupe {
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
    margin: 1rem 0 .4rem;
}

/* Le premier titre de la fenêtre n'a pas à s'écarter de l'en-tête : c'est le
   corps de la fenêtre qui porte l'espace, pas lui. */
.orl-raccourcis-fenetre .modal-body { padding-top: .25rem; }

.orl-raccourcis {
    width: 100%;
    border-collapse: collapse;
}

.orl-raccourcis td {
    padding: .35rem 0;
    border-bottom: 1px solid var(--orl-line-soft);
    vertical-align: top;
}

.orl-raccourcis td:first-child {
    width: 11rem;
    white-space: nowrap;
    padding-right: 1rem;
}

.orl-raccourcis kbd {
    display: inline-block;
    min-width: 1.6rem;
    text-align: center;
    background: var(--orl-page);
    color: var(--orl-ink);
    border: 1px solid var(--orl-line);
    border-bottom-width: 2px;
    border-radius: var(--orl-radius-sm);
    font-size: var(--orl-fs-sm);
    padding: .05rem .35rem;
}

.orl-raccourcis-note {
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
    margin: 1rem 0 0;
}

/* Une touche n'est utile qu'à qui a un clavier. Sur tablette elle n'annonce
   qu'un geste impossible, et elle mange la largeur du bouton. */
@media (hover: none) {
    .orl-kbd { display: none; }
}

/* La recherche de la liste des patients réutilise la liste déroulante de la
   barre du haut, mais rien de son habillage : là-bas le champ est étroit, à
   hauteur réduite, et l'icône est posée en absolu par-dessus. Ici l'icône est un
   élément du groupe Bootstrap et le champ garde sa taille normale.

   Seule la position relative est commune — c'est elle qui ancre la liste. */
.orl-recherche-liste {
    position: relative;
}

.orl-recherche-resultats {
    position: absolute;
    top: calc(100% + .3rem);
    left: 0;
    right: 0;
    z-index: var(--orl-z-liste-deroulante);
    margin: 0;
    padding: .25rem;
    list-style: none;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    box-shadow: var(--orl-shadow-flottant);
    max-height: 22rem;
    overflow-y: auto;
}

.orl-recherche-item {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    padding: .4rem .6rem;
    border-radius: var(--orl-radius-sm);
    cursor: pointer;
}

/* La date de naissance et le téléphone restent lisibles sur le fond
   bleu clair de la suggestion retenue (voir la charte). */
.orl-recherche-item:hover,
.orl-recherche-item.is-active {
    background: var(--orl-brand-soft);
    --orl-muted: var(--orl-ink-2);
}

.orl-recherche-nom {
    font-weight: 600;
    font-size: var(--orl-fs-md);
    color: var(--orl-ink);
}

.orl-recherche-meta {
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
}

/* Ligne « créer le dossier » de la recherche patient : séparée des résultats
   par un filet, et hors du parcours clavier — elle ne prend jamais la classe
   is-active. */
.orl-recherche-item.orl-recherche-creer {
    border-top: 1px solid var(--orl-line);
    color: var(--orl-accent-dark);
    font-weight: 600;
}

.orl-recherche-vide {
    padding: .6rem;
    font-size: var(--orl-fs-md);
    color: var(--orl-muted);
    text-align: center;
}

/* « Rien trouvé » se lit en gris ; « la recherche n'a pas abouti » est un
   incident, et doit se distinguer d'un fichier vide — c'est la confusion des
   deux qui faisait créer un second dossier à un patient qui en avait un. */
.orl-recherche-echec {
    color: var(--orl-danger);
    font-weight: 500;
}

/* Dernière ligne des suggestions quand elles sont incomplètes : un lien vers la
   liste entière, séparé des patients proposés. Le bleu foncé, comme la ligne
   « créer le dossier » : le bleu primaire ne tenait pas au survol, sur fond
   bleu clair. */
.orl-recherche-tous {
    border-top: 1px solid var(--orl-line);
    color: var(--orl-accent-dark);
    font-weight: 600;
    font-size: var(--orl-fs-md);
}

/* Sous la barre repliee, le champ passe en pleine largeur plutot que de
   comprimer les liens de navigation. */
@media (max-width: 991.98px) {
    .orl-recherche {
        flex: 1 1 100%;
        margin: .5rem 0;
    }
}

/* ------------------------------------------------------ Pagination ---- */
/* Bootstrap code le bleu de ses liens de pagination en dur, comme pour les
   boutons : on realigne sur la palette du cabinet. */

.pagination .page-link {
    color: var(--orl-accent-dark);
    border-color: var(--orl-line);
    min-width: 2rem; /* « 1 » seul faisait 23,7 px : sous la cible de 24 px */
    text-align: center;
}

.pagination .page-link:hover {
    background-color: var(--orl-brand-soft);
    border-color: var(--orl-line);
    color: var(--orl-accent-dark);
}

.pagination .page-item.active .page-link {
    background-color: var(--orl-accent);
    border-color: var(--orl-accent);
    color: var(--orl-on-brand);
}

.pagination .page-item.disabled .page-link {
    color: var(--orl-muted);
    background-color: transparent;
    border-color: var(--orl-line-soft);
}

/* ------------------------------------------- Journal du dossier ---- */
/* Historique des modifications : une colonne d'evenements datee, lue du
   plus recent au plus ancien. Le filet vertical relie les pastilles pour
   qu'on lise une continuite plutot qu'une liste. */

.orl-journal {
    list-style: none;
    margin: 0;
    padding: 0;
    position: relative;
}

.orl-journal-entree {
    display: flex;
    gap: .9rem;
    padding-bottom: 1.5rem;
    position: relative;
}

.orl-journal-entree:last-child { padding-bottom: 0; }

/* Le filet s'arrete a la derniere pastille au lieu de flotter dans le vide. */
.orl-journal-entree:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 1rem;
    top: 2.1rem;
    bottom: .25rem;
    width: 1px;
    background: var(--orl-line);
}

.orl-journal-puce {
    flex: 0 0 2rem;
    height: 2rem;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--orl-fs-md);
    background: var(--orl-line-soft);
    color: var(--orl-ink-2);
    border: 1px solid var(--orl-line);
    z-index: 1;
}

/* Sur leur fond clair, les puces prennent l'encre de leur teinte : l'aplat
   pur n'y tenait que 3,00:1 (vert) et 1,93:1 (ambre). Le grenat sert aux
   deux, il tient déjà 5,35:1. */
.orl-journal-puce.is-success { background: var(--orl-success-soft); color: var(--orl-success-ink); border-color: transparent; }
.orl-journal-puce.is-danger  { background: var(--orl-danger-soft);  color: var(--orl-danger-ink);  border-color: transparent; }
.orl-journal-puce.is-warning { background: var(--orl-warning-soft); color: var(--orl-warning-ink); border-color: transparent; }

.orl-journal-corps { flex: 1 1 auto; min-width: 0; padding-top: .15rem; }

.orl-journal-tete {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .5rem;
    margin-bottom: .35rem;
}

.orl-journal-diff th,
.orl-journal-diff td {
    border: 0;
    padding: .2rem .5rem .2rem 0;
    vertical-align: top;
}

.orl-journal-diff th {
    font-weight: 500;
    color: var(--orl-muted);
    white-space: nowrap;
    width: 1%;
}

/* L'ancienne valeur est barree : l'oeil comprend le remplacement sans lire. */
.orl-journal-avant {
    color: var(--orl-muted);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

.orl-journal-fleche { color: var(--orl-muted); width: 1%; }

.orl-journal-apres { font-weight: 500; }

/* --------------------------------------------- Blocs de formulaire ------
   Un formulaire long se lit par blocs : « Identité », « Adresse »,
   « Contact ». Le patron est né sur la prise de rendez-vous — d'où les noms
   en orl-rdv-* — puis la fiche patient l'a repris sous des noms génériques,
   qui sont les bons : ces blocs n'ont rien de propre aux rendez-vous.

   Les deux séries de noms partagent chaque règle. Les anciens restent en
   alias, comme .orl-rdv-form et .orl-form plus haut : les renommer dans toutes
   les vues qui les portent déjà serait un remue-ménage sans effet visible.

   Ce fichier a manqué une fois, et c'est la raison de ce commentaire : la
   fiche patient est passée aux noms génériques sans que les règles suivent,
   et ses quatre blocs se sont retrouvés sans cadre, sans fond et sans ombre —
   un formulaire nu. Une classe employée par une vue et absente d'ici ne
   produit aucune erreur, nulle part : rien ne le signale que l'écran. */

.orl-bloc,
.orl-rdv-bloc {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: 1.1rem 1.25rem 1.25rem;
    margin-bottom: 1rem;
}

/* legend se pose par defaut sur la bordure du fieldset, hors de sa marge
   interieure : le titre du bloc touchait le haut de la carte. Flottante sur
   toute la largeur, elle rentre dans le flux et prend la marge du bloc comme
   n'importe quel contenu ; ce qui la suit repasse dessous. */
.orl-legende,
.orl-rdv-legende {
    float: left;
    width: 100%;
    padding: 0;
    font-size: var(--orl-fs-base);
    font-weight: 600;
    letter-spacing: -.005em;
    color: var(--orl-ink);
    margin-bottom: .75rem;
}

.orl-legende + *,
.orl-rdv-legende + * { clear: both; }

/* Seul le champ est étroit : le message « Proposé : … » voisin du bouton
   « Premier créneau libre » passait à la ligne dans 15rem. */
.orl-rdv-date > .form-control { max-width: 15rem; }
.orl-rdv-statut { max-width: 15rem; }

.orl-bloc-aide,
.orl-rdv-aide {
    margin: .75rem 0 0;
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
}

.orl-actions,
/* flex-wrap : sous le détail d'une consultation, jusqu'à six boutons se
   suivent ; ils passent à la ligne plutôt que de sortir de l'écran (audit
   UX, RESP-01). */
.orl-rdv-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    align-items: center;
}

/* Rendez-vous sur grand écran : deux colonnes lues l'une après l'autre dans
   l'ordre de la saisie au téléphone. Patient et date à gauche ; créneau et
   note à droite. Empilés, les blocs repoussaient le bouton Enregistrer sous
   l'écran pendant que la moitié droite de la page restait vide (retour
   mainteneur, avis medorl-uxui et UX Architect, 28/09/2026).
   Chaque colonne garde environ la largeur d'un formulaire d'une colonne :
   rien ne s'étire. Une première version élargissait tout le formulaire et ne
   scindait que le bloc Date, et patient et note s'étiraient sur 1000 px.
   À 1400 px et plus seulement : en dessous, deux colonnes serreraient la
   grille des créneaux. L'ordre du code, donc de la tabulation, ne change pas. */
@media (min-width: 1400px) {
    .orl-rdv-form:has(> .orl-rdv-colonnes) { max-width: 64rem; }

    .orl-rdv-colonnes {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: 1rem;
        align-items: start;
    }
}

/* L'astérisque des champs obligatoires. Ils ne se découvraient qu'après un
   refus de validation : on remplissait, on envoyait, et l'écran répondait ce
   qu'il aurait pu dire d'emblée.

   Rouge, mais pas de la couleur d'une erreur — c'en est l'annonce, pas une.
   Porté par un <span aria-hidden> : les lecteurs d'écran lisent l'attribut
   « required » du champ, et l'étoile n'y ajouterait qu'un « astérisque »
   énoncé après chaque libellé. */
.orl-requis {
    color: var(--orl-danger);
    margin-left: .15rem;
    font-weight: 600;
}

/* La légende « * champs obligatoires », en fin de barre d'actions. Poussée à
   droite : elle explique l'étoile, elle ne concurrence pas les boutons. */
.orl-actions-aide {
    margin-left: auto;
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
}

/* ------------------------------------------------ Fiche patient en deux ----
   La fiche tient en deux colonnes : a gauche qui est le patient et ou il
   habite, a droite comment on le joint. Un filet les separe.

   Le filet est pose sur la colonne de droite et non entre les deux : une
   bordure sur un element de grille suit sa hauteur, donc la plus haute des
   deux colonnes, sans qu'on ait a la connaitre.

   Il ne parait qu'a partir de « lg ». En dessous, les deux colonnes s'empilent
   et un trait vertical n'aurait plus rien a separer — il barrerait le cote de
   la page. */
@media (min-width: 992px) {
    .orl-fiche-colonne-jointe {
        border-left: 1px solid var(--orl-line);
    }
}

/* -- Le pense-bete du rendez-vous -- */

/* Papier plutot que pastille : une pastille se lit comme un statut, et le
   planning en aligne deja une par ligne. Le fond creme et le bord gauche epais
   disent « quelqu'un a colle un mot ici » sans avoir a l'ecrire. */
.orl-postit {
    display: flex;
    align-items: flex-start;
    gap: .4rem;
    max-width: 26rem;
    margin-top: .35rem;
    padding: .3rem .55rem;
    background: var(--orl-warning-soft);
    border: 1px solid var(--orl-warning-line);
    border-left: 3px solid var(--orl-warning);
    border-radius: var(--orl-radius-sm);
    font-size: var(--orl-fs-sm);
    font-weight: 400;
    color: var(--orl-ink-2);

    /* Ce qui a ete saisi sur plusieurs lignes se lit sur plusieurs lignes : une
       note d'accueil s'ecrit souvent en liste. */
    white-space: pre-line;
    overflow-wrap: anywhere;
}

.orl-postit > .bi {
    flex: none;
    margin-top: .1em;
    color: var(--orl-warning);
}

/* Hors tableau — detail et suppression du rendez-vous — la note n'a plus de nom
   au-dessus d'elle : elle prend un peu de place pour se tenir seule. */
.orl-postit-seul {
    max-width: 34rem;
    margin: .25rem 0 1rem;
    padding: .55rem .75rem;
    font-size: var(--orl-fs-md);
}


/* -- La liste d'attente du jour -- */

/* Le bloc « reglage » — le depliant qui portait le moment de passage, l'heure
   precise et l'urgence — est parti avec ces champs. L'ecran n'inscrit plus
   qu'un patient, un praticien et un motif. */

/* Ceux qui n'attendent plus restent lisibles, en retrait : ils repondent a
   « il est passe ? », ils ne demandent plus rien. */
.orl-attente-closes {
    opacity: .85;
}

/* Le champ de saisie porte le meme papier que la note affichee : ce qu'on tape
   ressemble a ce qu'on verra. */
.orl-postit-champ {
    background-color: var(--orl-warning-soft);
    border-color: var(--orl-warning-line);
    resize: vertical;
}

.orl-postit-champ:focus {
    background-color: var(--orl-warning-soft);
    border-color: var(--orl-warning);
}

/* -- Patient -- */

/* Le champ de recherche est ici un element de formulaire, pas un accessoire de
   barre de navigation : il occupe la largeur du bloc. */
/* Pleine largeur de son bloc, comme « Agenda » juste en dessous : plafonné à
   26 rem, il s'arrêtait au milieu de la carte du rendez-vous. */
.orl-patient-recherche {
    flex: none;
    margin-right: 0;
}

/* Mêmes taille de texte et fond que les champs voisins : le style de la barre
   du haut (14 px, fond beige) le faisait plus bas et plus pâle que « Praticien »
   ou « État » à côté de lui, sur la même ligne (Facturation, Sans rendez-vous). */
.orl-patient-recherche .form-control {
    height: auto;
    padding-top: .375rem;
    padding-bottom: .375rem;
    padding-right: .75rem;
    font-size: inherit;
    background-color: var(--orl-surface);
}
.orl-patient-choisi {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    background: var(--orl-accent-soft);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    max-width: 26rem;
}

.orl-patient-choisi .bi { color: var(--orl-accent-dark); }

.orl-patient-nom {
    font-weight: 600;
    color: var(--orl-ink);
}

/* Repousse « Changer » a droite sans le detacher de la carte. */
.orl-patient-choisi .btn-link {
    margin-left: auto;
    padding: 0;
    font-size: var(--orl-fs-sm);
    text-decoration: none;
}

/* ------------------------------------------------------- Largeur page ---- */

/* Remplace « container » de Bootstrap, plafonne a 1140px. Sur un ecran de
   1920, un tiers de la page restait vide et les tableaux se comprimaient
   sans raison.

   1560px et non toute la largeur : au-dela, l'oeil peine a suivre une ligne
   de tableau de gauche a droite, et les formulaires prendraient des champs
   impossibles a relire. */
.orl-page-large {
    width: 100%;
    max-width: var(--orl-largeur-page);
    margin: 0 auto;
    padding-left: var(--orl-marge-page);
    padding-right: var(--orl-marge-page);
}

/* Largeurs de formulaire, a poser sur le <form> lui-meme.

   Un formulaire n'occupe pas la largeur de la page : ces classes remplacent
   les « row > col-md-4 » qui enfermaient les formulaires dans un tiers de
   page — soit environ 380px, ou aucun libelle ne tenait sur une ligne. */
/* Quatre noms pour deux largeurs : orl-rdv-form et orl-param-form sont les
   noms d'origine, gardes pour les ecrans qui les portent deja. Les valeurs se
   lisent dans les jetons, une seule fois, pour qu'elles ne puissent plus
   diverger. */
.orl-form,
.orl-rdv-form { max-width: var(--orl-largeur-saisie); }

.orl-form-large,
.orl-param-form { max-width: var(--orl-largeur-contenu); }

/* Dans les Paramètres, le formulaire vit déjà dans la colonne de contenu de
   .orl-account (elle-même large de toute la page) : le plafond de 76rem,
   pensé pour un formulaire posé seul sur la page, laissait un vide entre le
   panneau et le menu du haut. Ne s'applique qu'ici — Facture et Consultation
   posent le même .orl-param-form seul sur la page et gardent leur plafond. */
.orl-account .orl-param-form { max-width: none; }

/* Les écrans qui listent plutôt qu'ils ne saisissent — le stock, ses alertes,
   la fiche d'un consommable — vont jusqu'au bord du contenu.

   Le plafond de 76rem est fait pour un formulaire : au-delà, l'œil perd la
   ligne entre l'étiquette et le champ. Une rangée de tuiles et un tableau n'ont
   pas ce problème, et le plafond leur laissait une bande vide à droite alors
   que la barre de navigation, elle, va jusqu'au bout — la page paraissait
   décentrée. C'est la même correction que .orl-account juste au-dessus, sans le
   détour par le menu latéral des Paramètres.

   La largeur reste bornée : c'est .orl-page-large, dans le gabarit, qui arrête
   le contenu là où s'arrête le menu. */
.orl-pleine-largeur { max-width: none; }

/* Le fil d'Ariane et la carte patient qui précèdent ces blocs : même largeur
   qu'eux, pour que rien ne déborde plus large que ce qu'il surmonte. */
.orl-entete-dossier { max-width: var(--orl-largeur-contenu); }

/* Certaines pages n'ont elles-mêmes aucune largeur étroite à surmonter — la
   création d'une consultation pose son formulaire et son panneau latéral sur
   toute la largeur de la page, une fiche de suivi ou une ordonnance posent
   leurs blocs de la même façon. Le plafond de 76rem n'y suit plus rien : il ne
   fait que laisser un vide à droite de la carte patient. La règle suivante
   l'annule, pour que la barre s'étende alors jusqu'où va le contenu — c'est-à-
   dire jusqu'à .orl-page-large, qui borne toute la page. Sélecteur combiné et
   non classe seule : les deux règles ont sinon la même spécificité, et c'est
   l'ordre du fichier qui déciderait plutôt que l'intention. */
.orl-entete-dossier.orl-entete-pleine-largeur { max-width: none; }

/* ------------------------------------------------------ Consultation ---- */

/* En-tete : quand a eu lieu la consultation, et de quel type. Ces deux faits
   se lisent d'un coup d'oeil, avant le contenu medical. */
.orl-consult-tete {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: 1.25rem;
    padding-bottom: .9rem;
    border-bottom: 1px solid var(--orl-line);
}

/* Porté par un h1 : c'est le titre de la page (audit UX, NAV-02). Il garde
   l'allure d'un intitulé, sur la même ligne que l'heure ou le numéro. */
.orl-consult-quand {
    display: inline;
    margin: 0;
    font-size: var(--orl-fs-lg);
    font-weight: 600;
    line-height: inherit;
    color: var(--orl-ink);
}

.orl-consult-heure {
    margin-left: .5rem;
    color: var(--orl-muted);
    font-variant-numeric: tabular-nums;
}

.orl-consult-champ + .orl-consult-champ { margin-top: 1.1rem; }

/* Intitule du champ : discret, en capitales, pour que le texte medical reste
   ce que l'oeil accroche en premier. */
.orl-consult-titre {
    margin: 0 0 .25rem;
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
}

.orl-consult-texte {
    margin: 0;
    color: var(--orl-ink);
    /* Les retours a la ligne saisis sont rendus : un diagnostic ecrit sur
       plusieurs lignes — c'est le cas de 38 000 consultations reprises de
       l'ancien logiciel — revenait sinon en un seul pave. */
    white-space: pre-line;
    /* Les champs medicaux n'ont plus de limite de longueur : une mesure de
       lecture confortable evite les lignes interminables sur grand ecran. */
    max-width: 68ch;
}

.orl-consult-vide {
    margin: 0;
    color: var(--orl-muted);
    font-style: italic;
    font-size: var(--orl-fs-md);
}

/* Le diagnostic est la conclusion de la consultation : un filet le distingue
   sans recourir a une couleur, qui porterait un sens qu'il n'a pas. */
.orl-consult-diagnostic {
    padding-left: .75rem;
    border-left: 3px solid var(--orl-accent);
    font-weight: 500;
}

/* Les notes de consultation se restituent avec leurs retours a la ligne :
   la regle est posee plus haut, avec .orl-texte-libre, qui vaut pour tous les
   textes saisis au clavier — antecedents, traitement en cours, notes. */

/* -------------------------------------------------------- Mon compte ---- */

/* Liste de faits en lecture. Le terme au-dessus de la valeur, et non a cote :
   dans une colonne etroite, « Double authentification » imposait sa largeur a
   toute la grille, et il ne restait plus assez de place pour une adresse
   e-mail — qui se coupait alors en trois morceaux. */
.orl-compte-faits {
    display: flex;
    flex-direction: column;
    gap: .75rem;
    margin: 0;
}

.orl-compte-faits dt {
    font-weight: 400;
    font-size: var(--orl-fs-sm);
    letter-spacing: .02em;
    color: var(--orl-muted);
    margin-bottom: .1rem;
}

.orl-compte-faits dd {
    margin: 0;
    font-size: var(--orl-fs-md);
    /* anywhere plutot que break-word : une adresse longue se coupe alors
       proprement en fin de ligne au lieu de deborder du bloc. */
    overflow-wrap: anywhere;
}

/* minmax etroit : les quatre chiffres tiennent sur une ligne des que le bloc
   depasse 30rem, au lieu de laisser le quatrieme seul en dessous. */
.orl-compte-chiffres {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
    gap: .75rem;
}

.orl-compte-chiffre {
    display: flex;
    flex-direction: column;
    gap: .1rem;
    padding: .8rem .9rem;
    background: var(--orl-page);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
}

.orl-compte-valeur {
    font-size: var(--orl-fs-2xl);
    line-height: 1.1;
    font-weight: 600;
    color: var(--orl-brand);
    font-variant-numeric: tabular-nums;
}

.orl-compte-libelle {
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
}

/* ---------------------------------------------------------- Parametres ---- */

/* La largeur de ces ecrans est declaree plus haut, avec les autres.

   Elargir ne suffisait pas : un champ « Adresse » etire sur toute la page se
   remplit mal et se relit encore moins bien. On garde donc des champs de
   longueur raisonnable, et ce sont les blocs que l'on met cote a cote.

   Deux colonnes a partir de 1200px seulement : en dessous, les blocs
   s'empilent et occupent toute la largeur disponible. */
@media (min-width: 75rem) {
    .orl-param-colonnes {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 1rem;
        align-items: start;
    }

    /* Un bloc marque « large » reprend les deux colonnes : les horaires
       alignent quatre champs, les couper en deux les rendrait illisibles. */
    .orl-param-colonnes > .orl-param-large { grid-column: 1 / -1; }

    /* Les blocs sont poses par la grille : leur marge propre creerait un
       ecart different entre colonnes voisines et blocs empiles. */
    .orl-param-colonnes > .orl-bloc,
    .orl-param-colonnes > .orl-rdv-bloc { margin-bottom: 0; }

    /* La marge retiree ci-dessus laissait les boutons coller au dernier bloc :
       elle est rendue au conteneur, qui la porte une seule fois. */
    .orl-param-colonnes { margin-bottom: 1rem; }
}

/* Une duree se saisit courte et se lit avec son unite : un champ nombre
   etire sur la colonne entiere suggererait qu'on y attend autre chose. */
.orl-duree {
    display: flex;
    align-items: baseline;
    gap: .6rem;
}

.orl-duree .form-control {
    width: 6.5rem;
    font-variant-numeric: tabular-nums;
}

.orl-duree-unite {
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
}

/* Navigation entre les sections des parametres. Des liens vers des pages
   distinctes, et non des onglets : chaque section a son formulaire et sa
   validation, si bien qu'un message d'erreur ne peut pas se retrouver
   cache derriere un onglet inactif. */
/* Navigation des parametres : laterale et groupee, non plus une rangee
   d'onglets. Ils etaient neuf, ajoutes un par un au fil des livraisons, et une
   rangee de neuf ne se lit plus — elle se parcourt en cherchant, et se replie
   sur deux lignes des que l'ecran retrecit.

   Elle reutilise « orl-account-nav » plutot que d'inventer un second menu
   lateral : les reglages du cabinet et ceux du compte se lisent alors de la
   meme maniere, et il n'y a qu'un jeu de regles a tenir. Seuls les titres de
   groupe et le retrait des sous-entrees sont propres a cet ecran. */
.orl-param-nav {
    margin-bottom: 1.5rem;
}

/* Titre de groupe : discret, en capitales espacees. Il classe sans attirer
   l'oeil — ce qu'on cherche est l'entree, pas le groupe. */
.orl-param-groupe {
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
    padding: 0 0 .35rem .85rem;
}

/* L'air se pose entre deux groupes, jamais au-dessus du premier : une marge
   portee par le titre lui-meme aurait decale le menu entier vers le bas. */
.orl-param-bloc + .orl-param-bloc .orl-param-groupe {
    margin-top: 1.25rem;
}

/* La sauvegarde : export de la base entiere, restauration d'essai, phrase
   secrete. Posee en dernier et separee du reste par un filet, pour qu'on n'y
   entre pas en cherchant autre chose. Ses quatre entrees restent toujours
   visibles : repliees, elles cachaient l'envoi automatique a qui ne l'avait
   pas encore trouve. */
.orl-param-bloc.is-sensible {
    border-top: 1px solid var(--orl-line);
    margin-top: 1.25rem;
    padding-top: 1rem;
}

.orl-param-bloc.is-sensible .orl-param-groupe {
    margin-top: 0;
}

/* Titre de la section ouverte : le nom de l'entree du menu, pour savoir ou
   l'on est sans chercher l'entree en gras. Il recoit les liens du menu ; la
   marge garde un peu d'air au-dessus quand le navigateur y descend. */
.orl-param-titre {
    font-size: var(--orl-fs-xl);
    font-weight: 600;
    margin-bottom: 1rem;
    scroll-margin-top: 1rem;
}

@media (max-width: 991.98px) {
    /* En colonne unique, le menu passe au-dessus du contenu. Empile, il
       occuperait tout le premier ecran avant la moindre ligne utile — plus mal
       que la rangee d'onglets qu'il remplace. Les groupes se posent donc cote a
       cote, autant que la largeur en accepte, et la hauteur est divisee par
       trois. Un filet separe l'ensemble du contenu, faute de quoi les deux se
       confondent. */
    .orl-param-nav {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
        gap: 0 1.25rem;
        align-items: start;
        border-bottom: 1px solid var(--orl-line);
        padding-bottom: .75rem;
    }

    .orl-param-nav > .orl-param-bloc > .orl-param-groupe {
        margin-top: 1rem;
    }

    /* La sauvegarde garde sa ligne a elle, sous les autres groupes, avec son
       filet : dans la grille, elle se serait glissee a cote de l'agenda. */
    .orl-param-nav > .orl-param-bloc.is-sensible {
        grid-column: 1 / -1;
        margin-top: 1rem;
        padding-top: 0;
    }
}

/* Encart d'information : ce qui va se passer, dit avant l'action plutot
   qu'apres coup dans un message de confirmation. */
.orl-avis {
    display: flex;
    gap: .65rem;
    margin-top: 1rem;
    padding: .75rem .9rem;
    background: var(--orl-brand-soft);
    border: 1px solid var(--orl-line);
    border-left: 3px solid var(--orl-accent);
    border-radius: var(--orl-radius-sm);
    font-size: var(--orl-fs-md);
    color: var(--orl-ink-2);
}

.orl-avis .bi {
    flex: none;
    margin-top: .1rem;
    color: var(--orl-accent);
}

/* -- Logo du cabinet -- */

.orl-logo {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 1.25rem;
}

/* Le damier laisse voir la transparence d'un PNG : un logo blanc sur fond
   blanc paraitrait manquant. */
.orl-logo-apercu {
    flex: none;
    width: 8rem;
    height: 5rem;
    display: grid;
    place-items: center;
    padding: .5rem;
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    background-color: var(--orl-surface);
    background-image:
        linear-gradient(45deg, var(--orl-line-soft) 25%, transparent 25%),
        linear-gradient(-45deg, var(--orl-line-soft) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, var(--orl-line-soft) 75%),
        linear-gradient(-45deg, transparent 75%, var(--orl-line-soft) 75%);
    background-size: 12px 12px;
    background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}

.orl-logo-apercu img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.orl-logo-vide {
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
}

.orl-logo-actions {
    flex: 1 1 18rem;
    min-width: 0;
}

/* -- Creneaux -- */

/* auto-fill plutot qu'un nombre fixe de colonnes : la grille se resserre sur
   telephone sans media query, et les creneaux gardent une taille cliquable. */
/* clear: both : la légende des blocs (.orl-rdv-legende) flotte sur toute la
   largeur. Posée directement dans le bloc « Créneau », cette grille — qui ne
   peut pas chevaucher un flottant — se rangeait à côté de la légende, dans une
   largeur nulle : une seule colonne de créneaux, sortie du bloc par la droite
   (4.6.2, serveur de test). Elle passe désormais dessous. */
.orl-creneaux {
    clear: both;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
    gap: .5rem;
    margin-top: .35rem;
}

.orl-creneaux-message {
    grid-column: 1 / -1;
    margin: 0;
    padding: .75rem 0;
    color: var(--orl-muted);
    font-size: var(--orl-fs-md);
}

.orl-creneau {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .1rem;
    padding: .5rem .7rem;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    cursor: pointer;
    text-align: left;
    transition: border-color .12s, background-color .12s;
}

/* L'heure de fin, en gris atténué, n'atteindrait que 3,90:1 sur ce bleu. */
.orl-creneau:hover:not(:disabled) {
    border-color: var(--orl-accent);
    background: var(--orl-accent-soft);
    --orl-muted: var(--orl-ink-2);
}

.orl-creneau-heure {
    font-weight: 600;
    font-size: var(--orl-fs-base);
    color: var(--orl-ink);
    font-variant-numeric: tabular-nums;
}

.orl-creneau-fin {
    font-size: var(--orl-fs-xs);
    color: var(--orl-muted);
}

/* Le creneau retenu ne se distingue pas que par la couleur : le fond plein et
   le texte inverse restent lisibles en cas de daltonisme ou d'impression. */
.orl-creneau.is-choisi {
    background: var(--orl-accent);
    border-color: var(--orl-accent-dark);
}

.orl-creneau.is-choisi .orl-creneau-heure,
.orl-creneau.is-choisi .orl-creneau-fin { color: var(--orl-on-brand); }

.orl-creneau.is-pris {
    background: var(--orl-line-soft);
    border-style: dashed;
    cursor: not-allowed;
}

/* Barrée, l'heure dit déjà qu'elle est prise : le gris atténué n'ajoutait
   rien, sinon un contraste de 4,34:1 sur le fond du créneau. */
.orl-creneau.is-pris .orl-creneau-heure {
    color: var(--orl-ink-2);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* Pastille de la barre de navigation : le nombre d'alertes de stock.
   ------------------------------------------------------------------
   Ambre et non rouge : ce n'est pas une panne, c'est quelque chose à décider —
   jeter un lot, en commander un autre. Le rouge de la charte est réservé à ce
   qui est cassé, et l'user pour un réapprovisionnement le rendrait muet le jour
   où il servira vraiment.

   Le chiffre s'écrit à l'encre, comme sur les boutons ambre : en blanc, il
   ne tenait que 2,15:1 sur l'ambre, illisible en 11 px ; l'encre de nuit y
   tient 6,48:1. */
.orl-nav-pastille {
    background: var(--orl-warning);
    border-radius: 999px;
    color: var(--orl-ink);
    font-size: var(--orl-fs-2xs);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    line-height: 1;
    margin-inline-start: .25rem;
    padding: .15rem .4rem;
    vertical-align: text-top;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Agenda à durée libre
   ═══════════════════════════════════════════════════════════════════════════

   Le mode se règle dans Paramètres → Agenda, et se voit à trois endroits : le
   choix lui-même, la saisie de la durée, et le planning où les blocs cessent
   d'être tous égaux.

   Aucune couleur nouvelle : tout reprend l'accent et les gris de la charte. */

/* Les deux modes, en cartes cliquables. Le choix engage la façon de travailler
   du secrétariat et se fait une fois : il mérite de montrer ce qu'il implique,
   pas de tenir sur une ligne repliée dans une liste déroulante. */
.orl-mode-agenda {
    display: grid;
    gap: .75rem;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

.orl-mode-carte {
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    cursor: pointer;
    display: grid;
    gap: .35rem;
    padding: 1rem;
    transition: border-color .12s ease, background-color .12s ease;
}

.orl-mode-carte:hover { border-color: var(--orl-accent); }

.orl-mode-carte.is-choisi {
    background: var(--orl-page);
    border-color: var(--orl-accent);
    box-shadow: inset 0 0 0 1px var(--orl-accent);
}

.orl-mode-titre {
    font-size: var(--orl-fs-md);
    font-weight: 600;
}

.orl-mode-texte { color: var(--orl-ink); }

.orl-mode-detail {
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
}

/* Ce qui est déjà pris, sous les champs de saisie. Sans grille à griser, c'est
   la seule chose qui dise où se loger. */
.orl-occupation {
    background: var(--orl-page);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius-sm);
    padding: .6rem .8rem;
}

.orl-occupation-titre {
    color: var(--orl-muted);
    display: block;
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    margin-bottom: .35rem;
}

.orl-occupation-liste {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    list-style: none;
    margin: 0;
    padding: 0;
}

.orl-occupation-plage {
    background: var(--orl-line-soft);
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
    padding: .1rem .45rem;
}

.orl-occupation-vide { color: var(--orl-muted); }

/* Un creux libre, et il se clique : il pose son heure de début dans le champ.
   Assez marqué pour se distinguer des plages prises juste au-dessus — c'est la
   seule chose de ce bloc sur laquelle on agit. */
.orl-occupation-libre {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: 999px;
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: baseline;
    font-variant-numeric: tabular-nums;
    gap: .4rem;
    padding: .15rem .55rem;
}

.orl-occupation-libre:hover,
.orl-occupation-libre:focus-visible {
    border-color: var(--orl-accent);
    color: var(--orl-accent);
}

.orl-occupation-duree {
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
    font-variant-numeric: normal;
}

.orl-occupation-libre:hover .orl-occupation-duree,
.orl-occupation-libre:focus-visible .orl-occupation-duree { color: inherit; }

/* Ce qui est pris passe en second, replié : on l'ouvre pour répondre à « et à
   10h, il a quoi ? », pas pour poser un rendez-vous. */
.orl-occupation-pris { margin-top: .5rem; }

.orl-occupation-pris > summary {
    color: var(--orl-muted);
    cursor: pointer;
    font-size: var(--orl-fs-sm);
    margin-bottom: .35rem;
}

/* Le planning, quand les durées cessent d'être égales.
   ---------------------------------------------------
   Le trait de gauche est proportionnel à la durée : c'est ce qui rend visible,
   en parcourant la colonne, qu'un rendez-vous en vaut trois. Une grille
   régulière n'en avait pas besoin — toutes les lignes s'y valaient.

   La hauteur est bornée : sans plafond, un rendez-vous de quatre heures
   étirerait sa ligne au point de repousser les suivantes hors de l'écran. Le
   trait dit la proportion, pas la mesure exacte ; c'est le libellé « 45 min »
   qui donne le chiffre. */
.orl-agenda-horaire {
    align-items: center;
    display: flex;
    gap: .5rem;
}

/* Couleur par praticien : une bordure sur la première cellule de la ligne.

   Trois causes de décalage écartées, dans l'ordre où elles ont été trouvées :
     1. un <span> interne dont la hauteur dépendait de la durée du
        rendez-vous (l'ancien .orl-agenda-bloc) — elle pouvait dépasser
        celle de la ligne et déborder sur la suivante ;
     2. box-shadow posé sur <tr> plutôt que sur une cellule — masqué par le
        fond opaque des cellules, qui se peint par-dessus le fond de leur
        ligne dans le modèle de rendu des tableaux ;
     3. LA VRAIE CAUSE : .orl-agenda-horaire posait display:flex
        DIRECTEMENT SUR LE <td>. Un <td> ainsi transformé perd son
        comportement de cellule de tableau — sa hauteur ne suit plus celle
        de la ligne, elle retombe sur son seul contenu. Dès qu'une autre
        cellule de la même ligne réclamait plus de hauteur (un nom de
        patient qui repasse à la ligne, par exemple), cette cellule-là
        restait courte : la bordure qu'elle porte semblait alors s'arrêter
        avant la fin de la ligne. Le correctif est dans la vue : le flex vit
        maintenant sur un <div> À L'INTÉRIEUR du <td>, qui reste une vraie
        cellule et suit donc toujours la hauteur réelle de sa ligne — voir
        Views/Appointment/Index.cshtml.

   La classe est posée sur <tr> — voir WebUi.Helpers.PraticienAffichage, qui
   la choisit — et la durée reste lisible via .orl-agenda-duree, en toutes
   lettres, qui ne l'a jamais quittée.

   Palette à part de celle des statuts (is-success, is-warning…) : celle-ci
   n'est pas une gravité, c'est une catégorie, et le vert ou le rouge y
   ferait croire à une alerte qui n'existe pas.

   Rangs 2, 4, 5, 7 et 8 désaturés (revue de marque, 4.3.0) : les teintes
   Tailwind d'origine (chroma 71 à 102) restaient hors du registre sourd de
   la charte, et l'orange du rang 5 se lisait comme une alerte à côté du
   pense-bête ambre. Même teinte, chroma ramenée à 20-45 : les repères que les
   secrétaires ont appris (« Dr X = violet ») restent reconnaissables. Rangs 1,
   3 et 6 inchangés. */
/* En bordures fusionnées, le liseré de 4 px des lignes élargit le bord gauche
   du tableau de 2 px, et l'en-tête, qui n'en porte pas, commençait en retrait :
   une fente blanche entre le cadre de la carte et le fond de « Horaire »
   (retour client, 27/09/2026). Un liseré de la couleur de l'en-tête le remplit
   jusqu'au bord, et aligne son libellé sur celui des cellules. */
.table:has(> tbody > tr[class*="orl-praticien-"]) > thead > tr > th:first-child {
    border-left: 4px solid var(--orl-line-soft);
}

.table > tbody > tr.orl-praticien-1 > td:first-child { border-left: 4px solid #1d5c96; }
.table > tbody > tr.orl-praticien-2 > td:first-child { border-left: 4px solid #7956a7; }
.table > tbody > tr.orl-praticien-3 > td:first-child { border-left: 4px solid #0891b2; }
.table > tbody > tr.orl-praticien-4 > td:first-child { border-left: 4px solid #c04d76; }
.table > tbody > tr.orl-praticien-5 > td:first-child { border-left: 4px solid #b65f37; }
.table > tbody > tr.orl-praticien-6 > td:first-child { border-left: 4px solid #0d9488; }
.table > tbody > tr.orl-praticien-7 > td:first-child { border-left: 4px solid #3f4a8f; }
/* Fuchsia, et non plus la pierre #78716c qui occupait cette case. Un gris ne
   peut pas désigner un praticien : c'est la teinte que l'œil lit comme « rien »,
   et c'est celle qui marque, deux lignes plus bas, un rendez-vous sans agenda.
   La même couleur disait donc deux choses opposées — et celui qui y tombait
   paraissait ne pas en avoir. */
.table > tbody > tr.orl-praticien-8 > td:first-child { border-left: 4px solid #9f59a5; }
/* Rendez-vous d'avant le cloisonnement, sans praticien précis. Un gris neutre,
   et non plus var(--orl-accent) : celle-ci vaut #1d5c96, c'est-à-dire
   exactement la teinte du praticien n°1 — « le cabinet » et le premier
   praticien portaient le même filet, sur le seul écran qui sert à les
   distinguer. Le gris dit ici ce qu'il doit dire : personne en particulier. */
.table > tbody > tr.orl-praticien-aucun > td:first-child { border-left: 4px solid #9a948a; }

/* « Suivi par » (DEM-013) : une pastille par praticien, marquée d'un point à
   la couleur de son agenda — la même que le filet du planning, pour qu'on le
   reconnaisse d'un écran à l'autre. Le nom reste écrit en encre neutre : la
   couleur désigne, elle ne porte pas le texte, et ne pèse donc pas sur le
   contraste. */
.orl-suivi { display: inline-flex; flex-wrap: wrap; gap: .25rem; vertical-align: middle; }

/* Le filtre tient dans le groupe de la recherche, à sa largeur de contenu. */
.orl-filtre-praticien { flex: 0 0 auto; width: auto; max-width: 16rem; }

/* Sous 576 px, l'icône, le champ, la liste, « Rechercher » et la croix ne
   tiennent plus sur une ligne : le champ était réduit à une soixantaine de
   pixels. La liste passe seule sur une seconde ligne, en pleine largeur
   (le groupe Bootstrap se replie déjà : flex-wrap: wrap), et l'ordre la rejette
   après le bouton et la croix. Sa place dans le balisage — au milieu du groupe —
   lui vaut de Bootstrap des coins carrés et un recouvrement de 1px ; seule sur
   sa ligne elle n'a plus de voisin à qui se souder, d'où des coins tous ronds
   et pas de recouvrement (!important : la règle de Bootstrap pèse (0,6,0)).
   Les voisins n'ont rien à changer : la ligne du haut garde ses deux bornes
   (l'icône et le dernier bouton, voir plus haut). */
@media (max-width: 575.98px) {
    .input-group > .orl-filtre-praticien {
        order: 1;
        flex: 1 1 100%;
        width: 100%;
        max-width: none;
        margin-top: .5rem;
        margin-left: 0 !important;
        border-radius: var(--orl-radius-sm) !important;
    }
}
.orl-suivi-ligne { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .15rem; }

.orl-suivi-pastille {
    --orl-suivi-teinte: #9a948a;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .05rem .5rem;
    border: 1px solid var(--orl-line);
    border-radius: 999px;
    background: var(--orl-surface);
    color: var(--orl-ink-2);
    font-size: var(--orl-fs-sm);
    white-space: nowrap;
}

.orl-suivi-pastille::before {
    content: "";
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--orl-suivi-teinte);
}

.orl-suivi-pastille.orl-praticien-1 { --orl-suivi-teinte: #1d5c96; }
.orl-suivi-pastille.orl-praticien-2 { --orl-suivi-teinte: #7956a7; }
.orl-suivi-pastille.orl-praticien-3 { --orl-suivi-teinte: #0891b2; }
.orl-suivi-pastille.orl-praticien-4 { --orl-suivi-teinte: #c04d76; }
.orl-suivi-pastille.orl-praticien-5 { --orl-suivi-teinte: #b65f37; }
.orl-suivi-pastille.orl-praticien-6 { --orl-suivi-teinte: #0d9488; }
.orl-suivi-pastille.orl-praticien-7 { --orl-suivi-teinte: #3f4a8f; }
.orl-suivi-pastille.orl-praticien-8 { --orl-suivi-teinte: #9f59a5; }

.orl-agenda-plage { font-variant-numeric: tabular-nums; }

.orl-agenda-duree {
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
    font-weight: 400;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Tableau de bord des statistiques
   ═══════════════════════════════════════════════════════════════════════════

   Rien ici n'introduit de couleur nouvelle : les séries reprennent le
   bleu-vert de la marque et son accent, éclaircis par paliers. Le vert,
   l'ambre et le rouge de la charte sont réservés aux graphiques où « réglé »
   et « impayé » ont vraiment ce sens — une tranche d'âge n'est ni bonne ni
   mauvaise, et la teinter en rouge le laisserait croire.

   Aucune bibliothèque de graphiques n'est chargée. L'application est servie
   sans accès extérieur : un cabinet doit pouvoir ouvrir cet écran avec une
   connexion médiocre, ou sans connexion du tout. */

.orl-stat-intro {
    font-size: var(--orl-fs-md);
    margin-bottom: 1.25rem;
    max-width: 62ch;
}

/* ─── Les chiffres d'en-tête ─────────────────────────────────────────────── */

.orl-stat-chiffres {
    display: grid;
    /* 150px et non 180 : sur un téléphone, deux carreaux tiennent côte à
       côte au lieu d'une colonne de cinq cartes à faire défiler. */
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: .75rem;
    margin-bottom: 1.75rem;
}

.orl-stat-chiffre {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: .9rem 1rem;
    display: flex;
    flex-direction: column;
    gap: .15rem;
}

/* Le filet coloré ne reste qu'au carreau qui demande de l'attention : posé
   sur tous, il ne disait plus rien — un bleu de plus sur un écran où le bleu
   est réservé à ce qui se clique. Il survit à une impression en noir. */
.orl-stat-chiffre.is-attention { border-top: 3px solid var(--orl-warning); }

/* Un carreau qui mène quelque part le montre au survol et au clavier. Sans
   href — le compte n'ouvre pas cet écran —, il reste un simple chiffre. */
a.orl-stat-chiffre[href] {
    color: inherit;
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

a.orl-stat-chiffre[href]:hover {
    border-color: var(--orl-accent);
    box-shadow: var(--orl-shadow-lg, 0 .35rem 1rem rgba(15, 46, 74, .08));
    transform: translateY(-1px);
}

a.orl-stat-chiffre[href]:focus-visible {
    outline: 2px solid var(--orl-accent);
    outline-offset: 2px;
}

a.orl-stat-chiffre:not([href]) { cursor: default; }

@media (prefers-reduced-motion: reduce) {
    a.orl-stat-chiffre[href] { transition: none; }
    a.orl-stat-chiffre[href]:hover { transform: none; }
}

.orl-stat-valeur {
    font-size: var(--orl-fs-3xl);
    font-weight: 700;
    letter-spacing: -.02em;
    line-height: 1.1;
    color: var(--orl-ink);

    /* Les chiffres s'alignent en colonne d'une carte à l'autre. */
    font-variant-numeric: tabular-nums;
}

.orl-stat-libelle {
    font-size: var(--orl-fs-md);
    color: var(--orl-ink);
}

.orl-stat-detail {
    font-size: var(--orl-fs-xs);
    color: var(--orl-muted);
}

/* ─── Sections et cartes ─────────────────────────────────────────────────── */

.orl-stat-section {
    font-size: var(--orl-fs-xl);
    font-weight: 600;
    color: var(--orl-brand);
    margin: 2rem 0 .85rem;
    padding-bottom: .4rem;
    border-bottom: 1px solid var(--orl-line);
}

.orl-stat-grille {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1rem;
}

.orl-stat-carte {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: 1.1rem 1.15rem;
    margin-bottom: 1rem;
}

.orl-stat-titre {
    font-size: var(--orl-fs-lg);
    font-weight: 600;
    color: var(--orl-ink);
    margin: 0 0 1rem;
}

/* Une phrase sous le graphique, qui dit comment le lire. Un tableau de bord
   sans mode d'emploi se lit de travers ou pas du tout. */
.orl-stat-lecture {
    font-size: var(--orl-fs-sm);
    color: var(--orl-muted);
    margin: 1rem 0 0;
    padding-top: .75rem;
    border-top: 1px dashed var(--orl-line);
}

.orl-stat-absent {
    display: flex;
    align-items: flex-start;
    gap: .9rem;
}

.orl-stat-absent i {
    font-size: 1.5rem;
    color: var(--orl-muted);
    line-height: 1.3;
}

/* ─── Anneau ─────────────────────────────────────────────────────────────── */

.orl-anneau {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1.5rem;
}

.orl-anneau-figure {
    width: 170px;
    height: 170px;
    flex: 0 0 auto;
}

.orl-anneau-total {
    text-anchor: middle;
    font-size: 26px;
    font-weight: 600;
    fill: var(--orl-ink);
}

.orl-anneau-unite {
    text-anchor: middle;
    font-size: 12px;
    fill: var(--orl-muted);
}

.orl-anneau-legende {
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1 1 200px;
    min-width: 0;
}

.orl-anneau-legende li {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: baseline;
    gap: .5rem;
    padding: .35rem 0;
    border-bottom: 1px solid var(--orl-line-soft);
    font-size: var(--orl-fs-md);
}

.orl-anneau-legende li:last-child { border-bottom: 0; }

.orl-anneau-puce {
    width: .7rem;
    height: .7rem;
    border-radius: 2px;
    display: inline-block;
}

.orl-anneau-nom {
    color: var(--orl-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.orl-anneau-part {
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.orl-anneau-nombre {
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
    font-variant-numeric: tabular-nums;
}

/* ─── Barres horizontales ────────────────────────────────────────────────── */

.orl-barres {
    list-style: none;
    margin: 0;
    padding: 0;
}

.orl-barre {
    display: grid;
    grid-template-columns: minmax(6rem, 11rem) 1fr auto;
    align-items: center;
    gap: .75rem;
    padding: .3rem 0;
}

.orl-barre-nom {
    font-size: var(--orl-fs-md);
    color: var(--orl-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.orl-barre-piste {
    background: var(--orl-line-soft);
    border-radius: var(--orl-radius-sm);
    height: 1.15rem;
    overflow: hidden;
}

.orl-barre-valeur {
    display: block;
    height: 100%;
    border-radius: var(--orl-radius-sm);
    min-width: 2px;
}

.orl-barre-chiffre {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    font-variant-numeric: tabular-nums;
    font-size: var(--orl-fs-md);
    white-space: nowrap;
}

.orl-barre-part {
    color: var(--orl-muted);
    font-size: var(--orl-fs-sm);
    min-width: 3.2rem;
    text-align: right;
}

/* ─── Colonnes ───────────────────────────────────────────────────────────── */

.orl-colonnes {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 190px;
    overflow-x: auto;
    padding-bottom: .25rem;
}

.orl-colonne {
    flex: 1 1 0;
    min-width: 18px;
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* La piste occupe toute la hauteur pour que les colonnes partent d'une même
   ligne de base ; sans elle, chacune se cale sur sa propre hauteur et le
   graphique n'a plus de sol. */
.orl-colonne-piste {
    flex: 1 1 auto;
    display: flex;
    align-items: flex-end;
    background: linear-gradient(var(--orl-line-soft), var(--orl-line-soft)) no-repeat center / 100% 1px;
}

.orl-colonne-valeur {
    width: 100%;
    border-radius: 3px 3px 0 0;
    transition: opacity .12s ease;
}

.orl-colonne:hover .orl-colonne-valeur { opacity: .78; }

.orl-colonne-etiquette {
    font-size: var(--orl-fs-xs);
    color: var(--orl-muted);
    text-align: center;
    padding-top: .35rem;
    white-space: nowrap;
    overflow: hidden;
}

.orl-colonne-etiquette.is-masquee { visibility: hidden; }

/* ─── Impression ─────────────────────────────────────────────────────────── */

@media print {
    /* Les cartes ne doivent pas être coupées en deux par un saut de page :
       une légende orpheline sur la page suivante ne veut plus rien dire. */
    .orl-stat-carte,
    .orl-stat-chiffre {
        break-inside: avoid;
        box-shadow: none;
    }

    .orl-stat-section { break-after: avoid; }

    /* Sans cela, les navigateurs suppriment les aplats à l'impression et le
       tableau de bord sort en barres blanches. */
    .orl-barre-valeur,
    .orl-colonne-valeur,
    .orl-anneau-puce,
    .orl-anneau-figure,
    /* Un planning du jour imprime et pose sur le comptoir est un usage reel :
       sans cela le pense-bete sort en texte gris sur blanc, indistinct du
       reste. */
    .orl-postit {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    .orl-colonnes { overflow-x: visible; }
}

/* ─── Choix de la période ────────────────────────────────────────────────── */

.orl-stat-periode {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem 1.25rem;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    padding: .75rem .9rem;
    margin-bottom: 1.5rem;
}

.orl-stat-periode-champs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.orl-stat-periode-champs label {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin: 0;
    font-size: var(--orl-fs-md);
    color: var(--orl-muted);
}

.orl-stat-periode-champs input[type="date"] { width: auto; }

.orl-stat-raccourcis {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-left: auto;
}

/* Des liens, et non des boutons : la période vit dans l'adresse, donc chaque
   raccourci se met en favori et s'ouvre dans un nouvel onglet. */
.orl-stat-raccourci {
    font-size: var(--orl-fs-sm);
    color: var(--orl-accent-dark);
    text-decoration: none;
    padding: .2rem .6rem;
    border: 1px solid var(--orl-line);
    border-radius: 999px;
    white-space: nowrap;
}

.orl-stat-raccourci:hover {
    background: var(--orl-accent-soft);
    border-color: var(--orl-accent);
}

.orl-stat-raccourci.is-actif {
    background: var(--orl-accent);
    border-color: var(--orl-accent);
    color: var(--orl-on-brand);
}

@media print {
    /* Les contrôles ne servent à rien sur papier ; la période, si — elle est
       rappelée dans le titre. */
    .orl-stat-periode-champs,
    .orl-stat-raccourcis { display: none; }
    .orl-stat-periode { border: 0; padding: 0; }
}

/* ------------------------------------------ Avertissement de saisie ------- */
/* Une question posée au moment d'enregistrer — « ce patient est déjà attendu,
   voulez-vous quand même ? » —, et non une erreur.

   L'ambre plutôt que le rouge, et c'est toute la distinction : le rouge dit
   « corrigez », l'ambre dit « regardez avant de continuer ». Ce qui est saisi
   est correct ; c'est une décision qui revient à celui qui la fait. */
.orl-avertissement {
    background: var(--orl-warning-soft);
    border: 1px solid var(--orl-warning-line);
    border-radius: var(--orl-radius);
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.orl-avertissement-titre {
    font-weight: 600;
    margin: 0 0 .35rem;
}

.orl-avertissement-titre i { color: var(--orl-warning); }

.orl-avertissement-question {
    color: var(--orl-ink-2);
    margin: 0 0 .75rem;
}

.orl-avertissement-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

/* La même question, posée dans une fenêtre — « ce patient est déjà attendu ».
   ÉTROITE : trois lignes et deux boutons. Une fenêtre pleine largeur pour une
   phrase donne à la question un poids qu'elle n'a pas, et fait chercher des
   yeux les boutons qu'elle contient. */
.orl-modal-question {
    max-width: 24rem;
}

/* L'ambre du bandeau, repris ici : le rouge dirait « corrigez », l'ambre dit
   « regardez avant de continuer ». Ce qui est saisi est correct. */
.orl-modal-question-tete {
    background: var(--orl-warning-soft);
    border-bottom-color: var(--orl-warning-line);
    padding: .75rem 1rem;
}

.orl-modal-question-tete i { color: var(--orl-warning); }

.orl-modal-question-pied {
    padding: .6rem 1rem;
}

/* ------------------------------------------- Droits : l'accordéon ------- */

/* La matrice des droits fait une trentaine de lignes réparties en onze
   catégories. D'un seul tenant, elle se parcourait longtemps sans repère : on
   cochait une case sans plus voir de quel module elle relevait, et l'on
   remontait pour le vérifier.

   Un panneau par catégorie, donc. Ce qui suit ne change que l'habillage :
   Bootstrap 5.1 n'a pas de variables d'accordéon : les dix « --bs-accordion-* »
   qui vivaient ici n'avaient aucun effet, et l'accordéon restait peint dans
   le bleu et le gris par défaut de Bootstrap (ouvert : fond #e7f1ff, chevron
   #0c63e4 ; focus : anneau rgba(13,110,253,.25)), deux couleurs qui
   n'existent nulle part ailleurs dans l'application (finish-gate, revue de
   marque 4.3.0). L'habillage est repris ci-dessous par de vrais sélecteurs. */
.orl-droits-accordeon {
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
}

.orl-droits-accordeon .accordion-item {
    border-color: var(--orl-line);
}

.orl-droits-accordeon .accordion-item:first-of-type {
    border-top-left-radius: var(--orl-radius);
    border-top-right-radius: var(--orl-radius);
}

.orl-droits-accordeon .accordion-item:last-of-type {
    border-bottom-left-radius: var(--orl-radius);
    border-bottom-right-radius: var(--orl-radius);
}

/* Le titre tient la place qui reste, les pastilles se rangent à droite —
   avant le chevron, que Bootstrap pose en dernier. Sur écran étroit, les
   pastilles passent à la ligne au lieu d'écraser le titre. */
.orl-droits-accordeon .accordion-button {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    font-weight: 600;
    color: var(--orl-ink);
    background-color: var(--orl-surface);
}

/* Panneau ouvert : fond beige et texte encre, sans l'ombre bleue interne que
   Bootstrap pose par défaut (inset, jamais employée ailleurs ici). */
.orl-droits-accordeon .accordion-button:not(.collapsed) {
    color: var(--orl-ink);
    background-color: var(--orl-line-soft);
    box-shadow: inset 0 -1px 0 var(--orl-line);
}

/* La flèche est un SVG encodé en data-URI dont Bootstrap fixe le fill à
   #0c63e4 à l'état ouvert : seule façon de la recolorer, la réécrire avec le
   fill de l'encre (même dessin que Bootstrap, #0f2e4a en fill). */
.orl-droits-accordeon .accordion-button::after,
.orl-droits-accordeon .accordion-button:not(.collapsed)::after {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230f2e4a'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
}

.orl-droits-titre { margin-right: auto; }

/* Bootstrap pose aussi margin-left: auto sur le chevron : les deux marges
   automatiques se partageaient l'espace libre, et les pastilles flottaient
   au milieu du titre au lieu de se ranger à droite, contre le chevron. */
.orl-droits-accordeon .accordion-button::after { margin-left: 0; }

.orl-droits-compte {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    font-weight: 400;
}

/* Une catégorie ouverte : le tableau touche les bords du panneau, et son
   filet du haut fait la séparation avec le titre. */
/* Le tableau arrondit ses coins partout ailleurs (.table) ; ici, collé sous le
   titre de la catégorie, ses coins du haut découvraient le fond blanc du
   panneau derrière l'en-tête beige : un coin blanc à gauche de
   « Fonctionnalité ». C'est le panneau qui arrondit, pas le tableau. */
.orl-droits-accordeon .accordion-body > .table-responsive > .table { border-radius: 0; }

.orl-droits-accordeon .accordion-body > .table-responsive > .table > thead th {
    border-top: 0;
}

/* Bootstrap pose son anneau bleu sur :focus, pas seulement au clavier ; on le
   retire au profit du seul anneau de :focus-visible, juste dessous. */
.orl-droits-accordeon .accordion-button:focus {
    border-color: var(--orl-line);
    box-shadow: none;
}

.orl-droits-accordeon .accordion-button:focus-visible {
    outline: 2px solid var(--orl-accent);
    outline-offset: -2px;
}

@media print {
    /* Sur papier, tout se lit : un panneau replié y serait une catégorie
       manquante, sans rien pour dire qu'elle existe. */
    .orl-droits-accordeon .accordion-collapse { display: block !important; }
    .orl-droits-accordeon .accordion-button::after { display: none; }
    [data-orl-deplier-tout] { display: none; }
}

/* -------------------------------------- Tri par en-tête de colonne ------ */

/* Un en-tête qui trie est un lien, parce que le tri est fait par la base et
   que le résultat est une autre page — l'adresse la porte, donc elle se
   partage et le retour arrière la retrouve. Reste à ce qu'il ne ressemble pas
   à un lien : dans un tableau, un intitulé souligné en bleu se lit comme une
   donnée cliquable, pas comme une commande de tri. Il garde donc la couleur et
   la graisse des autres en-têtes, et ne se signale qu'au survol. */
.orl-tri-colonne {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
}

.orl-tri-colonne:hover { color: var(--orl-accent-dark); }

/* L'icône dit l'ordre en cours ; elle est plus discrète que l'intitulé, qui
   reste ce qu'on lit en premier. */
.orl-tri-colonne i {
    font-size: .85em;
    opacity: .6;
}

.orl-tri-colonne:hover i { opacity: 1; }

/* Le focus clavier doit se voir : sans contour, on ne saurait pas que
   l'en-tête est atteignable au clavier — c'est justement ce que le lien
   apporte sur une ligne cliquable qui, elle, ne l'est pas. */
.orl-tri-colonne:focus-visible {
    outline: 2px solid var(--orl-accent);
    outline-offset: 2px;
    border-radius: var(--orl-radius-sm);
}

/* ------------------------------------------------ Page Nouveautés ------- */

/* Une colonne de lecture, pas un tableau de bord : le texte se lit d'un
   trait, et au-delà de 52rem les lignes deviennent trop longues pour l'œil. */
/* Pleine largeur (DEM-002) : la page était plafonnée à 52rem, une colonne
   étroite au milieu d'un écran vide. Le sommaire occupe désormais la gauche. */

/* Le sommaire reste en vue à côté de la version lue. Il défile lui-même
   quand les groupes dépliés dépassent la hauteur de l'écran. */
@media (min-width: 992px) {
    .orl-nouveautes-sommaire {
        position: sticky;
        top: 1rem;
        max-height: calc(100vh - 2rem);
        overflow-y: auto;
    }
}

/* Un accordéon par version majeure (DEM-018) : l'intitulé reprend l'allure des
   groupes du menu des Paramètres, avec le nombre de versions qu'il contient. */
.orl-nouveautes-groupe + .orl-nouveautes-groupe {
    margin-top: .75rem;
}

.orl-nouveautes-groupe > summary {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .35rem .85rem;
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
    cursor: pointer;
    border-radius: var(--orl-radius-sm);
}

/* Le triangle natif disparaît avec display:flex : un chevron dit qu'on déplie,
   et pivote quand le groupe est ouvert. */
.orl-nouveautes-groupe > summary {
    list-style: none;
}

.orl-nouveautes-groupe > summary::-webkit-details-marker {
    display: none;
}

.orl-nouveautes-groupe > summary::before {
    content: "\f285";
    font-family: "bootstrap-icons";
    font-size: .7rem;
    transition: transform .15s ease;
}

.orl-nouveautes-groupe[open] > summary::before {
    transform: rotate(90deg);
}

@media (prefers-reduced-motion: reduce) {
    .orl-nouveautes-groupe > summary::before {
        transition: none;
    }
}

.orl-nouveautes-groupe > summary:hover {
    color: var(--orl-accent-dark);
    background-color: var(--orl-brand-soft);
}

.orl-nouveautes-groupe > summary:focus-visible {
    outline: 2px solid var(--orl-accent);
    outline-offset: 1px;
}

.orl-nouveautes-compte {
    margin-left: auto;
    font-weight: 400;
    letter-spacing: 0;
    font-variant-numeric: tabular-nums;
}

.orl-nouveautes-groupe > .orl-account-nav {
    margin-top: .35rem;
}

.orl-nouveautes-sommaire a {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: .5rem;
}

.orl-nouveautes-numero {
    font-variant-numeric: tabular-nums;
}

.orl-nouveautes-marque {
    font-size: var(--orl-fs-xs);
    padding-block: 0;
}

.orl-nouveautes-date {
    flex-basis: 100%;
    font-size: var(--orl-fs-xs);
    font-weight: 400;
    color: var(--orl-muted);
}

/* En colonne unique, le sommaire passe au-dessus : les versions d'un groupe se
   posent côte à côte plutôt qu'empilées — même parti que le menu des
   Paramètres. */
@media (max-width: 991.98px) {
    .orl-nouveautes-sommaire .orl-account-nav {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
        border-left: 0;
        border-bottom: 1px solid var(--orl-line);
        padding-bottom: .5rem;
    }
}

/* Précédente à gauche, suivante à droite, sous la version lue. */
.orl-nouveautes-voisines {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: 1rem;
}

/* La version installée se repère sans lire les numéros : un filet à gauche,
   dans la couleur de la pastille « Votre version ». */
.orl-nouveautes-installee {
    border-left: 3px solid var(--orl-success);
}

.orl-nouveautes-liste {
    padding-left: 1.1rem;
}

.orl-nouveautes-liste > li + li {
    margin-top: .35rem;
}

/* Bandeau « session ouverte sur un autre poste », posé par saisie.js au-dessus
   d'une saisie en cours au lieu de renvoyer la page à la connexion (audit UX,
   FLOW-01). Fixé en haut : il doit rester visible où que l'on soit dans un
   long compte rendu. */
.orl-bandeau-session {
    position: fixed;
    top: .75rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: var(--orl-z-bandeau);
    width: min(42rem, calc(100% - 1.5rem));
    padding: .9rem 1rem;
    background: var(--orl-warning-soft);
    color: var(--orl-ink);
    border: 1px solid var(--orl-warning);
    border-left: 4px solid var(--orl-warning);
    border-radius: var(--orl-radius-sm);
    box-shadow: var(--orl-shadow-flottant);
    font-size: var(--orl-fs-md);
}

/* Tant que le bandeau est là : les notifications passent en bas, sinon elles
   en cachent la phrase qui dit que la saisie n'est pas enregistrée ; et le
   défilement réserve sa hauteur, pour qu'il ne masque pas le champ qui a le
   focus (WCAG 2.4.11). */
body:has(> .orl-bandeau-session) .orl-toasts { top: auto; bottom: 1rem; }
html:has(body > .orl-bandeau-session) { scroll-padding-top: 12rem; }

/* Barre d'enregistrement collée au bas de l'écran, sur les formulaires trop
   longs pour que le bouton reste en vue — la matrice des droits (audit UX,
   FORM-01). */
.orl-barre-enregistrement {
    position: sticky;
    bottom: 0;
    z-index: var(--orl-z-barre-collante);
    padding: .65rem 0;
    background: var(--orl-page);
    border-top: 1px solid var(--orl-line);
}

/* ─── Bootstrap 5.1 : composants re-thémés ──────────────────────────────────
   Inventaire de la revue de marque 4.3.0 (finish-gate) : ces composants sont
   employés dans l'application mais n'avaient jamais reçu la charte Casbah —
   ils gardaient le bleu #0d6efd, le cyan et l'ambre par défaut de Bootstrap.
   Regroupés ici plutôt que dispersés à côté de chaque écran, parce qu'aucun
   d'eux n'avait jusqu'ici de section à lui dans ce fichier. Exception
   délibérée : .text-primary et les bascules de l'audiogramme gardent leurs
   couleurs conventionnelles (rouge/bleu de l'oreille droite/gauche), voir la
   charte en tête de fichier. */

/* Texte atténué et texte d'aide : #6c757d tombait à 4,49:1 sur le fond et
   3,56:1 sur une ligne survolée — sous le seuil AA que la charte promet
   partout. */
.text-muted { color: var(--orl-muted) !important; }
.form-text { color: var(--orl-muted); }
.text-success { color: var(--orl-success-ink) !important; }
/* #ffc107 sur blanc : 1,63:1, illisible. text-warning-emphasis est une classe
   Bootstrap 5.3 sans effet en 5.1 : elle est définie ici par précaution. */
.text-warning,
.text-warning-emphasis { color: var(--orl-warning-ink) !important; }

/* Alertes : Bootstrap 5.1 les peint chacune dans sa propre couleur par
   défaut (cyan pour info, gris froid pour secondary, ni l'une ni l'autre du
   Casbah), sans reprendre les jetons sémantiques déjà définis pour les
   pastilles de statut. */
.alert-info      { color: var(--orl-ink);         background-color: var(--orl-brand-soft);   border-color: var(--orl-accent-soft); }
.alert-secondary { color: var(--orl-ink-2);       background-color: var(--orl-line-soft);    border-color: var(--orl-line); }
.alert-success   { color: var(--orl-success-ink); background-color: var(--orl-success-soft); border-color: var(--orl-success-line); }
.alert-warning   { color: var(--orl-warning-ink); background-color: var(--orl-warning-soft); border-color: var(--orl-warning-line); }
.alert-danger    { color: var(--orl-danger-ink);  background-color: var(--orl-danger-soft);  border-color: var(--orl-danger-line); }
.alert .alert-link,
.alert a:not(.btn) { color: var(--orl-accent-dark); }

/* Menus déroulants hors du menu Agenda (compte, factures) : même survol et
   même état actif que .orl-nav-agenda .dropdown-item, plus haut, au lieu du
   gris #e9ecef et du bleu #0d6efd de Bootstrap. */
.dropdown-item:hover,
.dropdown-item:focus { background-color: var(--orl-brand-soft); color: var(--orl-accent-dark); }
.dropdown-item.active,
.dropdown-item:active { background-color: var(--orl-accent-soft); color: var(--orl-accent-dark); }

/* Champs non modifiables et préfixe d'un groupe de saisie : Bootstrap les
   laissait au gris froid #e9ecef. */
.form-control:disabled,
.form-control[readonly],
.form-select:disabled { background-color: var(--orl-line-soft); }
.input-group-text { background-color: var(--orl-line-soft); border-color: var(--orl-line); color: var(--orl-ink-2); }

/* Boutons que la charte n'avait pas encore habillés : le doublon à la saisie,
   les colonnes au choix, le rapprochement bancaire, la réserve de stock. */
.btn-warning,
.btn-warning:disabled { background-color: var(--orl-warning); border-color: var(--orl-warning); color: var(--orl-ink); }
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:active { background-color: var(--orl-warning); border-color: var(--orl-warning); color: var(--orl-ink); filter: brightness(.92); }
.btn-outline-success { color: var(--orl-success-ink); border-color: var(--orl-success-ink); }
.btn-outline-success:hover,
.btn-outline-success:active { background-color: var(--orl-success-ink); border-color: var(--orl-success-ink); color: var(--orl-on-brand); }

/* Bouton bordé à l'état actif — hors audiogramme, dont les bascules gardent
   le gris de Bootstrap juste dessous : ce n'est pas une action, c'est un
   choix de symbole parmi quatre, tous aussi cliquables les uns que les
   autres.
   L'enfoncement, lui, n'est qu'un accusé de réception : il fonce d'un cran
   la teinte du survol au lieu de basculer d'un bouton blanc à un aplat bleu
   le temps d'un clic. Il vient avant .active, qui l'emporte à spécificité
   égale : une bascule déjà choisie reste pleine sous le doigt. */
.btn-outline-secondary:active { background-color: var(--orl-accent-soft); border-color: var(--orl-muted); color: var(--orl-accent-dark); }
.btn-outline-secondary.active { background-color: var(--orl-accent); border-color: var(--orl-accent); color: var(--orl-on-brand); }

#orlAudiogramme .btn-outline-secondary.active,
#orlAudiogramme .btn-outline-secondary:active {
    background-color: #6c757d;
    border-color: #6c757d;
    color: #fff;
}

/* Anneaux et couleurs de focus restés au bleu #0d6efd de Bootstrap. */
.btn-close:focus { box-shadow: none; outline: 2px solid var(--orl-accent); outline-offset: 2px; }
.pagination .page-link:focus-visible { color: var(--orl-accent-dark); background-color: var(--orl-brand-soft); box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--orl-accent) 25%, transparent); }
.nav-tabs .nav-link:focus { color: var(--orl-accent-dark); }

/* Lignes de tableau colorées (stock, rapprochement des factures) : Bootstrap
   les peint dans ses propres pastels, texte noir compris. */
.table-success { --bs-table-bg: var(--orl-success-soft); color: var(--orl-ink); border-color: var(--orl-line); }
.table-warning { --bs-table-bg: var(--orl-warning-soft); color: var(--orl-ink); border-color: var(--orl-line); }
.table-danger  { --bs-table-bg: var(--orl-danger-soft);  color: var(--orl-ink); border-color: var(--orl-line); }

/* Filets restés au gris froid de Bootstrap, comme les séparateurs de tableau
   plus haut (voir la section Tables). */
.list-group-item { border-color: var(--orl-line); }
.modal-header,
.modal-footer { border-color: var(--orl-line); }
.border,
.border-top,
.border-end,
.border-bottom,
.border-start { border-color: var(--orl-line) !important; }
/* Après la règle ci-dessus : à spécificité égale, la dernière l'emporte. */
.border-warning { border-color: var(--orl-warning) !important; }
.bg-light { background-color: var(--orl-line-soft) !important; }

/* Bootstrap 5.2/5.3 sans effet en 5.1 : ajoutée ici plutôt que réécrite dans
   les quinze vues qui l'emploient déjà en attendant de le faire (hors gate,
   effort M). */
.fw-semibold { font-weight: 600 !important; }

/* ------------------------------------------- Paramètres › Utilisateurs ---- */

/* Une liste des comptes et un panneau pour celui qu'on a choisi. Les actions
   étaient répétées sur chaque ligne du tableau (cases de rôles, Appliquer,
   Désactiver, Mot de passe, Périmètre) : elles vivent désormais une seule
   fois, dans le panneau. Empilés sous 992 px, la liste d'abord. */
.orl-comptes-entete {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: 1rem;
}

.orl-comptes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    align-items: start;
}

@media (min-width: 992px) {
    .orl-comptes { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
    .orl-compte-panneau { position: sticky; top: 1rem; }
}

.orl-comptes-liste {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    padding: .4rem;
}

.orl-compte-ligne {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .6rem .75rem;
    border-radius: var(--orl-radius-sm);
    color: var(--orl-ink);
    text-decoration: none;
    border: 1px solid transparent;
}

.orl-compte-ligne:hover { background: var(--orl-line-soft); color: var(--orl-ink); }

.orl-compte-ligne.is-actif {
    background: var(--orl-brand-soft);
    border-color: var(--orl-accent-soft);
}

.orl-compte-ident { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.orl-compte-nom,
.orl-compte-sous {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.orl-compte-nom { font-weight: 600; }
.orl-compte-sous { font-size: var(--orl-fs-sm); color: var(--orl-muted); }

.orl-compte-roles { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .25rem; }

/* Sur téléphone, les pastilles passent sous le nom plutôt que d'écraser
   l'adresse à trois lettres. */
@media (max-width: 575.98px) {
    .orl-compte-ligne { flex-wrap: wrap; }
    .orl-compte-roles { flex-basis: 100%; justify-content: flex-start; padding-left: 3rem; }
}

.orl-compte-panneau {
    background: var(--orl-surface);
    border: 1px solid var(--orl-line);
    border-radius: var(--orl-radius);
    box-shadow: var(--orl-shadow);
    padding: 1.1rem 1.25rem 1.25rem;
    scroll-margin-top: 1rem;
}

.orl-compte-panneau-tete { display: flex; align-items: center; gap: .75rem; margin-bottom: .75rem; }
.orl-compte-panneau-titre { font-size: var(--orl-fs-lg); margin: 0; overflow-wrap: anywhere; }
.orl-avatar.orl-avatar-lg { width: 2.75rem; height: 2.75rem; }

.orl-compte-note { font-size: var(--orl-fs-sm); color: var(--orl-muted); margin: 0 0 .5rem; }

.orl-compte-section { border-top: 1px solid var(--orl-line); padding-top: .9rem; margin-top: .9rem; }
.orl-compte-section p:last-of-type { margin-bottom: .5rem; }

.orl-compte-section-titre {
    font-size: var(--orl-fs-sm);
    font-weight: 600;
    color: var(--orl-muted);
    margin: 0 0 .5rem;
}

.orl-compte-role { margin-bottom: .4rem; }
.orl-compte-role .orl-hint { margin-top: 0; }

/* Comptes archivés : la cellule reprend la ligne de la liste des actifs. */
.orl-compte-cellule { display: flex; align-items: center; gap: .75rem; min-width: 0; }
