/**
 * @project: poesie
 * @version: 0.2.0
 * @encoding: UTF-8
 * @compliance: GDPR, EU-Accessibility, Data Sovereignty
 * @copyright: (c) 2025-2026 kwargs SRL
 * @description: Base styles, layout, components, accessibility.
 */

/* ── POESIE : STYLES DE BASE ──────────────────────────────────── */

:root {
    --ks-font-main: 'Hanken Grotesk', system-ui, -apple-system, sans-serif;
}

body {
    font-family: var(--ks-font-main);
    font-weight: 420; /* Hanken Grotesk variable : entre regular (400) et medium (500) */
}

/* ── Navbar ──────────────────────────────────────────────────── */

.navbar {
    background-color: var(--bs-body-bg);
}

/* ── Sections ────────────────────────────────────────────────── */

.section {
    padding-top: var(--ks-rhythm-1);
}

/* ── Thème : bascule et substitution d'actifs ────────────────── */

/* `--ks-transition` porte sur la couleur, le fond, la bordure et l'ombre :
   sans cette coupure, changer de thème anime toute la page d'un coup.
   Posée puis retirée par theme-handler.js, le temps de la bascule. */

.ks-theme-switching,
.ks-theme-switching *,
.ks-theme-switching *::before,
.ks-theme-switching *::after {
    transition: none !important;
}

/* Un logo clair et un logo sombre coexistent dans le gabarit, seul celui du
   thème actif reste affiché. La référence injecte une feuille de style au vol
   parce qu'elle REMPLACE le fichier CSS ; le socle change un attribut sur
   <html>, la règle se dit donc en CSS pur, sans JavaScript de produit.
   `!important` parce qu'une classe utilitaire Bootstrap posée sur le même
   élément (d-block, d-flex) l'emporterait autrement. */

[data-bs-theme="dark"] [data-ks-theme="light"],
[data-bs-theme="light"] [data-ks-theme="dark"] {
    display: none !important;
}

/* ── Cards ────────────────────────────────────────────────────── */

.card {
    box-shadow: var(--bs-box-shadow-lg);
    border-radius: var(--ks-border-radius);
}

/* ── Scroll to top ───────────────────────────────────────────── */

#btn-back-to-top {
    position: fixed;
    bottom: 20px;
    inset-inline-end: 20px; /* RTL-safe : right en LTR, left en RTL */
    display: none; /* Géré par JS, bascule vers flex via poesie-ui.js */
    z-index: var(--ks-z-fixed);
    width: 40px;
    height: 40px;
    padding: 0;
    align-items: center;
    justify-content: center;
    background-color: var(--ks-primary);
    border: none;
    border-radius: var(--ks-border-radius);
    box-shadow: none;
    transition: var(--ks-transition);
}

#btn-back-to-top:hover {
    background-color: var(--ks-secondary);
    transform: translateY(-5px);
}

#btn-back-to-top:focus-visible {
    outline: 2px solid var(--ks-secondary);
    outline-offset: 2px;
}

/* ── Messages ────────────────────────────────────────────────── */

.message-container {
    position: fixed;
    bottom: 0;
    inset-inline-start: 0; /* RTL-safe : left en LTR, right en RTL */
    margin: 0 10px 10px;
    z-index: var(--ks-z-backdrop);
    display: flex;
    flex-direction: column-reverse; /* Empile de bas en haut */
}

.message-alert {
    padding-inline-start: 10px; /* RTL-safe */
    margin-bottom: 3px;
}

.message-alert .alert {
    opacity: 1;
    transition: opacity var(--ks-duration-slow) var(--ks-easing);
    border: none;
    border-inline-start: 4px solid var(--bs-alert-color); /* RTL-safe */
}

/* ── Icônes de la navbar ─────────────────────────────────────── */
/* Remplace les styles inline et les longues chaînes utilitaires. */

.navbar-icon {
    /* Neutralise le dessin natif : un <button> sans classe .btn garde
       -webkit-appearance et WebKit repasse par dessus la feuille. */
    -webkit-appearance: none;
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem 0.5rem;
    font-size: 1.2rem;
    background: none;
    border: none;
    color: var(--bs-body-color);
    text-decoration: none;
    box-shadow: none;
    cursor: pointer;
    transition: var(--ks-transition);
}

.navbar-icon:hover,
.navbar-icon:focus-visible {
    color: var(--ks-primary);
}

/* ── Cookie banner RGPD ─────────────────────────────────────── */

#rgpd-cookie-banner {
    position: fixed;
    bottom: 0;
    inset-inline-start: 0; /* RTL-safe */
    inset-inline-end: 0;
    padding: 1rem;
    z-index: var(--ks-z-modal);
    display: none; /* Géré par JS */
}

#rgpd-cookie-banner .bi-shield-check {
    color: var(--ks-success);
}

/* ── Tables (poesie-table) ──────────────────────────────────── */

.poesie-table-toolbar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.75rem;
}

.poesie-table-search {
    max-width: 280px;
}

.poesie-table-pagination {
    margin-top: 0.75rem;
}

/* Indicateur de tri dans les en-têtes */
[data-poesie-table] thead th[aria-sort] {
    position: relative;
    padding-inline-end: 1.5rem;
    user-select: none;
}

[data-poesie-table] thead th[aria-sort]::after {
    position: absolute;
    inset-inline-end: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0.3;
    content: '⇅';
}

[data-poesie-table] thead th[aria-sort="ascending"]::after {
    content: '↑';
    opacity: 1;
}

[data-poesie-table] thead th[aria-sort="descending"]::after {
    content: '↓';
    opacity: 1;
}

/* ── Profil ──────────────────────────────────────────────────── */

.profile-avatar {
    width: 75px;
    height: 75px;
    object-fit: cover;
}

/* ── Composants ergonomiques ─────────────────────────────────── */
/* Patterns réutilisables inspirés du template Front v4.3.1.     */

/* Label de section (uppercase, semi-bold, petit) */
.text-cap {
    display: block;
    font-size: .8125rem;
    font-weight: 600;
    letter-spacing: .03125rem;
    text-transform: uppercase;
    margin-bottom: .75rem;
}

/* Cercle d'icône (conteneur rond pour Bootstrap Icons) */
.icon-circle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 4rem;
    border-radius: var(--ks-border-radius-circle);
}

/* Carte avec effet de survol (élévation) */
.card-transition {
    transition: transform var(--ks-duration-fast) var(--ks-easing),
                box-shadow var(--ks-duration-fast) var(--ks-easing);
}

.card-transition:hover {
    transform: translateY(-.1875rem);
    box-shadow: var(--ks-shadow-hover) !important;
}

/* ── Step (timeline horizontale / verticale) ────────────────── */

.step {
    list-style: none;
    padding-left: 0;
    margin-bottom: 0;
}

.step-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: var(--ks-border-radius-circle);
    font-weight: 700;
    font-size: 1.125rem;
    flex-shrink: 0;
}

.step-icon-soft-primary {
    background-color: var(--bs-body-bg);
    box-shadow: inset 0 0 0 100px rgba(var(--ks-primary-rgb, 13, 110, 253), .1);
    color: var(--ks-primary, var(--bs-primary));
    position: relative;
    z-index: var(--ks-z-overlay);
}

/* Layout horizontal centré (md+) */
@media (min-width: 768px) {
    .step-centered {
        display: flex;
    }

    .step-centered .step-item {
        flex: 1;
        text-align: center;
        position: relative;
    }

    .step-centered .step-item + .step-item::before {
        content: '';
        position: absolute;
        top: 1.75rem;
        left: 0;
        right: 50%;
        height: 2px;
        background-color: rgba(var(--ks-primary-rgb, 13, 110, 253), .2);
        z-index: var(--ks-z-base);
    }

    .step-centered .step-item:not(:last-child)::after {
        content: '';
        position: absolute;
        top: 1.75rem;
        left: 50%;
        right: 0;
        height: 2px;
        background-color: rgba(var(--ks-primary-rgb, 13, 110, 253), .2);
        z-index: var(--ks-z-base);
    }

    .step-centered .step-icon {
        position: relative;
        z-index: var(--ks-z-raised);
    }

    .step-centered .step-content p {
        text-align: start;
    }
}

/* Layout vertical (mobile) */
@media (max-width: 767.98px) {
    .step-item {
        display: flex;
        align-items: flex-start;
        gap: 1rem;
    }

    .step-item + .step-item {
        margin-top: 1.5rem;
    }
}

/* ── Page header ─────────────────────────────────────────────── */
/* Breadcrumb + titre + actions alignés. Utilisé sur toutes les  */
/* pages applicatives via le partial page_header.                */

.page-header {
    padding-bottom: 1.5rem;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.page-header-title {
    margin-bottom: 0;
}

.page-header-text {
    color: var(--bs-secondary-color);
    margin-bottom: 0;
}

.page-header .breadcrumb {
    padding: 0;
    margin-bottom: .5rem;
    background: none;
}

.page-header-tabs {
    margin-bottom: calc(-1.5rem - 1px); /* Aligner le border-bottom de la tab avec celui du page-header */
}

/* Variante sans bordure (sections internes) */
.page-header-reset {
    padding-bottom: 0;
    margin-bottom: 0;
    border-bottom: none;
}

/* ── Content spacing ─────────────────────────────────────────── */
/* Spacing dédié aux sections de page (distinct des spacers      */
/* Bootstrap qui sont pour les marges entre éléments).            */

.content-space-1 { padding-top: var(--ks-rhythm-1); padding-bottom: var(--ks-rhythm-1); }
.content-space-2 { padding-top: var(--ks-rhythm-2); padding-bottom: var(--ks-rhythm-2); }
.content-space-3 { padding-top: var(--ks-rhythm-3); padding-bottom: var(--ks-rhythm-3); }
.content-space-4 { padding-top: var(--ks-rhythm-4); padding-bottom: var(--ks-rhythm-4); }
.content-space-5 { padding-top: var(--ks-rhythm-5); padding-bottom: var(--ks-rhythm-5); }

.content-space-t-1 { padding-top: var(--ks-rhythm-1); }
.content-space-t-2 { padding-top: var(--ks-rhythm-2); }
.content-space-t-3 { padding-top: var(--ks-rhythm-3); }
.content-space-t-4 { padding-top: var(--ks-rhythm-4); }
.content-space-t-5 { padding-top: var(--ks-rhythm-5); }

.content-space-b-1 { padding-bottom: var(--ks-rhythm-1); }
.content-space-b-2 { padding-bottom: var(--ks-rhythm-2); }
.content-space-b-3 { padding-bottom: var(--ks-rhythm-3); }
.content-space-b-4 { padding-bottom: var(--ks-rhythm-4); }
.content-space-b-5 { padding-bottom: var(--ks-rhythm-5); }

@media (min-width: 992px) {
    .content-space-t-lg-2 { padding-top: var(--ks-rhythm-2); }
    .content-space-t-lg-3 { padding-top: var(--ks-rhythm-3); }
    .content-space-t-lg-4 { padding-top: var(--ks-rhythm-4); }
    .content-space-b-lg-2 { padding-bottom: var(--ks-rhythm-2); }
    .content-space-b-lg-3 { padding-bottom: var(--ks-rhythm-3); }
    .content-space-b-lg-4 { padding-bottom: var(--ks-rhythm-4); }
}

/* ── Badges soft ─────────────────────────────────────────────── */
/* Fond 10% opacité + texte coloré. Plus lisible que text-bg-*.  */

.bg-soft-primary { background-color: rgba(var(--bs-primary-rgb), 0.1) !important; }
.bg-soft-secondary { background-color: rgba(var(--bs-secondary-rgb), 0.1) !important; }
.bg-soft-success { background-color: rgba(var(--bs-success-rgb), 0.1) !important; }
.bg-soft-info { background-color: rgba(var(--bs-info-rgb), 0.1) !important; }
.bg-soft-warning { background-color: rgba(var(--bs-warning-rgb), 0.1) !important; }
.bg-soft-danger { background-color: rgba(var(--bs-danger-rgb), 0.1) !important; }
.bg-soft-dark { background-color: rgba(var(--bs-dark-rgb), 0.1) !important; }
.bg-soft-light { background-color: rgba(var(--bs-light-rgb), 0.1) !important; }

/* Dark mode : opacité renforcée pour lisibilité */
[data-bs-theme="dark"] .bg-soft-primary,
[data-bs-theme="dark"] .bg-soft-secondary,
[data-bs-theme="dark"] .bg-soft-success,
[data-bs-theme="dark"] .bg-soft-info,
[data-bs-theme="dark"] .bg-soft-warning,
[data-bs-theme="dark"] .bg-soft-danger,
[data-bs-theme="dark"] .bg-soft-dark,
[data-bs-theme="dark"] .bg-soft-light {
    --_soft-opacity: 0.2;
}

[data-bs-theme="dark"] .bg-soft-primary { background-color: rgba(var(--bs-primary-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-secondary { background-color: rgba(var(--bs-secondary-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-success { background-color: rgba(var(--bs-success-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-info { background-color: rgba(var(--bs-info-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-warning { background-color: rgba(var(--bs-warning-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-danger { background-color: rgba(var(--bs-danger-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-dark { background-color: rgba(var(--bs-dark-rgb), var(--_soft-opacity)) !important; }
[data-bs-theme="dark"] .bg-soft-light { background-color: rgba(var(--bs-light-rgb), var(--_soft-opacity)) !important; }

/* ── Avatars ─────────────────────────────────────────────────── */

.avatar {
    position: relative;
    display: inline-block;
    width: 3rem;
    height: 3rem;
    border-radius: var(--bs-border-radius);
}

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

.avatar-initials {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-weight: 600;
    text-transform: uppercase;
    border-radius: inherit;
    color: var(--bs-primary);
    background-color: rgba(var(--bs-primary-rgb), 0.1);
}

.avatar-circle { border-radius: var(--ks-border-radius-circle); }

/* Tailles */
.avatar-xss { width: 1.5rem; height: 1.5rem; font-size: .5rem; }
.avatar-xs  { width: 2rem; height: 2rem; font-size: .625rem; }
.avatar-sm  { width: 2.5rem; height: 2.5rem; font-size: .75rem; }
/* .avatar (default) : 3rem */
.avatar-lg  { width: 4rem; height: 4rem; font-size: 1rem; }
.avatar-xl  { width: 5.625rem; height: 5.625rem; font-size: 1.25rem; }
.avatar-xxl { width: 7.5rem; height: 7.5rem; font-size: 1.75rem; }

/* Groupe (chevauchement) */
.avatar-group {
    display: inline-flex;
    flex-direction: row-reverse; /* Empile de droite à gauche pour z-index naturel */
}

.avatar-group .avatar {
    margin-inline-start: -.75rem;
    border: 2px solid var(--bs-body-bg);
}

.avatar-group .avatar:last-child {
    margin-inline-start: 0;
}

/* Statut (point coloré positionné) */
.avatar-status {
    position: absolute;
    bottom: 0;
    inset-inline-end: 0;
    width: .625rem;
    height: .625rem;
    border-radius: var(--ks-border-radius-circle);
    border: 2px solid var(--bs-body-bg);
}

/* ── Card variants ───────────────────────────────────────────── */

.card-hover-shadow {
    transition: box-shadow var(--ks-duration-fast) var(--ks-easing);
}

.card-hover-shadow:hover {
    box-shadow: var(--ks-shadow-hover) !important;
}

.card-dashed {
    border: 2px dashed var(--bs-border-color);
    box-shadow: none;
}

.card-bordered {
    border: 1px solid var(--bs-border-color);
    box-shadow: none;
}

.card-sm > .card-body { padding: 1.25rem; }
.card-lg > .card-body { padding: 2.75rem; }

.card-header-content-between {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

@media (min-width: 768px) {
    .card-header-content-md-between {
        display: flex;
        align-items: center;
        justify-content: space-between;
    }
}

/* ── Input search flush ──────────────────────────────────────── */

.input-group-merge {
    position: relative;
}

.input-group-merge .form-control {
    border-radius: var(--bs-border-radius) !important;
}

/* Le creux ne se creuse que du cote ou quelque chose se pose. Avant le lot 2,
   le decalage a gauche etait inconditionnel : un merge portant seulement un
   append gardait un creux vide. */
.input-group-merge:has(.input-group-prepend) .form-control {
    padding-inline-start: 2.5rem;
}

.input-group-merge:has(.input-group-append) .form-control {
    padding-inline-end: 2.75rem;
}

.input-group-merge .input-group-prepend {
    position: absolute;
    inset-inline-start: 0;
    top: 0;
    bottom: 0;
    z-index: var(--ks-z-field);
    display: flex;
    align-items: center;
    padding-inline-start: .75rem;
    color: var(--bs-secondary-color);
    pointer-events: none;
}

/* L'etat vit sur le GROUPE et non sur le seul champ : le champ d'un merge n'a
   pas de bordure propre, c'est le groupe qui dessine l'anneau. Pose et retire
   par poesie-forms.js au focus et au blur. */

.input-group-merge.is-focused {
    outline: 2px solid var(--bs-primary);
    outline-offset: 1px;
    border-radius: var(--bs-border-radius);
}

/* Symetrique du prepend, mais CLIQUABLE : c'est ici que vit la revelation du
   mot de passe, donc les evenements de pointeur restent actifs.

   L'ENVELOPPE porte la mise en page, le bouton n'est qu'un controle. Poser le
   positionnement et le flex sur le <button> lui-meme faisait diverger Safari
   de Firefox (26/08/2026) : WebKit garde -webkit-appearance sur un bouton et
   ne dispose pas son contenu de la meme facon. Regle generale : pas de mise en
   page sur un element dont le navigateur dessine deja l'apparence. */

.input-group-merge .input-group-append {
    position: absolute;
    inset-inline-end: .5rem;
    top: 0;
    bottom: 0;
    z-index: var(--ks-z-field);
    display: flex;
    align-items: center;
    color: var(--bs-secondary-color);
}

.btn-password-toggle {
    /* Neutralise le dessin natif du bouton, sans quoi WebKit repasse par
       dessus la feuille. Les deux ecritures, la prefixee n'etant pas
       redondante sur les Safari encore en service. */
    -webkit-appearance: none;
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: none;
    padding: .25rem;
    color: inherit;
    font-size: 1rem;
    line-height: 1;
    border-radius: var(--ks-border-radius-sm);
    transition: color var(--ks-duration-fast) var(--ks-easing);
}

/* Le bouton n'a plus de classe .btn : son anneau de focus ne viendrait donc
   d'aucune feuille, et le contour natif disparait avec l'apparence. */
.btn-password-toggle:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 1px;
}

.btn-password-toggle:hover,
.btn-password-toggle:focus-visible {
    color: var(--bs-primary);
}

/* ── Champs : variantes selon le contexte ────────────────────── */
/* Le socle avait deja merge et flush. Deux de plus, pas davantage : les
   autres variantes de la reference ne repondent a aucun besoin identifie. */

/* Dans une barre d'outils, ou le champ ne doit pas dessiner de boite. */
.input-group-borderless .form-control,
.input-group-borderless .form-select {
    border-color: transparent;
    background-color: transparent;
}

.input-group-borderless .form-control:focus,
.input-group-borderless .form-select:focus {
    border-color: var(--bs-border-color);
    background-color: var(--bs-body-bg);
}

/* Sur fond colore, ou le blanc du champ trancherait trop. */
.input-group-light .form-control,
.input-group-light .form-select {
    border-color: transparent;
    background-color: rgba(var(--bs-secondary-rgb), .08);
}

.input-group-light .form-control:focus,
.input-group-light .form-select:focus {
    background-color: var(--bs-body-bg);
}

/* ── Hierarchie de libelles ──────────────────────────────────── */
/* Quatre niveaux, chacun avec sa charge : le libelle (form-label), la
   precision facultative (ici), le texte d'aide (form-text, Bootstrap), et
   le lien d'action (form-link). */

.form-label-secondary {
    font-size: var(--ks-font-size-sm);
    color: var(--bs-secondary-color);
    margin-inline-start: .25rem;
}

.form-link {
    display: inline-block;
    margin-top: .5rem;
    font-size: var(--ks-font-size-sm);
    font-weight: 600;
}

/* ── Compteur de caracteres ──────────────────────────────────── */
/* Rendu par le gabarit avec son etat initial ; le JavaScript ne fait que le
   mettre a jour. Son identifiant entre dans aria-describedby via field_a11y. */

.form-counter {
    text-align: end;
    font-variant-numeric: tabular-nums;
}

.form-counter.is-over {
    color: var(--bs-danger);
    font-weight: 600;
}

/* ── Repeteur de formset ─────────────────────────────────────── */
/* Le bouton de retrait se detache du flux : une ligne peut porter un ou dix
   champs, et l'ancrer dans la grille le ferait sauter d'une ligne a l'autre. */

.poesie-repeater-row {
    position: relative;
    padding: 1rem;
    padding-inline-end: 3rem;
    margin-bottom: .75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--ks-border-radius-lg);
}

.poesie-repeater-remove {
    position: absolute;
    top: .5rem;
    inset-inline-end: .5rem;
}

/* ── Squelette applicatif ────────────────────────────────────── */
/* Deux etats sur ecran large, deployee et reduite. Sur ecran etroit, la barre
   est un offcanvas de Bootstrap : rien a ecrire ici, la classe offcanvas-lg
   suffit et le voile, le piege de focus et l'echappement viennent avec.

   La direction et l'affichage vivent ICI et non en utilitaire Bootstrap :
   .flex-column et .d-block sont !important, et interdiraient la bascule.
   Lecon prise du shell de rylm. */

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

.app-sidebar {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    width: var(--ks-sidebar-width);
    border-inline-end: 1px solid var(--bs-border-color);
    background-color: var(--bs-body-bg);
    transition: width var(--ks-duration-slow) var(--ks-easing);
}

@media (min-width: 992px) {
    .app-sidebar {
        position: sticky;
        top: 0;
        height: 100vh;
        overflow-y: auto;
    }
}

.app-sidebar-brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    min-height: var(--ks-app-header-height);
    padding: 0 1rem;
}

.app-nav {
    flex: 1;
    padding: .5rem;
    overflow-y: auto;
}

.app-nav-item {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .5rem .75rem;
    border-radius: var(--ks-border-radius);
    color: var(--bs-body-color);
    text-decoration: none;
    transition: background-color var(--ks-duration-fast) var(--ks-easing);
}

.app-nav-item:hover,
.app-nav-item:focus-visible {
    background-color: rgba(var(--bs-secondary-rgb), .08);
}

.app-nav-item.active {
    background-color: rgba(var(--bs-primary-rgb), .1);
    color: var(--bs-primary);
}

.app-sidebar-account {
    padding: .75rem;
    border-top: 1px solid var(--bs-border-color);
}

.app-sidebar-reduce,
.app-sidebar-open {
    /* Meme raison que .navbar-icon et .btn-password-toggle : sans cela, Safari
       redessine le bouton et Firefox non. */
    -webkit-appearance: none;
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: none;
    color: inherit;
    padding: .25rem .5rem;
    line-height: 1;
    border-radius: var(--ks-border-radius-sm);
}

.app-sidebar-reduce:focus-visible,
.app-sidebar-open:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 1px;
}

/* ── Barre reduite ───────────────────────────────────────────── */
/* Le libelle est OCCULTE, jamais supprime : display:none le retirerait de
   l'arbre d'accessibilite, et un lien reduit a une icone decorative n'aurait
   plus de nom. Recette de .visually-hidden de Bootstrap. */

.ks-sidebar-mini .app-nav-label,
.ks-sidebar-mini .app-sidebar-account .app-nav-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

@media (min-width: 992px) {
    .ks-sidebar-mini .app-sidebar {
        width: var(--ks-sidebar-mini-width);
    }

    .ks-sidebar-mini .app-nav-item {
        justify-content: center;
    }

    .ks-sidebar-mini .app-sidebar-reduce i {
        transform: rotate(180deg);
    }
}

.app-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.app-header {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: var(--ks-app-header-height);
    padding: 0 1.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.app-header-titles {
    flex: 1;
    min-width: 0;
}

.app-header-actions {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.app-content {
    flex: 1;
    padding: 1.5rem;
}

/* ── Etat de chargement ──────────────────────────────────────── */
/* Il SIGNALE, il n'empeche rien : pas de desactivation du bouton, qui
   retirerait son nom et sa valeur de la requete. Le tourniquet est dessine
   par un pseudo-element, donc aucun DOM n'est fabrique. */

[data-poesie-loading].is-loading {
    position: relative;
    color: transparent !important;
}

[data-poesie-loading].is-loading::after {
    position: absolute;
    top: 50%;
    inset-inline-start: 50%;
    width: 1rem;
    height: 1rem;
    margin: -.5rem 0 0 -.5rem;
    border: 2px solid currentColor;
    border-top-color: transparent;
    border-radius: var(--ks-border-radius-circle);
    color: var(--bs-body-color);
    content: '';
    animation: poesie-spin var(--ks-duration-spin) var(--ks-easing-linear) infinite;
}

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

/* ── En-tete de tableau collant ──────────────────────────────── */
/* En CSS pur, sur demande. poesie-table.js n'a pas a connaitre cette regle :
   le tri et la pagination sont un autre sujet que la mise en page. */

.table-sticky-header thead th {
    position: sticky;
    top: 0;
    z-index: var(--ks-z-raised);
    background-color: var(--bs-body-bg);
}

/* ── Choix en carte ──────────────────────────────────────────── */
/* UN seul mecanisme : le libelle enveloppe son input, donc toute la carte est
   nativement cible de clic. Pas de pseudo-element etire, pas d'element frere,
   pas de JavaScript. L'etat selectionne se dit en CSS. */

.form-check-card {
    display: flex;
    align-items: center;
    gap: .75rem;
    width: 100%;
    margin: 0;
    padding: 1rem;
    cursor: pointer;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--ks-border-radius-lg);
    background-color: var(--bs-body-bg);
    transition: border-color var(--ks-duration-fast) var(--ks-easing),
                box-shadow var(--ks-duration-fast) var(--ks-easing);
}

.form-check-card:hover {
    border-color: var(--bs-primary);
}

.form-check-card:has(:checked) {
    border-color: var(--bs-primary);
    box-shadow: var(--ks-shadow-hover);
}

/* L'anneau de focus appartient a l'input, mais c'est la carte qui se voit. */
.form-check-card:has(:focus-visible) {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

.form-check-card .form-check-input {
    margin: 0;
    flex-shrink: 0;
}

.form-check-card-body {
    flex: 1;
    min-width: 0;
}

.form-check-card-dashed {
    border-style: dashed;
    border-width: 2px;
    background-color: transparent;
}

.input-group-flush .form-control {
    border: none;
    background-color: transparent;
    padding-inline-start: 2rem;
}

.input-group-flush .form-control:focus {
    box-shadow: none;
}

.input-group-flush .input-group-prepend {
    padding-inline-start: .25rem;
}

/* ── Col divider ─────────────────────────────────────────────── */

.col-divider > [class*="col"]:not(:first-child),
.col-sm-divider > [class*="col"]:not(:first-child),
.col-md-divider > [class*="col"]:not(:first-child),
.col-lg-divider > [class*="col"]:not(:first-child) {
    position: relative;
}

.col-divider > [class*="col"]:not(:first-child)::before,
.col-sm-divider > [class*="col"]:not(:first-child)::before,
.col-md-divider > [class*="col"]:not(:first-child)::before,
.col-lg-divider > [class*="col"]:not(:first-child)::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    inset-inline-start: 0;
    border-inline-start: 1px solid var(--bs-border-color);
}

.col-divider-light > [class*="col"]:not(:first-child)::before {
    border-color: rgba(var(--bs-light-rgb), 0.1);
}

/* Responsive : masquer le divider sous le breakpoint */
@media (max-width: 575.98px) {
    .col-sm-divider > [class*="col"]:not(:first-child)::before { display: none; }
}
@media (max-width: 767.98px) {
    .col-md-divider > [class*="col"]:not(:first-child)::before { display: none; }
}
@media (max-width: 991.98px) {
    .col-lg-divider > [class*="col"]:not(:first-child)::before { display: none; }
}

/* ── Input card (search fusion) ───────────────────────────────── */

.input-card {
    display: flex;
    align-items: center;
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-lg);
    padding: .25rem;
    box-shadow: var(--bs-box-shadow-sm);
}

.input-card-pill { border-radius: var(--ks-border-radius-pill); }
.input-card-sm { padding: .125rem; }
.input-card-sm .form-control { padding: .375rem .75rem; font-size: .875rem; }

.input-card-form {
    display: flex;
    align-items: center;
    flex: 1;
    min-width: 0;
}

.input-card-form .form-control {
    border: none;
    background: transparent;
    box-shadow: none;
}

.input-card-icon {
    display: flex;
    align-items: center;
    padding-inline-start: .75rem;
    color: var(--bs-secondary-color);
}

.input-card-separator {
    width: 1px;
    height: 2rem;
    background-color: var(--bs-border-color);
    flex-shrink: 0;
    margin: 0 .25rem;
}

.input-card .btn {
    flex-shrink: 0;
    /* Aligne l'arrondi du bouton sur celui du container (--bs-border-radius-lg). */
    border-radius: var(--bs-border-radius-lg);
}

/* Variante pill : le bouton suit l'arrondi pill du container. */
.input-card-pill .btn {
    border-radius: var(--ks-border-radius-pill);
}

/* ── List checked / list pointer ─────────────────────────────── */

.list-checked,
.list-pointer {
    list-style: none;
    padding-inline-start: 0;
}

.list-checked-item,
.list-pointer-item {
    position: relative;
    padding-inline-start: 1.75rem;
    margin-bottom: .5rem;
}

.list-checked-item::before {
    content: '✓';
    position: absolute;
    inset-inline-start: 0;
    font-weight: 700;
    color: var(--bs-primary);
}

.list-checked-primary .list-checked-item::before { color: var(--bs-primary); }
.list-checked-success .list-checked-item::before { color: var(--bs-success); }
.list-checked-info .list-checked-item::before { color: var(--bs-info); }

.list-pointer-item::before {
    content: '';
    position: absolute;
    inset-inline-start: 0;
    top: .55em;
    width: .5rem;
    height: .5rem;
    border-radius: var(--ks-border-radius-circle);
    background-color: var(--bs-primary);
}

.list-pointer-primary .list-pointer-item::before { background-color: var(--bs-primary); }
.list-pointer-success .list-pointer-item::before { background-color: var(--bs-success); }
.list-pointer-danger .list-pointer-item::before { background-color: var(--bs-danger); }

.list-separator {
    list-style: none;
    padding-inline-start: 0;
}

.list-separator > li:not(:last-child) {
    border-bottom: 1px solid var(--bs-border-color);
    padding-bottom: .75rem;
    margin-bottom: .75rem;
}

/* ── Table enhancements ──────────────────────────────────────── */

.table-thead-bordered > :not(caption) > thead > tr {
    border-top: 1px solid var(--bs-border-color);
    border-bottom: 2px solid var(--bs-border-color);
}

.table-align-middle th,
.table-align-middle td {
    vertical-align: middle;
}

.table-nowrap th,
.table-nowrap td {
    white-space: nowrap;
}

.thead-light th {
    background-color: var(--bs-tertiary-bg);
}

/* ── Sticky sidebar ──────────────────────────────────────────── */
/*
 * Sidebar qui reste fixe au scroll (page detail, checkout, doc).
 * Pas de JS : position:sticky natif (support universel modernes).
 *
 * Usage :
 *   <div class="row">
 *     <aside class="col-lg-3 sidebar-sticky">...</aside>
 *     <main class="col-lg-9">...</main>
 *   </div>
 *
 * Offset top configurable via la variable CSS --ks-sticky-top
 * (defaut 5rem). La valeur par defaut dégage la navbar poesie
 * (.navbar.sticky-top, ~60px de haut) + 20px de respiration.
 *
 * Si le produit n'a PAS de navbar sticky, ramener a 1.5rem dans
 * son palette.css :
 *   :root { --ks-sticky-top: 1.5rem; }
 *
 * Si la navbar est plus haute (logo XL, topbar promo au-dessus),
 * augmenter en consequence.
 */
.sidebar-sticky {
    position: sticky;
    top: var(--ks-sticky-top, 5rem);
    align-self: flex-start;
}

@media (max-width: 991.98px) {
    /* En dessous de lg : pas de sticky (la sidebar passe au-dessus du contenu). */
    .sidebar-sticky {
        position: static;
    }
}

/* ── Accessibilité ───────────────────────────────────────────── */

/* Focus visible pour la navigation clavier (WCAG 2.1 AA) */
:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* Désactiver les animations si l'utilisateur le demande (EAA) */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}
