/* =============================================
   GCA - Application CSS
   Theme dark professionnel pour cabinet d'avocats
   ============================================= */

/* =============================================
   1. VARIABLES CSS
   ============================================= */
/* -------------------------------------------------------------
   PALETTE "PETROLE & ABRICOT"

   Le petrole (#12484F) porte toute la structure : barre laterale,
   boutons primaires, liens, en-tetes. L'abricot (#C97F3E) n'est
   employe que sur ce qui est ACTIF ou demande une action -- jamais
   en aplat. C'est ce contraste chaud/froid, et lui seul, qui rend
   l'accent lisible ; le noyer en aplats le neutraliserait.

   Les gris ne sont pas neutres : ils tirent vers le petrole. Un gris
   parfaitement neutre a cote d'une teinte franche se lit comme un
   gris "non choisi".

   Les couleurs semantiques (succes / attention / danger) sont
   DISTINCTES de l'accent : une pastille d'alerte ne doit jamais
   pouvoir etre confondue avec un element simplement actif.
   ------------------------------------------------------------- */

/* Theme dark (defaut) */
:root, [data-theme="dark"] {
    /* Backgrounds */
    /* LA MARGE HAUTE DE LA ZONE DEFILANTE. Lue a DEUX endroits qui doivent
       s'accorder : le padding de ".app-main", et le "top" de l'en-tete de
       grille collant, qui vaut son OPPOSE. Voir le bloc de l'en-tete collant
       en fin de fichier pour la raison. */
    --app-main-padding-y: 20px;

    --bg-body: #0D1F22;
    --bg-surface: #142C30;
    --bg-surface-hover: #1B3A3F;
    --bg-sidebar: #0B1A1D;
    --bg-header: #0D1F22;
    --bg-card: #142C30;
    --bg-input: #0D1F22;

    /* Borders */
    --border-color: #24474C;
    --border-light: #1B3A3F;

    /* Text */
    --text-primary: #E3ECEC;
    --text-secondary: #9DB4B6;
    --text-muted: #6F8A8D;
    --text-accent: #D89355;

    /* Marque */
    --color-primary: #2E7D86;
    --color-primary-hover: #379AA4;
    --color-primary-dark: #12484F;
    --color-primary-wash: #14343A;
    --color-accent: #D89355;
    --color-accent-hover: #E5A66C;
    --color-accent-ink: #E5A66C;
    --color-accent-wash: #33261A;
    --color-accent-line: #4A3826;

    /* Status colors */
    --color-success: #3FA57F;
    --color-success-wash: #14332B;
    --color-warning: #D69A34;
    --color-warning-wash: #332914;
    --color-danger: #D4574A;
    --color-danger-wash: #35201D;
    --color-info: #379AA4;
    --color-purple: #D89355;

    /* Barre laterale : jetons dedies. La barre est sombre dans les DEUX
       themes, les jetons generiques de texte n'y sont donc pas utilisables. */
    --sidebar-text: #A8C0C2;
    --sidebar-text-muted: #6B8A8D;
    --sidebar-text-strong: #FFFFFF;
    --sidebar-hover-bg: rgba(255, 255, 255, 0.06);
    --sidebar-active-bg: rgba(255, 255, 255, 0.10);
    --sidebar-title: #7FA3A6;

    /* Spacing (commun aux 2 themes) */
    --sidebar-width: 260px;
    --sidebar-collapsed-width: 60px;
    --header-height: 56px;

    /* Transitions */
    --transition-fast: 0.15s ease;
    --transition-normal: 0.25s ease;

    /* Radius */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
}

/* Theme light */
[data-theme="light"] {
    --bg-body: #F3F6F6;
    --bg-surface: #FFFFFF;
    --bg-surface-hover: #F4F8F8;
    /* La barre laterale reste en petrole sombre sur fond clair : c'est elle
       qui ancre l'ecran et donne sa couleur a l'application. */
    --bg-sidebar: #0F3E44;
    --bg-header: #FFFFFF;
    --bg-card: #FFFFFF;
    --bg-input: #F4F8F8;

    --border-color: #DFE7E7;
    --border-light: #C9D6D7;

    --text-primary: #1C2A2C;
    --text-secondary: #4A5C5E;
    --text-muted: #6F7F81;
    --text-accent: #12484F;

    /* Marque */
    --color-primary: #12484F;
    --color-primary-hover: #0E3A40;
    --color-primary-dark: #0B2F34;
    --color-primary-wash: #E4EEEF;
    --color-accent: #C97F3E;
    --color-accent-hover: #B06E32;
    --color-accent-ink: #965C26;
    --color-accent-wash: #FAF0E6;
    --color-accent-line: #EDD8C1;

    /* Status colors */
    --color-success: #2F7D62;
    --color-success-wash: #E7F2ED;
    --color-warning: #B0761A;
    --color-warning-wash: #F9F0DE;
    --color-danger: #B03A2E;
    --color-danger-wash: #F9E9E6;
    --color-info: #12484F;
    --color-purple: #C97F3E;

    /* Barre laterale */
    --sidebar-text: #A9C2C4;
    --sidebar-text-muted: #6F9296;
    --sidebar-text-strong: #FFFFFF;
    --sidebar-hover-bg: rgba(255, 255, 255, 0.07);
    --sidebar-active-bg: rgba(255, 255, 255, 0.12);
    --sidebar-title: #7FA5A9;

    /* Spacing */
    --sidebar-width: 260px;
    --sidebar-collapsed-width: 60px;
    --header-height: 56px;

    /* Transitions */
    --transition-fast: 0.15s ease;
    --transition-normal: 0.25s ease;

    /* Radius */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
}

/* =============================================
   2. BASE
   ============================================= */
html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    height: 100dvh; /* dynamic viewport height - fallback ci-dessus pour anciens navigateurs */
    overflow: hidden;
    font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    background-color: var(--bg-body);
    color: var(--text-primary);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--text-primary);
    margin-top: 0;
    font-weight: 600;
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.25rem; margin-bottom: 1rem; }
h4 { font-size: 1.1rem; color: var(--text-accent); margin-bottom: 0.75rem; }

a { color: var(--text-accent); text-decoration: none; }
a:hover { color: #8FB6BA; text-decoration: underline; }

/* Alignement vertical des icones dans les boutons */
.e-btn .e-icons { vertical-align: middle; }
.e-btn .e-btn-icon { vertical-align: middle; }

/* =============================================
   3. LAYOUT PRINCIPAL (CSS Grid)
   ============================================= */

/* Shell : grille 2 lignes x 2 colonnes, remplit 100% du viewport */
.app-shell {
    display: grid;
    grid-template-rows: var(--header-height) 1fr;
    grid-template-columns: var(--sidebar-width) 1fr;
    grid-template-areas:
        "header header"
        "sidebar main";
    height: 100vh;
    height: 100dvh; /* dynamic viewport height */
    overflow: hidden;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

.app-shell.sidebar-collapsed {
    grid-template-columns: var(--sidebar-collapsed-width) 1fr;
}

/* Header */
.app-header {
    grid-area: header;
    height: var(--header-height);
    background: var(--bg-header);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    padding: 0 20px;
    z-index: 1000;
    gap: 16px;
    box-sizing: border-box;
}

.app-header .logo {
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--text-accent);
    white-space: nowrap;
}

/* Nom du cabinet courant affiche dans le header */
.app-header .tenant-name {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--text-primary);
    font-size: 0.95rem;
    font-weight: 500;
    white-space: nowrap;
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-header .tenant-name-sep {
    display: inline-block;
    width: 1px;
    height: 22px;
    background: var(--border-color);
    margin: 0 4px;
}

.app-header .tenant-name-icon {
    color: var(--text-muted);
    font-size: 14px;
}

.app-header .tenant-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Sur petit ecran, on masque le nom du cabinet pour gagner de la place */
@media (max-width: 900px) {
    .app-header .tenant-name {
        display: none;
    }
}

.app-header .search-bar {
    flex: 1;
    max-width: 400px;
}

.app-header .header-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
}

.header-btn {
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 6px;
    border-radius: var(--radius-sm);
    position: relative;
    font-size: 1.1rem;
}
.header-btn:hover { color: var(--text-primary); background: var(--bg-surface-hover); }

/* Pill de setup : indicateur de configuration dans le header */
.header-btn.setup-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    font-size: 0.78rem;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(135deg, #12484F 0%, #B06E32 100%);
    border-radius: 14px;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.header-btn.setup-pill:hover {
    background: linear-gradient(135deg, #0E3A40 0%, #8E5726 100%);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(18, 72, 79, 0.3);
}
.header-btn.setup-pill .e-icons { font-size: 0.9rem; }
.setup-pill-pct { font-size: 0.78rem; font-weight: 700; letter-spacing: 0.02em; }

.notif-badge {
    position: absolute;
    top: 0;
    right: 0;
    width: 8px;
    height: 8px;
    background: var(--color-danger);
    border-radius: 50%;
}

/* Pastille de l'utilisateur connecte (21/09/2026) : initiales, nom complet, role.
   L'adresse de connexion reste en infobulle. */
.user-chip {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    max-width: 260px;
    padding: 3px 14px 3px 3px;
    border: 1px solid var(--border-color);
    border-radius: 999px;
    background: var(--bg-card);
    cursor: default;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.user-chip:hover {
    border-color: var(--color-primary);
    box-shadow: 0 2px 10px rgba(18, 72, 79, 0.15);
}
.user-chip-avatar {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: linear-gradient(135deg, #12484F 0%, #B06E32 100%);
    color: #fff;
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}
.user-chip-texte {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.2;
}
.user-chip-nom,
.user-chip-role {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.user-chip-nom {
    color: var(--text-primary);
    font-size: 0.82rem;
    font-weight: 600;
}
.user-chip-role {
    color: var(--text-secondary);
    font-size: 0.64rem;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
}
/* Barre etroite : la pastille seule ; nom et role restent dans l'infobulle du navigateur. */
@media (max-width: 1024px) {
    .user-chip { padding: 3px; gap: 0; }
    .user-chip-texte { display: none; }
}

.lang-selector {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    outline: none;
}
.lang-selector:hover { border-color: var(--color-primary); color: var(--color-primary); }
.lang-selector option { background: var(--bg-card); color: var(--text-primary); }

/* Sidebar */
.app-sidebar {
    grid-area: sidebar;
    background: var(--bg-sidebar);
    /* Pas de --border-light ici : la barre est sombre dans les deux themes,
       un filet gris clair dessinerait un lisere visible sur le petrole. */
    border-right: 1px solid rgba(0, 0, 0, 0.18);
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 900;
}
.app-sidebar::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.16); }

.app-sidebar.collapsed {
    /* la largeur est geree par grid-template-columns du parent */
}

.app-sidebar::-webkit-scrollbar { width: 4px; }
.app-sidebar::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 2px; }

/* Main content - seule zone scrollable */
.app-main {
    grid-area: main;
    /* LA MARGE HAUTE PASSE PAR UN JETON, ET CE N'EST PAS UN ORNEMENT. Un
       en-tete de grille en "position: sticky" s'ancre sur la boite de CONTENU
       de la zone defilante -- donc APRES ce padding. Il se pose alors trop bas
       et laisse une bande libre au-dessus de lui, DANS la zone qui defile : les
       lignes y passent a decouvert. La regle de l'en-tete collant compense
       cette valeur exacte ; les deux doivent donc lire le meme jeton, sinon
       elles derivent en silence. */
    padding: var(--app-main-padding-y) 24px;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Breadcrumbs */
.breadcrumbs {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 16px;
}
.breadcrumbs a { color: var(--text-secondary); }
.breadcrumbs a:hover { color: var(--text-accent); text-decoration: none; }
.breadcrumbs .separator { color: var(--text-muted); }

/* =============================================
   4. CARDS
   ============================================= */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 16px;
    margin-bottom: 16px;
}

/* Ligne de detail label/valeur (fiches dossier, facture, etc.) */
.detail-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-color);
    gap: 12px;
}
.detail-row:last-child { border-bottom: none; }
.detail-label {
    color: var(--text-muted);
    font-size: 0.85rem;
    min-width: 120px;
    flex-shrink: 0;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.card-header h4 { margin: 0; }

/* =============================================
   5. KPI CARDS
   ============================================= */
.kpi-row {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 20px;
}

.kpi-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 16px 24px;
    min-width: 140px;
    text-align: center;
    transition: border-color var(--transition-fast);
}
.kpi-card.clickable:hover { border-color: var(--text-accent); }

.kpi-value {
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--text-accent);
    line-height: 1.2;
}

.kpi-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin-top: 4px;
}

/* Smaller KPI variant */
.kpi-card-sm { background: var(--bg-card); border-radius: var(--radius-md); padding: 10px 16px; text-align: center; border: 1px solid var(--border-color); }
.kpi-value-sm { font-size: 1.2rem; font-weight: 700; color: var(--text-accent); }
.kpi-label-sm { font-size: 0.75rem; color: var(--text-secondary); }

/* =============================================
   6. STATUS BADGES
   ============================================= */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 12px;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.badge-open, .badge-todo       { background: rgba(34,197,94,0.15); color: var(--color-success); }
.badge-inprogress              { background: rgba(34, 104, 112,0.15); color: var(--color-info); }
.badge-onhold, .badge-pending  { background: rgba(245,158,11,0.15); color: var(--color-warning); }
.badge-closed, .badge-done     { background: rgba(100,116,139,0.15); color: var(--text-muted); }
.badge-overdue, .badge-critical{ background: rgba(239,68,68,0.15); color: var(--color-danger); }
.badge-draft                   { background: rgba(216, 147, 85,0.15); color: var(--color-purple); }
.badge-sent, .badge-submitted  { background: rgba(34, 104, 112,0.15); color: var(--color-info); }
.badge-paid, .badge-validated  { background: rgba(34,197,94,0.15); color: var(--color-success); }
.badge-cancelled               { background: rgba(100,116,139,0.1); color: var(--text-muted); text-decoration: line-through; }
/* Niveau de risque « Unknown » : un mandat hors du champ LBC-FT n'est pas
   gradue. Ce n'est ni un brouillon ni un risque faible -- c'est l'absence
   d'evaluation, et elle se lit comme telle. */
.badge-unknown                 { background: rgba(100,116,139,0.15); color: var(--text-muted); font-style: italic; }

/* =============================================
   7. TIMELINE
   ============================================= */
.timeline {
    position: relative;
    padding-left: 30px;
}

.timeline::before {
    content: '';
    position: absolute;
    left: 12px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--border-color);
}

.timeline-item {
    position: relative;
    margin-bottom: 16px;
    padding: 12px 16px;
    background: var(--bg-card);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-color);
}

.timeline-item::before {
    content: '';
    position: absolute;
    left: -24px;
    top: 16px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--text-accent);
    border: 2px solid var(--bg-body);
}

.timeline-item.note::before { background: var(--color-info); }
.timeline-item.create::before { background: var(--color-success); }
.timeline-item.update::before { background: var(--color-warning); }
.timeline-item.delete::before { background: var(--color-danger); }

.timeline-date {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 4px;
}

.timeline-author {
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.timeline-content {
    color: var(--text-primary);
    margin-top: 4px;
}

/* =============================================
   7b. INDETERMINATE PROGRESS BAR
   ============================================= */
.indeterminate-progress {
    height: 3px;
    width: 100%;
    background: var(--border-color);
    border-radius: 2px;
    overflow: hidden;
    position: relative;
}

.indeterminate-progress-bar {
    height: 100%;
    width: 30%;
    background: var(--text-accent);
    border-radius: 2px;
    position: absolute;
    animation: indeterminate 1.4s ease-in-out infinite;
}

@keyframes indeterminate {
    0% { left: -30%; }
    100% { left: 100%; }
}

/* =============================================
   8. DOSSIER VIEW - 2 COLONNES
   ============================================= */
.dossier-layout {
    display: flex;
    gap: 20px;
}

.dossier-main {
    flex: 1;
    min-width: 0;
}

.dossier-sidebar {
    width: 300px;
    flex-shrink: 0;
}

.dossier-sidebar .card {
    position: sticky;
    top: calc(var(--header-height) + 20px);
}

/* UNE LIGNE « LIBELLE A GAUCHE, VALEUR A DROITE » -- ET ELLE N'APPARTIENT PAS
   A LA COLONNE DE DROITE.

   LE DEFAUT QUE CELA FERME. Ces trois regles etaient ecrites
   « .dossier-sidebar .info-row » : elles ne s'appliquaient QUE dans le panneau
   de droite. Le meme balisage employe ailleurs se rendait SANS AUCUN STYLE --
   le libelle et le montant colles l'un a l'autre, « Forfait vendu5 000,00 EUR ».
   Quatre panneaux etaient touches : abonnement, honoraire de resultat et
   rentabilite du forfait dans la colonne principale de DossierView, plus
   l'ecran ModuleBilling/InvoiceFromSuccessFee qui n'a pas de colonne de droite
   du tout.

   C'EST LE MEME PIEGE QUE LES CLASSES « dp-dd-* » DU SELECTEUR DE DOSSIER :
   un balisage reprend des classes qui n'existent que sous un parent, et se rend
   nu partout ailleurs. Rien ne le signale -- ni le compilateur, ni un test :
   la page s'affiche, elle est seulement illisible. */
.info-row {
    display: flex;
    justify-content: space-between;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-color);
}

.info-label {
    color: var(--text-secondary);
}

.info-value {
    color: var(--text-primary);
    font-weight: 500;
    text-align: right;
}

.info-value a {
    color: var(--text-accent);
}

/* LA COLONNE DE DROITE EST COMPACTE, LA COLONNE PRINCIPALE NE L'EST PAS. C'est
   la SEULE chose qui restait proprement specifique a la barre laterale. */
.dossier-sidebar .info-row {
    font-size: 0.85rem;
}

/* =============================================
   9. NAV MENU
   ============================================= */
.nav-menu {
    padding: 8px;
    font-size: 0.85rem;
}

.nav-section {
    padding: 0 4px;
    margin-bottom: 4px;
}

/* La barre laterale est sombre dans les DEUX themes : elle a donc ses propres
   jetons. Utiliser ici --text-secondary / --border-light donnerait du texte
   sombre sur fond petrole, illisible en theme clair. */
.nav-section-title {
    color: var(--sidebar-title);
    font-weight: 600;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 12px 8px 4px;
    border-top: 1px solid rgba(255, 255, 255, 0.09);
    margin-top: 4px;
    display: flex;
    align-items: center;
    gap: 6px;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--sidebar-text);
    text-decoration: none;
    padding: 6px 8px;
    border-radius: var(--radius-sm);
    transition: all var(--transition-fast);
    white-space: nowrap;
    overflow: hidden;
}
.nav-link:hover { color: var(--sidebar-text-strong); background: var(--sidebar-hover-bg); text-decoration: none; }
/* L'element actif est le seul endroit de la navigation ou l'abricot apparait :
   un filet a gauche plutot qu'un aplat, pour qu'il signale sans crier. */
.nav-link.active {
    color: var(--sidebar-text-strong);
    background: var(--sidebar-active-bg);
    font-weight: 600;
    box-shadow: inset 2px 0 0 var(--color-accent);
}
.nav-link.active .nav-icon { color: var(--color-accent); }

.nav-icon { font-size: 1rem; width: 20px; text-align: center; flex-shrink: 0; }

/* =============================================
   10. FORMS & DIALOGS
   ============================================= */
.form-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 12px;
}

.form-group label {
    font-size: 0.8rem;
    color: var(--text-secondary);
    font-weight: 500;
}

.form-row {
    display: flex;
    gap: 12px;
}

.form-row > * { flex: 1; }

/* =============================================
   11. MISC
   ============================================= */
.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
}

.page-header h3 { margin: 0; }

.empty-state {
    text-align: center;
    padding: 40px;
    color: var(--text-muted);
}

.clickable { cursor: pointer; }
.clickable:hover { color: var(--text-accent); }

/* Scrollbar global */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* =============================================
   12. TRANSITIONS & ANIMATIONS
   ============================================= */
.fade-in {
    animation: fadeIn var(--transition-normal);
}

@keyframes fadeIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* LE SOULEVEMENT AU SURVOL EST RESERVE AUX CARTES CLIQUABLES.

   CE QU'IL FAISAIT AVANT. La regle portait sur « .card » tout court,
   c'est-a-dire sur les 400 cartes du logiciel : le simple passage de la
   souris sur un panneau d'information le decollait de deux pixels et lui
   posait une ombre. Or une ombre et un mouvement sont la promesse d'un clic.
   Sur une carte qui n'ecoute rien, la promesse n'est pas tenue, et le
   deplacement devient un tremblement sous le curseur pendant la lecture.

   LE MARQUEUR EXISTE DEJA, ET C'EST « .clickable » : il pose le curseur en
   main juste au-dessus, et les cartes qui ecoutent vraiment le portent deja.
   Les cartes cliquables qui ont leur propre classe -- .dossier-card,
   .party-card, .message-card -- gardent le leur, ecrit dans leur composant :
   elles ne sont pas concernees par cette regle et ne l'ont jamais ete.

   LA TRANSITION EST SUR L'ETAT AU REPOS, ET NON SUR LE SURVOL : declaree
   dans le :hover, elle n'animait que l'aller, et le retour tombait d'un
   coup. */
.card.clickable, .kpi-card.clickable {
    transition: transform var(--transition-normal), box-shadow var(--transition-normal);
}

.card.clickable:hover, .kpi-card.clickable:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}

/* Smooth transitions sur les boutons */
.e-btn {
    transition: all var(--transition-fast) !important;
}

/* PAS D'ANIMATION CSS SUR LES DIALOGUES (19/09/2026, signale par l'utilisateur :
   « la fenetre apparait puis flash, comme ouverte, fermee puis reouverte »).
   Syncfusion anime deja l'ouverture (fondu, ~400 ms). Une animation CSS sur
   .e-dialog repartait de l'opacite 0 A LA FIN de ce fondu -- le dialogue passe de
   e-popup-close a e-popup-open, ce qui relance l'animation CSS -- : mesure dans le
   navigateur, FadeIn a 275 ms puis dialogSlideIn a 674 ms sur le meme element.
   Tous les dialogues du logiciel clignotaient. Une seule animation : celle du composant. */

/* Tab content animation */
.e-tab .e-content .e-item.e-active {
    animation: fadeIn 0.2s ease;
}

/* Badge pulse pour les alertes */
.notif-badge {
    animation: pulse 2s infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* =============================================
   13. RESPONSIVE MOBILE
   ============================================= */

/* Tablette (< 1024px) */
@media (max-width: 1024px) {
    /* LE REPLI DE LA BARRE NE SE FAIT PAS ICI, ET C'EST DELIBERE. Forcer la
       colonne de grille a la largeur repliee laisserait le MENU deplie
       dedans : il recoit son etat par un parametre de composant, pas par une
       classe, et ses libelles entiers se retrouveraient ecrases dans 60 px puis
       coupes par « overflow-x: hidden ». MainLayout replie sous ce meme seuil,
       et la grille suit alors « .app-shell.sidebar-collapsed » comme partout
       ailleurs. */
    .dossier-layout {
        flex-direction: column;
    }
    .dossier-sidebar {
        width: 100%;
    }
    .dossier-sidebar .card {
        position: static;
    }
    .kpi-row {
        gap: 8px;
    }
    .kpi-card {
        min-width: 110px;
        padding: 12px 16px;
    }
    .kpi-value {
        font-size: 1.4rem;
    }
}

/* Mobile (< 768px) */
@media (max-width: 768px) {
    .app-header {
        padding: 0 12px;
    }
    .app-header .search-bar {
        display: none;
    }
    .app-header .logo {
        font-size: 1rem;
    }
    /* LES DEUX ETATS SONT NOMMES, ET IL LE FAUT.
       « .app-shell.sidebar-collapsed » porte deux classes : elle l'emporte sur
       « .app-shell » ou qu'elle soit ecrite, et elle aurait rendu sa colonne de
       60 px a une barre qui, elle, est sortie de l'ecran -- une bande vide a
       gauche de chaque page. */
    .app-shell,
    .app-shell.sidebar-collapsed {
        grid-template-columns: 0 1fr;
    }
    .app-sidebar {
        position: fixed;
        top: var(--header-height);
        left: 0;
        bottom: 0;
        width: var(--sidebar-width);
        transform: translateX(-100%);
        transition: transform var(--transition-normal);
        z-index: 1100;
    }
    /* LE TIROIR SUIT LE BOUTON « MENU », ET NON UNE CLASSE FANTOME. La regle
       d'origine ouvrait sur « .app-sidebar.mobile-open », que rien dans
       l'application n'ecrit : la barre se serait cachee sans aucun moyen de la
       rouvrir. MainLayout pose « sidebar-collapsed » sur la coquille quand on
       clique « Menu » -- c'est cet etat-la, le seul qui existe, qui ferme le
       tiroir. Et sur un ecran de moins de 768 px, MainLayout demarre REPLIE :
       sans quoi le menu couvrirait la page a chaque ouverture. */
    .app-shell:not(.sidebar-collapsed) .app-sidebar {
        transform: translateX(0);
        box-shadow: 0 0 24px rgba(0, 0, 0, 0.35);
    }
    /* LA MARGE CHANGE SUR PETIT ECRAN, ET L'EN-TETE COLLANT DOIT SUIVRE. Le
       jeton est redefini ici plutot que le padding ecrit en dur : sans cela,
       la compensation du "top" resterait a 20px et une bande de 8px se
       rouvrirait, dans laquelle les lignes defileraient a decouvert. */
    :root {
        --app-main-padding-y: 12px;
    }
    .app-main {
        padding: var(--app-main-padding-y) 12px;
        padding-bottom: var(--app-main-padding-y);
    }
    .page-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 8px;
    }
    .form-row {
        flex-direction: column;
    }
    .kpi-row {
        flex-direction: column;
    }
    .kpi-card {
        min-width: auto;
    }
    h3 {
        font-size: 1.1rem;
    }
}

/* Petit mobile (< 480px) */
@media (max-width: 480px) {
    .app-header .header-actions {
        gap: 6px;
    }
    .badge {
        font-size: 0.65rem;
        padding: 1px 6px;
    }
}

/* =============================================
   PWA / Mobile optimisations
   ============================================= */

/* Safe area pour les appareils avec encoche (iPhone) */
@supports (padding-top: env(safe-area-inset-top)) {
    .app-header {
        padding-top: env(safe-area-inset-top);
    }
    .nav-menu {
        padding-bottom: env(safe-area-inset-bottom);
    }
}

/* Bouton installation PWA */
#pwa-install-btn {
    display: none;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    background: var(--color-primary);
    color: white;
    border: none;
    border-radius: 6px;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background 0.2s;
}
#pwa-install-btn:hover {
    background: var(--color-primary-hover, #0E3A40);
}

/* Touch-friendly sur mobile */
@media (max-width: 768px) {
    /* Boutons plus grands pour le tactile */
    .e-btn, button {
        min-height: 40px;
    }

    /* Grilles : scroll horizontal */
    .e-grid {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* Cards en colonne */
    .dossier-layout {
        flex-direction: column !important;
    }
    .dossier-main, .dossier-sidebar {
        width: 100% !important;
    }

    /* Formulaires : champs pleine largeur */
    .card div[style*="grid-template-columns"] {
        grid-template-columns: 1fr !important;
    }

    /* KPI cards : 2 colonnes au lieu de 4-5 */
    div[style*="grid-template-columns:repeat(4"] ,
    div[style*="grid-template-columns:repeat(5"] {
        grid-template-columns: repeat(2, 1fr) !important;
    }

    /* Detail rows : empiler */
    .detail-row {
        flex-direction: column;
        gap: 2px;
    }

    /* Invoice preview : pleine largeur */
    .invoice-preview {
        padding: 16px !important;
    }
}

/* Mode standalone PWA : pas de barre d'adresse */
@media (display-mode: standalone) {
    .app-header {
        /* Barre de titre draggable pour PWA desktop */
        -webkit-app-region: drag;
    }
    .app-header button, .app-header a, .app-header .header-actions {
        -webkit-app-region: no-drag;
    }
}

/* Eviter le zoom sur les inputs en iOS */
@media screen and (max-width: 768px) {
    input[type="text"],
    input[type="email"],
    input[type="number"],
    input[type="tel"],
    textarea,
    select {
        font-size: 16px !important;
    }
}

/* Error UI */
#blazor-error-ui {
    background: var(--color-danger);
    color: white;
    padding: 0.5rem 1rem;
    position: fixed;
    bottom: 0;
    width: 100%;
    z-index: 2000;
    display: none;
}

/* =============================================
   Mobile bottom navigation (< 768px uniquement)
   Pattern Outlook/Gmail mobile : 5 raccourcis fixes
   en bas de l'ecran. Cache sur desktop.
   ============================================= */
.mobile-bottom-nav {
    display: none; /* visible uniquement en mobile, cf @media */
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--bg-card, #1a1f3a);
    border-top: 1px solid var(--border-color, #2a3050);
    padding: 4px 0 calc(4px + env(safe-area-inset-bottom, 0px));
    z-index: 1000;
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.15);
    justify-content: space-around;
    align-items: stretch;
    height: 56px;
}
.mb-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    text-decoration: none;
    color: var(--text-muted, #94a3b8);
    font-size: 10px;
    padding: 4px 2px;
    -webkit-tap-highlight-color: transparent;
    transition: color 0.12s ease;
    border-radius: 8px;
    margin: 0 2px;
}
.mb-nav-item:hover, .mb-nav-item:active {
    color: var(--text-accent, #3C848B);
    background: rgba(27, 92, 100, 0.06);
}
.mb-nav-item.active {
    color: var(--text-accent, #3C848B);
    font-weight: 600;
}
.mb-nav-item .e-icons {
    font-size: 20px;
    line-height: 1;
}
.mb-nav-label {
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

@media (max-width: 768px) {
    .mobile-bottom-nav { display: flex; }
    /* Reserver l'espace en bas pour eviter que la nav ne masque le contenu */
    .app-main {
        padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px)) !important;
    }
    /* Sur mobile : la sidebar verticale principale Norvy est cachee
       quand on a la bottom nav (sinon redondance). L'utilisateur fait
       Toggle pour la sortir s'il a besoin du menu complet. */
    .app-sidebar:not(.collapsed) {
        /* On ne cache pas, on laisse l'utilisateur la collapse via le bouton header */
    }
}

/* ====================================================================
   Syncfusion DocumentEditor toolbar - alignement uniforme
   --------------------------------------------------------------------
   Probleme : icones (font-icons) et labels n'ont pas la meme baseline
   selon le type d'item, resultant en alignement vertical heterogene.
   Solution : forcer une grille rigide (icone 22px haut, label 14px bas).
   CSS GLOBAL car ::deep en scoped CSS n'atteint pas les enfants
   Syncfusion qui sortent du scope du composant Blazor.
==================================================================== */
.e-documenteditorcontainer .e-de-ctnr-toolbar .e-toolbar-items,
.e-documenteditorcontainer .e-toolbar-items {
    align-items: stretch !important;
}

.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item {
    height: 64px !important;
    display: inline-flex !important;
    align-items: center !important;
    padding: 0 !important;
}

.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn {
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 4px !important;
    padding: 8px 10px !important;
    min-width: 64px !important;
    height: 100% !important;
    box-sizing: border-box !important;
}

/* Icone : taille FIXE pour eviter les variations entre font-icons / SVG */
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn .e-icons,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn .e-btn-icon {
    font-size: 18px !important;
    line-height: 1 !important;
    width: 22px !important;
    height: 22px !important;
    margin: 0 !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
}

/* Label : taille FIXE sur TOUT span/element non-icone du bouton.
   Syncfusion utilise des classes variables selon le type d'item
   (.e-tbar-btn-text / .e-text / direct child span). On cible tous
   les spans du bouton sauf les conteneurs d'icone. */
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn .e-tbar-btn-text,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn .e-text,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn span:not(.e-icons):not(.e-btn-icon):not(.e-icon-btn) {
    font-size: 11px !important;
    line-height: 14px !important;
    font-weight: 400 !important;
    margin: 0 !important;
    padding: 0 !important;
    text-align: center !important;
    white-space: nowrap !important;
    color: inherit !important;
    font-family: inherit !important;
}

/* Le bouton lui-meme doit aussi avoir font-size:11px en cascade
   (au cas ou un item utilise du textnode direct sans span).
   Note critique : certains items toolbar Syncfusion (PageSetup,
   Break, RestrictEditing, FormFields...) sont des e-dropdown-btn
   avec la classe specifique 'e-de-bzr-button'. Syncfusion definit
   '.e-de-ctn .e-de-bzr-button { font-size: 14px !important }' qui
   ecrase tout. On cible donc directement cette classe pour gagner
   la cascade en specificite + !important. */
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-tbar-btn,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-dropdown-btn,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-de-bzr-button,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item button,
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-btn,
.e-documenteditorcontainer .e-de-ctnr-toolbar .e-de-bzr-button,
.e-documenteditorcontainer .e-de-ctn .e-de-bzr-button {
    font-size: 11px !important;
}

/* Layout uniforme des dropdown-btn (PageSetup etc.) : pareil que
   les e-tbar-btn standards : icone au-dessus, label en bas. */
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item .e-dropdown-btn {
    display: flex !important;
    flex-direction: column !important;
    align-items: center !important;
    justify-content: center !important;
    gap: 4px !important;
    padding: 8px 10px !important;
    min-width: 64px !important;
    height: 100% !important;
    box-sizing: border-box !important;
    width: auto !important;
    line-height: 14px !important;
    font-weight: 400 !important;
}

/* Separateur vertical entre groupes : meme hauteur que les items */
.e-documenteditorcontainer .e-toolbar-items .e-toolbar-item.e-separator {
    height: 64px !important;
    align-self: center !important;
}

/* Chevrons d'overflow (< / >) au meme niveau */
.e-documenteditorcontainer .e-toolbar .e-hor-nav,
.e-documenteditorcontainer .e-toolbar .e-toolbar-pop {
    height: 64px !important;
    align-self: center !important;
}

/* ====================================================================
   Syncfusion DropDownList items - DossierPicker etc.
   --------------------------------------------------------------------
   Probleme : padding excessif (default Syncfusion ~16px x2) + hover et
   selected ont le meme bg gris -> impossible de distinguer.
   Solution : compact + distinguer hover (bleu pale) et active (bleu
   marque + border-left primary).
   GLOBAL CSS car les .e-popup sortent du scope Blazor.
==================================================================== */
.e-popup .e-list-item,
.e-dropdownbase .e-list-item {
    padding: 8px 14px !important;
    line-height: 1.3 !important;
    min-height: 0 !important;
    border-left: 3px solid transparent !important;
    transition: background 0.1s ease, border-color 0.1s ease !important;
}
/* Hover SEUL (pas selectionne) : bleu tres pale */
.e-popup .e-list-item.e-hover:not(.e-active),
.e-popup .e-list-item:hover:not(.e-active),
.e-dropdownbase .e-list-item.e-hover:not(.e-active),
.e-dropdownbase .e-list-item:hover:not(.e-active) {
    background: #F1F7F7 !important;
}
/* Active/selected : bleu marque + border gauche primary */
.e-popup .e-list-item.e-active,
.e-popup .e-list-item.e-active:hover,
.e-dropdownbase .e-list-item.e-active,
.e-dropdownbase .e-list-item.e-active:hover {
    background: #DCE9EA !important;
    color: #0B2F34 !important;
    border-left-color: #226870 !important;
}
/* Group header (DOSSIERS ACTIFS / ARCHIVES) plus discret */
.e-popup .e-list-group-item,
.e-dropdownbase .e-list-group-item {
    background: #f1f5f9 !important;
    color: #64748b !important;
    font-size: 10px !important;
    text-transform: uppercase !important;
    letter-spacing: 0.06em !important;
    font-weight: 700 !important;
    padding: 6px 14px !important;
    line-height: 1.3 !important;
}

/* =============================================
   Chronometres de la barre superieure.
   Les deux moities forment un seul objet encadre : un inverseur, pas deux
   boutons independants.
   ============================================= */
.timer-seg {
    display: flex;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    overflow: hidden;
    flex: none;
}
.timer-half {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 9px;
    font-size: 12px;
    line-height: 1;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
}
.timer-half:hover { background: var(--bg-surface-hover); }
.timer-div { width: 1px; background: var(--border-color); flex: none; }
.timer-num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    letter-spacing: .3px;
}
.timer-icon { font-size: 9px; }
.timer-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }

.timer-idle .timer-num { color: var(--text-muted); }

.timer-running { background: rgba(34, 197, 94, .08); }
.timer-running .timer-dot { background: var(--color-success); }
.timer-running .timer-num { color: var(--text-primary); font-weight: 600; }

.timer-attention { background: rgba(245, 158, 11, .08); }
.timer-attention .timer-dot { background: var(--color-warning); }
.timer-attention .timer-num { color: var(--text-primary); font-weight: 600; }

.timer-anomaly { background: rgba(239, 68, 68, .10); }
.timer-anomaly .timer-dot { background: var(--color-danger); }
.timer-anomaly .timer-num { color: var(--color-danger); font-weight: 600; }

.timer-paused { background: rgba(245, 158, 11, .08); }
.timer-paused .timer-dot { background: var(--color-warning); }
.timer-paused .timer-num { color: var(--text-secondary); }

/* La barre porte deja la recherche, le cabinet, les notifications, le theme,
   la langue et l'utilisateur. Sur ecran etroit on replie sur le seul chrono
   actif, et sur rien du tout si aucun ne tourne. */
@media (max-width: 900px) {
    .timer-seg .timer-half.timer-idle,
    .timer-seg .timer-div { display: none; }
}

.timer-measure {
    display: flex;
    align-items: center;
    gap: 11px;
    background: rgba(34, 197, 94, .06);
    border: 1px solid rgba(34, 197, 94, .25);
    border-radius: var(--radius-md);
    padding: 10px 13px;
}
.timer-measure-bad {
    background: rgba(239, 68, 68, .06);
    border-color: rgba(239, 68, 68, .33);
}
.timer-measure-big {
    color: var(--text-primary);
    font-size: 21px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.timer-measure-sub { color: var(--text-secondary); font-size: 11.5px; line-height: 1.45; }

/* =============================================
   Dialogue d'encodage d'un chronometre.
   Mise en page en colonne unique, champs espaces regulierement, montant
   affiche sur la meme ligne que la duree pour que l'avocat voie l'effet de
   son choix sans deplacer le regard.
   ============================================= */
.tdlg {
    display: flex;
    flex-direction: column;
    gap: 16px;
    padding: 4px 2px 2px;
}
.tdlg-loading {
    padding: 28px 10px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
}
.tdlg-field { display: flex; flex-direction: column; gap: 6px; }
.tdlg-label {
    color: var(--text-secondary);
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .5px;
    margin: 0;
}
.tdlg-req { color: var(--color-danger); }
.tdlg-presets { display: flex; gap: 6px; flex-wrap: wrap; }
.tdlg-inline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tdlg-unit { color: var(--text-muted); font-size: 12.5px; }
.tdlg-amount { margin-left: auto; font-size: 13px; color: var(--text-primary); text-align: right; }
.tdlg-hint { color: var(--text-muted); font-size: 11.5px; font-weight: 400; }
.tdlg-warn { color: var(--color-danger); }
.tdlg-check { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-primary); }

/* Repliage "Plus d'options" : un bouton, pas un div cliquable, pour rester
   atteignable au clavier. */
.tdlg-more {
    align-self: flex-start;
    background: none;
    border: none;
    padding: 2px 0;
    cursor: pointer;
    color: var(--text-accent);
    font-size: 12.5px;
}
.tdlg-more:hover { text-decoration: underline; }
.tdlg-extra {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-surface);
}

/* =============================================
   99. THEME SYNCFUSION — REDEFINITION DE L'ACCENT

   Syncfusion charge son propre theme (tailwind3.css, voir App.razor) : c'est
   LUI qui teinte les boutons primaires, la selection des grilles, les cases a
   cocher, le focus des champs et les onglets actifs. Sans ce bloc, toute
   l'application resterait indigo quelle que soit la palette de Norvy.

   app.css est charge APRES le theme, et ces regles ciblent :root comme lui :
   a specificite egale, le dernier declare gagne. Ne pas inverser l'ordre des
   deux <link> dans App.razor.

   On ne redefinit QUE la famille "primary". Les couleurs semantiques de
   Syncfusion (succes / avertissement / danger) restent les siennes, alignees
   sur les notres par les blocs plus haut : une pastille d'erreur ne doit
   jamais prendre la teinte de la marque.
   ============================================= */
:root,
[data-theme="light"],
[data-theme="dark"] {
    --color-sf-primary: var(--color-primary);
    --color-sf-primary-bg-color: var(--color-primary);
    --color-sf-primary-bg-color-hover: var(--color-primary-hover);
    --color-sf-primary-bg-color-focus: var(--color-primary-hover);
    --color-sf-primary-bg-color-pressed: var(--color-primary-dark);
    --color-sf-primary-bg-color-disabled: var(--color-primary-wash);

    --color-sf-primary-border-color: var(--color-primary);
    --color-sf-primary-border-color-hover: var(--color-primary-hover);
    --color-sf-primary-border-color-focus: var(--color-primary-hover);
    --color-sf-primary-border-color-pressed: var(--color-primary-dark);
    --color-sf-primary-border-color-disabled: var(--color-primary-wash);

    --color-sf-primary-dark: var(--color-primary-dark);
    --color-sf-primary-darker: var(--color-primary-dark);
    --color-sf-primary-light: var(--color-primary-hover);
    --color-sf-primary-lighter: var(--color-primary-wash);
    --color-sf-primary-outline: var(--color-accent);

    --color-sf-primary-text: #ffffff;
    --color-sf-primary-text-color: #ffffff;
    --color-sf-primary-text-hover: #ffffff;
    --color-sf-primary-text-focus: #ffffff;
    --color-sf-primary-text-pressed: #ffffff;
    --color-sf-primary-text-disabled: #ffffff;
}

/* L'abricot ne sert que d'accent d'ETAT, jamais de couleur de remplissage.
   Ici : l'anneau de focus, seul endroit ou il doit primer sur le petrole
   pour que la position du curseur se voie immediatement. */
.e-input-group.e-input-focus::before,
.e-input-group.e-input-focus::after,
.e-input-group.e-control-wrapper.e-input-focus::before,
.e-input-group.e-control-wrapper.e-input-focus::after {
    background: var(--color-accent) !important;
}

.e-btn.e-primary:focus-visible,
.e-btn:focus-visible,
.e-input-group.e-input-focus,
.e-control:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 1px;
}

/* =============================================
   LE CADRE DE FOCUS D'UNE CELLULE DE GRILLE NE SE PEINT PLUS AU CLIC.

   CE QUE C'EST. Le theme Syncfusion tailwind3 pose une OMBRE INTERNE --
   "box-shadow: 0 0 0 1px var(--color-sf-primary) inset" -- sur un selecteur
   qui se termine par ":is(:focus,:focus-visible)". Ce ":is" est la cause :
   la regle peint AUSSI au clic de souris, alors que rien ne le justifie -- la
   ligne cliquee porte deja son fond de selection.

   POURQUOI ON NE L'ENLEVE PAS AU CLAVIER. Ce cadre est alors la SEULE chose qui
   dise ou l'on se trouve dans la grille : un utilisateur qui navigue aux
   fleches perdrait sa position sans aucun repli. La restriction ci-dessous ne
   s'applique qu'au clic de souris -- verifie sur la page reelle : apres un
   vrai clic, la cellule vaut ":focus" et NE VAUT PAS ":focus-visible".

   POURQUOI LES DEUX ":not" SONT LA. Le ":is()" de Syncfusion prend la
   specificite la plus ELEVEE de ses arguments. Une premiere version de cette
   regle, ecrite sans eux, N'A RIEN CHANGE : le style calcule restait
   "rgb(18, 72, 79) 0 0 0 1px inset". Une regle CSS perdante ne produit ni
   erreur ni avertissement -- elle est simplement sans effet.

   ET AUCUN !important : la regle gagne par sa specificite, donc elle se
   laisse surcharger proprement par la suivante.
   ============================================= */
.e-grid.sf-grid :is(
    .e-headercontent th.e-headercell:not(.e-menu-item):not(.e-editedbatchcell),
    .e-headercontent td.e-rowcell:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-rowcell:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-groupcaption:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-recordplusexpand:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-recordpluscollapse:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-detailrowcollapse:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content td.e-detailrowexpand:not(.e-menu-item):not(.e-editedbatchcell),
    .e-content th.e-detailcell:not(.e-menu-item):not(.e-editedbatchcell),
    tr.e-emptyrow td:not(.e-menu-item):not(.e-editedbatchcell)
):focus:not(:focus-visible) {
    box-shadow: none;
}


/* =============================================
   LE TITRE QUE BLAZOR FOCALISE NE DESSINE PAS DE CADRE.

   CE QUI POSE CE FOCUS. Routes.razor porte
   « <FocusOnNavigate RouteData="@routeData" Selector="h1" /> » : apres CHAQUE
   navigation, Blazor pose « tabindex="-1" » sur le premier h1 de la page et
   lui donne le focus. C'est une bonne pratique d'accessibilite -- le lecteur
   d'ecran annonce ainsi le titre de la page ou l'on vient d'arriver.

   LE SYMPTOME, SIGNALE LE 28/08/2026 SUR LE PORTAIL CLIENT. Au premier
   chargement, un cadre de focus entoure le prenom du client sous « Bonjour ».
   Il disparait au premier clic. La regle etant globale, le meme cadre
   apparait sur toute page portant un h1 -- cote cabinet aussi. Mesure : le
   h1 focalise est « .portal-greet-name » sur /portal/dossiers, « .page-title »
   sur /portal/documents, et il porte bien tabindex="-1" dans les deux cas.

   POURQUOI CE N'EST PAS UNE PERTE D'ACCESSIBILITE, et pourquoi on ne garde
   PAS « :focus-visible » ici comme ailleurs dans cette feuille :

       « tabindex="-1" » EXCLUT l'element de l'ordre de tabulation.

   Aucun utilisateur au clavier ne peut donc atteindre ce titre : le cadre ne
   lui sert jamais a se reperer. Le focus, lui, RESTE -- c'est lui que le
   lecteur d'ecran suit. Seul le dessin disparait.

   On ne vise que les h1 EN tabindex="-1" : un h1 rendu focalisable a la main,
   pour une raison qu'on ignore, garde son cadre.
   ============================================= */
h1[tabindex="-1"]:focus {
    outline: none;
}

/* =============================================
   L'EN-TETE COLLANT SE CALE SUR LE HAUT DE LA ZONE DEFILANTE.

   LE DEFAUT QUE CETTE REGLE FERME, ET IL A ETE LIVRE EN PRODUCTION. Avec
   "EnableStickyHeader" seul, l'en-tete se figeait 18 px TROP BAS : la zone
   defilante ".app-main" commence a 56 px, l'en-tete se posait a 74. Entre les
   deux subsistait une bande libre, DANS la zone qui defile -- et les lignes y
   passaient a decouvert, au-dessus d'un en-tete cense les masquer. Mesure sur
   la page reelle : deux lignes visibles simultanement dans cette bande.

   POURQUOI. "position: sticky" s'ancre sur la boite de CONTENU de la zone
   defilante, c'est-a-dire APRES son padding. Syncfusion pose "top: -2px", ce
   qui donne 56 + 20 - 2 = 74. Pour plaquer l'en-tete au bord haut, il faut lui
   donner l'OPPOSE du padding : c'est ce que fait cette regle, en lisant le
   MEME jeton que ".app-main" pour que les deux ne derivent jamais.

   ET C'EST LE SEUL "!important" JUSTIFIE DU FICHIER : Syncfusion ecrit
   "top: -2px" en STYLE EN LIGNE (mesure : element.style.top vaut "-2px"), et
   un style en ligne ne se surcharge pas autrement.

   CE QUE CETTE REGLE N'A PAS CORRIGE, PARCE QUE CE N'ETAIT PAS CASSE : le fond
   de l'en-tete est deja opaque dans les deux themes -- rgb(255,255,255) en
   clair, rgb(17,24,39) en sombre -- et son z-index vaut 10. Les lignes passent
   donc bien DERRIERE lui une fois la bande fermee.

   LA LECON. Tous les releves numeriques de ce chantier passaient -- classe
   e-sticky posee, position sticky, fond opaque, z-index 10 -- et le rendu
   etait casse. Aucun n'interrogeait la seule chose qui comptait : reste-t-il
   un espace entre le haut de la zone et l'en-tete ? Une capture d'ecran le
   montrait, et personne ne l'a regardee.
   ============================================= */
.e-grid.sf-grid .e-gridheader.e-sticky {
    top: calc(-1 * var(--app-main-padding-y)) !important;
}

/* =============================================
   LE DESSIN DE LA CHAINE DE DETENTION -- KYC > BENEFICIAIRES EFFECTIFS

   POURQUOI CES REGLES SONT ICI ET NON DANS UN COMPOSANT. Elles servent DEUX
   ecrans : celui de travail, qui dessine le graphe vivant, et la relecture d'un
   instantane, qui dessine la copie figee. Le balisage, lui, est partage par le
   composant SchemaDeLaChaine.

   ET UN <style> DE COMPOSANT N'AURAIT PAS SUFFI : il n'existe que tant que le
   composant est rendu. Or l'ecran de travail pose les MEMES glyphes devant les
   noms de ses tableaux, dans un onglet ou le schema n'est pas affiche -- les
   signes y auraient perdu leur style sans que rien ne le dise.
   ============================================= */
.be-schema { display: block; font-family: inherit; }

/* LE SIGNE EST EN LIGNES ET SANS REMPLISSAGE : il prend la couleur du
   texte, donc il suit le theme clair comme le sombre sans qu'une seule
   couleur soit ecrite pour lui. */
.be-glyphe path { fill: none; stroke: currentColor; stroke-width: 1.3;
                  stroke-linecap: round; stroke-linejoin: round; }
.be-glyphe { opacity: 0.72; }
.be-glyphe-ligne { vertical-align: -2px; margin-right: 2px; }

.be-legende { list-style: none; margin: 10px 0 0; padding: 0;
              display: flex; flex-wrap: wrap; gap: 7px 26px;
              font-size: 0.8rem; color: var(--text-secondary); }
.be-legende li { display: flex; align-items: flex-start; gap: 6px;
                 max-width: 44ch; }
.be-legende .be-glyphe { flex: none; margin-top: 1px; }

.be-legende-inconnu { flex: none; display: inline-flex; align-items: center;
                      justify-content: center; width: 15px; height: 15px;
                      border: 1px dashed var(--text-muted); border-radius: 3px;
                      font-size: 0.62rem; font-weight: 700; line-height: 1;
                      color: var(--text-muted); }
.be-arete { cursor: help; }
.be-noeud { cursor: pointer; }

/* LA SELECTION ETEINT, ELLE NE CACHE PAS. Tout reste a sa place et tout
   reste lisible de pres : on retire du CONTRASTE, pas de l'information.
   Effacer une branche ferait croire qu'elle n'existe pas -- sur cet
   ecran, ce serait la faute de trop. */
.be-noeud, .be-arete { transition: opacity 120ms ease; }
.be-avec-choix .be-noeud, .be-avec-choix .be-arete { opacity: 0.16; }

/* LE NOEUD CLIQUE FAIT PARTIE DE CE QU'ON REGARDE.
   Cette regle ne rendait son opacite qu'a .be-vif -- les ANCETRES. Le noeud
   choisi, lui, recevait bien sa classe .be-choisi et son trait epaissi, mais
   restait eteint a 16 % comme le reste : on cliquait sur une boite, et c'est
   elle qui disparaissait. Le trait plus epais n'y changeait rien, il etait
   eteint avec elle. Constate le 26/08/2026. */
.be-avec-choix .be-vif,
.be-avec-choix .be-choisi { opacity: 1; }
.be-choisi rect { stroke-width: 3; }
.be-noeud:focus { outline: none; }
.be-noeud:focus rect { stroke-width: 3; }

.be-noeud rect { fill: var(--bg-card); stroke: var(--border-color); stroke-width: 1.5; }
.be-noeud text { font-size: 0.72rem; fill: var(--text-primary); }

.be-n-racine rect { fill: var(--color-primary-wash); stroke: var(--color-primary); stroke-width: 2; }
.be-n-racine text { font-weight: 600; }
/* LA PERSONNE PHYSIQUE SE DISTINGUE, et ce n'est pas decoratif : c'est
   elle que la loi cherche en dernier ressort, et l'oeil doit la trouver
   sans lire.

   CE N'EST PLUS LA BORDURE QUI PORTE CETTE DISTINCTION. Elle l'a portee
   jusqu'au 26/08/2026 -- un trait plus marque que celui des personnes
   morales -- et cet ecart de contraste faisait lire les personnes morales
   comme des boites a demi effacees, sans que rien ne le justifie a
   l'oeil. Les deux genres partagent desormais le meme trait.

   DEUX SIGNES CONTINUENT DE LES SEPARER, et ils sont plus francs qu'une
   nuance de gris : LE GLYPHE, pose dans la boite par GlypheDuGenre, et LE
   FOND -- carte pour la personne physique, surface pour la personne
   morale. */
.be-n-physique rect { fill: var(--bg-card); stroke: var(--text-secondary); }
.be-n-morale rect { fill: var(--bg-surface); stroke: var(--text-secondary); }

/* La construction juridique et la categorie portent la teinte de
   l'avertissement : ni l'une ni l'autre ne rend de pourcentage. */
.be-n-construction rect { fill: var(--color-warning-wash); stroke: var(--color-warning);
                          stroke-dasharray: 5 3; }
.be-n-categorie rect { fill: none; stroke: var(--color-warning); stroke-dasharray: 3 3; }
.be-n-categorie text { font-style: italic; fill: var(--text-secondary); }

/* LE NOEUD « ? » : une boite VIDE, en pointille. Elle ne se confond avec
   aucune donnee, et c'est exactement ce qu'on veut lire. */
.be-n-inconnu rect { fill: none; stroke: var(--text-muted); stroke-dasharray: 3 3; }
.be-n-inconnu text { font-size: 1.15rem; font-weight: 700; fill: var(--text-muted); }

/* Le lisere de decision -- jamais avant qu'elle soit prise. */
.be-decide-retenu { fill: var(--color-success); stroke: none; }
.be-decide-ecarte { fill: var(--text-muted); stroke: none; }

.be-arete path { stroke-width: 1.5; fill: none; }
/* L'etiquette porte un halo de la couleur de la carte : sans lui, un
   pourcentage pose sur un trait qui en croise un autre devient illisible. */
.be-arete text { font-size: 0.68rem; fill: var(--text-secondary);
                 stroke: var(--bg-card); stroke-width: 4px; }

.be-a-capital path { stroke: var(--color-primary); }
.be-a-capital text { fill: var(--color-primary); }
/* Les droits de vote ont leur propre teinte PARCE QU'ILS NE S'ADDITIONNENT
   PAS au capital : deux traits identiques inviteraient a le faire. */
.be-a-voix path { stroke: var(--color-purple); }
.be-a-voix text { fill: var(--color-purple); }
.be-a-souple path { stroke: var(--text-muted); stroke-dasharray: 5 4; }
.be-a-boucle path { stroke: var(--color-danger); stroke-dasharray: 2 3; }
.be-a-boucle text { fill: var(--color-danger); }
