/**
 * mio.land - Composants UX partagés
 * Source de vérité pour tous les éléments d'interface utilisateur
 * 
 * Usage: <link rel="stylesheet" href="/ux/ux-components.css?<?= filemtime($_SERVER['DOCUMENT_ROOT'] . '/ux/ux-components.css') ?>">
 * 
 * Ce fichier est conçu pour être embeddable dans des exports HTML standalone.
 * Toutes les icônes sont en SVG inline, jamais d'emojis ou caractères graphiques.
 * 
 * PERSONNALISATION PAR APP:
 * Les apps peuvent définir --accent dans leur CSS pour personnaliser:
 * - La couleur du toast undo (bouton + barre de progression)
 * Exemple: :root { --accent: #7C4DFF; }
 */

/* ============================
   TYPO FRANCAISE — espaces inseparables
   Les helpers MioTypo / UX.typoFrHtml enveloppent « mot : » dans
   .ux-typo-nowrap (alias .oa-nowrap pour l'existant Actualite).
   ============================ */
.ux-typo-nowrap,
.oa-nowrap {
    white-space: nowrap;
}

/* ============================
   TAP HIGHLIGHT — INTERDIT
   Jamais de carre bleu/gris natif au touch (WebKit). Applique a toute app
   qui charge ce fichier. Feedback = .ux-btn-pressed / :active scopes.
   ============================ */
html, body, button, a, input, select, textarea, label, summary,
[role="button"], [onclick], .ux-btn, .ux-dialog-btn, .ux-toggle-item,
.ux-checkbox-item, .ux-radio-item, .ux-segment-btn {
    -webkit-tap-highlight-color: transparent;
}

/* ============================
   MODE MOBILE — TYPO / TAILLES STANDARDS +10 %
   Multiplie les font-size en px (et le reste de l'UI de l'app).
   Source de vérité : html.os-mode-mobile (theme-listener).
   Le shell OS annule ce zoom dans os/style.css pour ne pas
   casser la gestion des fenêtres ; les panneaux OS sont
   grossis séparément via body.mode-mobile.
   ============================ */
html.os-mode-mobile {
    --font-scale: 1.1;
    zoom: 1.1;
}

/* Fallback hors shell OS (pas de data-os-mode) */
@media (max-width: 760px) {
    html:not([data-os-mode]) {
        --font-scale: 1.1;
        zoom: 1.1;
    }
}

/* ============================
   VARIABLES UX (à ne pas surcharger)
   ============================ */

:root {
    /* Couleurs de boutons standard */
    --ux-btn-default: #2ECC71;
    --ux-btn-default-hover: #27AE60;
    --ux-btn-primary: #3498DB;
    --ux-btn-primary-hover: #2980B9;
    --ux-btn-secondary: rgba(255, 255, 255, 0.08);
    --ux-btn-secondary-hover: rgba(255, 255, 255, 0.15);
    --ux-btn-danger: #E74C3C;
    --ux-btn-danger-hover: #C0392B;
    --ux-btn-purple: #8b5cf6;
    --ux-btn-purple-hover: #7c3aed;
    --ux-btn-pink: #ec4899;
    --ux-btn-pink-hover: #db2777;
    --ux-btn-orange: #F39C12;
    --ux-btn-orange-hover: #E67E22;
    --ux-btn-cyan: #00BCD4;
    --ux-btn-cyan-hover: #00ACC1;
    
    /* Couleurs de feedback */
    --ux-success: #2ECC71;
    --ux-error: #E74C3C;
    --ux-warning: #F39C12;
    --ux-info: #3498DB;

    /* Liseret fluo au survol (contour uniquement, alpha 50 %, transition 0.2s) */
    --ux-hover-rim: rgba(255, 255, 255, 0.5);
    --ux-hover-glow: rgba(255, 255, 255, 0.5);
    --ux-hover-rim-shadow: 0 0 0 1px var(--ux-hover-rim), 0 0 8px 1px var(--ux-hover-glow);
    --ux-hover-rim-transition: box-shadow 0.2s ease, filter 0.2s ease, transform 0.2s ease;
    /* Clic / touch / enfoncé : ombre interne + assombrissement + liseret clair uniforme */
    --ux-btn-press-rim: rgba(255, 255, 255, 0.27);
    --ux-btn-press-shadow:
        /* Creux sombre (haut / gauche) — intensité réduite de moitié */
        inset 0 2px 6px rgba(0, 0, 0, 0.38),
        inset 0 1px 3px rgba(0, 0, 0, 0.28),
        /* Liseret clair uniforme tout autour */
        inset 0 1px 0 var(--ux-btn-press-rim),
        inset 1px 0 0 var(--ux-btn-press-rim),
        inset 0 -1px 0 var(--ux-btn-press-rim),
        inset -1px 0 0 var(--ux-btn-press-rim),
        /* Assombrissement du fond */
        inset 0 0 0 9999px rgba(0, 0, 0, 0.28);
    --ux-btn-press-filter: brightness(0.65);
    --ux-btn-press-offset: translate(1px, 1px);
    
    /* Transitions */
    --ux-transition-fast: 0.15s ease;
    --ux-transition-normal: 0.25s ease;
}

[data-theme="light"] {
    --ux-btn-secondary: rgba(0, 0, 0, 0.06);
    --ux-btn-secondary-hover: rgba(0, 0, 0, 0.10);
    --ux-hover-rim: rgba(0, 0, 0, 0.28);
    --ux-hover-glow: rgba(0, 0, 0, 0.10);
    --ux-btn-press-rim: rgba(255, 255, 255, 0.65);
    --ux-frost-bg: rgba(247, 247, 244, 0.55);
    --ux-frost-bg-fallback: rgba(247, 247, 244, 0.96);
    --ux-frost-border: rgba(0, 0, 0, 0.12);
}

/* ============================
   MARQUE PRODUCTIVIA
   ============================
   Style officiel du logotype "Productiv<span class="brand-ia">IA</span>".
   Source de verite : productivia.ca (_css/main.css).
   Usage obligatoire dans toute interface visible mentionnant la marque.
   - .brand-ia : applique le style officiel des lettres "IA" (taille reduite + decalage subtil vers le haut)
   - .brand-lock : empeche un retour a la ligne entre "Productiv" et "IA"
   Pattern HTML : <span class="brand-lock">Productiv<span class="brand-ia">IA</span></span>
   ============================ */

.brand-ia {
    display: inline-block;
    font-size: 0.85em;
    transform: translate(0px, -0.20em);
    pointer-events: none;
}

.brand-lock {
    white-space: nowrap;        /* empeche le retour a la ligne */
    display: inline-block;      /* evite certaines cesures bizarres */
    word-break: normal;         /* annule break-all sur des parents */
    overflow-wrap: normal;      /* annule anywhere / break-word */
    hyphens: none;              /* pas de cesure automatique */
}

/* ============================
   ICONE INFORMATION (globale)
   ============================
   Source : Material Icons « information-slab-symbol »
   Usage OBLIGATOIRE pour tout bouton / pastille « i » d'aide ou de détail.
   Pattern : UX.infoIconHtml() ou <span class="ux-info-icon">...</span>
   ============================ */
.ux-info-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: rgba(74, 158, 255, 0.18);
    color: #4a9eff;
    flex-shrink: 0;
    vertical-align: middle;
    box-sizing: border-box;
    user-select: none;
}
.ux-info-icon svg {
    width: 12px;
    height: 12px;
    fill: currentColor;
    stroke: none;
    display: block;
}
.ux-info-icon.ux-info-icon-sm {
    width: 16px;
    height: 16px;
}
.ux-info-icon.ux-info-icon-sm svg {
    width: 10px;
    height: 10px;
}
.ux-info-icon.ux-info-icon-lg {
    width: 24px;
    height: 24px;
}
.ux-info-icon.ux-info-icon-lg svg {
    width: 14px;
    height: 14px;
}

/* Tooltip riche modele (Superadmin Fournisseurs) — fixe au viewport, hors overflow panneau */
.ux-model-info-tip {
    position: fixed;
    z-index: 2147483000;
    width: min(520px, calc(100vw - 24px));
    max-width: calc(100vw - 24px);
    max-height: min(520px, calc(100vh - 24px));
    overflow-y: auto;
    overflow-x: hidden;
    padding: 14px 16px;
    background: #1a1a2e;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
    color: #f0f0f5;
    font-size: 12px;
    line-height: 1.5;
    text-align: left;
    pointer-events: auto;
    box-sizing: border-box;
}
.ux-model-info-tip .model-info-tip-title {
    font-weight: 600;
    font-size: 13px;
    margin: 0 0 6px;
    color: #ffffff;
}
.ux-model-info-tip .model-info-tip-excerpt {
    color: #d0d0e0;
    margin: 0 0 8px;
    white-space: pre-wrap;
}
.ux-model-info-tip .model-info-tip-specs {
    margin: 0 0 8px;
    padding-left: 16px;
    color: #c0c0d0;
}
.ux-model-info-tip .model-info-tip-specs li {
    margin: 0 0 4px;
}
.ux-model-info-tip .model-info-tip-link {
    display: inline-block;
    margin-top: 4px;
    padding: 0;
    border: none;
    background: none;
    color: #4a9eff;
    font-size: 12px;
    cursor: pointer;
    text-decoration: underline;
    user-select: none;
}

/* ============================
   INPUTS GLOBAUX
   ============================ */

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}

/* ============================
   ICONES DECLARATIVES (data-icon)
   ----------------------------
   Conteneur d'icone hydrate par UX.hydrateIcons (voir ux-components.js).
   Usage : <i data-icon="alert-circle"></i>
   La couleur suit currentColor, la taille suit la police (1em) sauf
   data-icon-size. Source unique : app Icones.
   ============================ */
[data-icon] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
    vertical-align: middle;
    flex-shrink: 0;
}

/* Listes déroulantes natives : harmoniser avec les champs (thème système + couleurs) */
select:not([multiple]) {
    color-scheme: dark;
}

[data-theme="light"] select:not([multiple]) {
    color-scheme: light;
}

select option {
    background-color: var(--bg-tertiary, #1a1a25);
    color: var(--text-primary, #f0f0f5);
}

select option:checked,
select option:hover {
    background-color: var(--bg-hover, rgba(255, 255, 255, 0.08));
    color: var(--text-primary, #f0f0f5);
}

/* Sélecteur stylé (liste HTML = même look que le champ) — activer avec data-ux-custom-select sur <select> */
.ux-select-wrap {
    position: relative;
    width: 100%;
    max-width: 100%;
}

select.ux-select-native-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
}

.ux-select-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 12px 40px 12px 16px;
    box-sizing: border-box;
    background-color: var(--bg-hover, rgba(255, 255, 255, 0.05));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    color: var(--text-primary, #f0f0f5);
    font-family: inherit;
    font-size: 14px;
    font-weight: 400;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--transition-fast, 0.15s ease), background var(--transition-fast, 0.15s ease), var(--ux-hover-rim-transition);
    user-select: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238888a0' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px;
}

.ux-select-trigger:hover {
    border-color: var(--border-hover, rgba(255, 255, 255, 0.12));
}

.ux-select-trigger:focus {
    outline: none;
    border-color: var(--border-focus, var(--accent-purple, #8b5cf6));
    background-color: rgba(139, 92, 246, 0.05);
}

.ux-select-trigger[aria-expanded="true"] {
    border-color: var(--border-focus, var(--accent-purple, #8b5cf6));
}

/* Etat enfoncé du trigger (meme rendu que .ux-btn) — :active + menu ouvert */
.ux-select-trigger:active:not(:disabled),
.ux-select-trigger[aria-expanded="true"],
.ux-select-trigger.ux-btn-pressed {
    box-shadow: var(--ux-btn-press-shadow);
    filter: var(--ux-btn-press-filter);
    transform: var(--ux-btn-press-offset);
}

.ux-select-wrap.ux-select-disabled .ux-select-trigger,
.ux-select-trigger:disabled {
    opacity: 0.5;
    cursor: default;
}

.ux-select-wrap.ux-select-disabled .ux-select-trigger:hover,
.ux-select-trigger:disabled:hover {
    border-color: var(--border, rgba(255, 255, 255, 0.08));
}

.ux-select-trigger-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ux-select-dropdown {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    z-index: 4000;
    margin-top: 4px;
    padding: 0;
    background: var(--bg-secondary, #12121a);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    box-shadow: var(--shadow-lg, 0 10px 40px rgba(0, 0, 0, 0.45));
    /* Hauteur max reelle posee en inline par le JS (surface disponible).
       Ce plafond CSS n'est qu'un filet de securite hors positionnement JS. */
    max-height: calc(100vh - 40px);
    max-width: min(480px, calc(100vw - 16px));
    overflow-x: hidden;
    overflow-y: auto;
    transform-origin: top center;
    transform-style: preserve-3d;
}

.ux-select-dropdown.ux-select-open {
    display: block;
    animation: uxSelectOpen 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.ux-select-dropdown.ux-select-open.ux-select-open-above {
    transform-origin: bottom center;
    animation-name: uxSelectOpenAbove;
}

.ux-select-dropdown:focus {
    outline: none;
}

.ux-select-dropdown.ux-select-flip {
    bottom: calc(100% + 4px);
    top: auto;
    margin-top: 0;
    margin-bottom: 4px;
}

/* Variante OS-level (rendue par os/app.js handleUXSelectOpen) :
   le contenu et le scroll sont deportes dans un wrapper interne pour que
   la scrollbar webkit soit clippee proprement par le border-radius du
   container externe. */
.ux-select-dropdown-os {
    overflow: hidden !important;
    padding: 0;
    box-sizing: border-box;
    min-width: 220px;
    width: max-content;
    /* Annule left:0 / right:0 de .ux-select-dropdown : en position:fixed
       ces deux ancres coinceraient la liste a 0–1 px de large. */
    left: auto;
    right: auto;
}
.ux-select-scroll {
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    /* Pas de padding vertical : le premier item colle le haut du menu
       (alignement avec le rendu canonique de l'app UX). */
    padding: 0;
    /* La hauteur max est posee par JS (positionList) en sync avec celle
       du container externe. */
}
/* Scrollbar des listes deroulantes : meme capsule que la plateforme. */
.ux-select-dropdown::-webkit-scrollbar,
.ux-select-scroll::-webkit-scrollbar {
    width: var(--ux-scrollbar-size, 10px);
    height: var(--ux-scrollbar-size, 10px);
}
.ux-select-dropdown::-webkit-scrollbar-track,
.ux-select-scroll::-webkit-scrollbar-track {
    background: transparent;
}
.ux-select-dropdown::-webkit-scrollbar-thumb,
.ux-select-scroll::-webkit-scrollbar-thumb {
    background-color: var(--ux-scrollbar-thumb, rgba(255, 255, 255, 0.14));
    background-image: none;
    border: 2px solid transparent;
    background-clip: padding-box;
    border-radius: 999px;
}
.ux-select-dropdown::-webkit-scrollbar-thumb:hover,
.ux-select-scroll::-webkit-scrollbar-thumb:hover {
    background-color: var(--ux-scrollbar-thumb-hover, rgba(255, 255, 255, 0.20));
    background-image: none;
}
.ux-select-dropdown::-webkit-scrollbar-button,
.ux-select-scroll::-webkit-scrollbar-button { display: none !important; }

@keyframes uxSelectOpen {
    from {
        opacity: 0;
        transform: perspective(900px) rotateX(-22deg) scale(0.96);
    }
    to {
        opacity: 1;
        transform: perspective(900px) rotateX(0deg) scale(1);
    }
}
@keyframes uxSelectOpenAbove {
    from {
        opacity: 0;
        transform: perspective(900px) rotateX(22deg) scale(0.96);
    }
    to {
        opacity: 1;
        transform: perspective(900px) rotateX(0deg) scale(1);
    }
}

.ux-select-option {
    padding: 10px 16px;
    font-size: 14px;
    color: var(--text-primary, #f0f0f5);
    cursor: pointer;
    transition: background 0.1s ease;
    user-select: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Options riches (ligne / stack) : ne pas forcer nowrap sur le conteneur. */
.ux-select-option:has(.ux-select-option-row) {
    white-space: normal;
    text-overflow: clip;
}

.ux-select-option:hover,
.ux-select-option.ux-select-option-active {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
}

.ux-select-option.is-selected {
    color: var(--accent-purple, #8b5cf6);
    font-weight: 500;
}

.ux-select-option[disabled] {
    opacity: 0.45;
    cursor: default;
    pointer-events: none;
}

.ux-select-optgroup-label {
    padding: 8px 16px 4px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #a0aec0);
    cursor: default;
    user-select: none;
    opacity: 0.7;
}

.ux-select-optgroup-label:not(:first-child) {
    margin-top: 4px;
    border-top: 1px solid var(--border, rgba(255, 255, 255, 0.06));
    padding-top: 10px;
}

.ux-select-option-grouped {
    padding-left: 24px;
}

/* Ligne riche dans un select (nom + meta alignée à droite).
   Utilisé p.ex. par Admin > Modèles LLM (data-ux-html). */
.ux-select-option-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
}
/* Variante empilee (titre + meta en dessous) — gain de largeur dans le trigger */
.ux-select-option-row.ux-select-option-stack {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
}
.ux-select-option-row.ux-select-option-stack .ux-select-option-primary {
    font-family: inherit;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.2;
}
.ux-select-option-row.ux-select-option-stack .ux-select-option-meta {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.2;
}
.ux-select-option-primary {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
    letter-spacing: -0.01em;
}
.ux-select-option-meta {
    flex: 0 0 auto;
    font-size: 11px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary, #a0aec0);
    white-space: nowrap;
    opacity: 0.9;
}
.ux-select-option-action {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin: -4px -6px -4px 0;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--text-secondary, #a0aec0);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}
.ux-select-option-action:hover {
    color: var(--text-primary, #f0f0f5);
    background: rgba(255, 255, 255, 0.08);
}
.ux-select-option-action:active,
.ux-select-option-action.ux-btn-pressed {
    filter: brightness(0.65);
}
.ux-select-option-action i,
.ux-select-option-action svg {
    width: 14px;
    height: 14px;
    display: block;
}
/* Action texte dans une ligne de liste (ex. « Appliquer »), revelee au survol
   de la ligne. Sur ecran tactile (pas de survol), elle reste visible. */
.ux-select-option-text-action {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    height: 22px;
    margin: -3px -4px -3px 10px;
    padding: 0 9px;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.12));
    border-radius: 6px;
    background: var(--bg-tertiary, rgba(255, 255, 255, 0.06));
    color: var(--text-primary, #f0f0f5);
    font-family: inherit;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: box-shadow var(--ux-hover-rim-transition, 0.2s);
}
@media (hover: hover) {
    .ux-select-option-text-action:hover { box-shadow: var(--ux-hover-rim-shadow, 0 0 0 1px rgba(255, 255, 255, 0.5)); }
    .ux-select-option .ux-select-option-hover-only { visibility: hidden; }
    .ux-select-option:hover .ux-select-option-hover-only,
    .ux-select-option:focus-within .ux-select-option-hover-only { visibility: visible; }
}
.ux-select-option-text-action:active,
.ux-select-option-text-action.ux-btn-pressed {
    filter: brightness(0.65);
    box-shadow: none;
}
.ux-select-option-row.ux-select-option-stack .ux-select-option-meta {
    white-space: normal;
}
.ux-select-option-prov {
    font-weight: 500;
    font-family: inherit;
    color: var(--text-secondary, #a0aec0);
    opacity: 0.9;
}
.ux-select-option.is-selected .ux-select-option-prov {
    color: inherit;
    opacity: 0.7;
}
.ux-select-option.is-selected .ux-select-option-meta {
    color: inherit;
    opacity: 0.75;
}
.ux-select-trigger-label:has(.ux-select-option-row) {
    display: flex;
    white-space: normal;
    text-overflow: clip;
    overflow: hidden;
}
.ux-select-trigger-label .ux-select-option-row {
    width: 100%;
}
.ux-select-trigger-label .ux-select-option-primary {
    font-size: 13px;
}
.ux-select-trigger-label .ux-select-option-meta {
    font-size: 11px;
}

/* Aperçu de style de paragraphe (Documents, menu Titre). Rendu OS-delegue :
   ces classes doivent vivre ici, pas dans le CSS de l'app. */
.ux-select-option:has(.ux-para-style) {
    white-space: normal;
    text-overflow: clip;
    overflow: visible;
    padding: 8px 10px 10px;
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.06));
}
.ux-select-option:has(.ux-para-style):last-child {
    border-bottom: none;
}
.ux-select-option-row.ux-select-option-stack.ux-para-style,
.ux-para-style {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 7px;
    width: 100%;
    min-width: 0;
}
.ux-para-style-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}
.ux-para-style-name {
    font-size: 12px;
    font-weight: 650;
    letter-spacing: 0.01em;
    color: var(--text-primary, #f0f0f5);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ux-para-style-head-aside {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    margin-left: auto;
}
.ux-para-style-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.ux-para-style-swatches {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
}
@media (hover: hover) {
    .ux-para-style-actions {
        max-width: 0;
        opacity: 0;
        overflow: hidden;
        pointer-events: none;
        gap: 0;
    }
    .ux-select-option:hover .ux-para-style-actions,
    .ux-select-option:focus-within .ux-para-style-actions {
        max-width: 220px;
        opacity: 1;
        overflow: visible;
        pointer-events: auto;
        gap: 6px;
    }
    .ux-para-style-actions .ux-select-option-hover-only {
        visibility: visible;
    }
}
.ux-para-style-swatch {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.22), 0 0 0 1px rgba(255, 255, 255, 0.12);
    flex-shrink: 0;
}
.ux-para-style-swatch-bg {
    border-radius: 3px;
}
.ux-para-style-page {
    display: block;
    width: 100%;
    box-sizing: border-box;
    border-radius: 7px;
    overflow: hidden;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.10);
    background: #ffffff;
    color: #111111;
}
.ux-select-option:hover .ux-para-style-page,
.ux-select-option.ux-select-option-active .ux-para-style-page {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16), 0 3px 10px rgba(0, 0, 0, 0.16);
}
.ux-para-style-sample {
    color: inherit;
    font-family: inherit;
}
.ux-para-style-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    min-width: 0;
}
.ux-para-style-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 18px;
    padding: 0 7px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.06);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text-secondary, #a0aec0);
    line-height: 1;
    white-space: nowrap;
}
.ux-para-style-chip-on {
    background: rgba(139, 92, 246, 0.16);
    color: var(--text-primary, #f0f0f5);
}
.ux-para-style-align {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    width: 11px;
    height: 10px;
}
.ux-para-style-align i {
    display: block;
    height: 1.5px;
    border-radius: 1px;
    background: currentColor;
    opacity: 0.75;
}
.ux-para-style-align[data-align="left"] i:nth-child(1),
.ux-para-style-align[data-align="right"] i:nth-child(1) { width: 100%; }
.ux-para-style-align[data-align="left"] i:nth-child(2) { width: 68%; }
.ux-para-style-align[data-align="left"] i:nth-child(3) { width: 86%; }
.ux-para-style-align[data-align="right"] i { margin-left: auto; }
.ux-para-style-align[data-align="right"] i:nth-child(2) { width: 68%; }
.ux-para-style-align[data-align="right"] i:nth-child(3) { width: 86%; }
.ux-para-style-align[data-align="center"] i { width: 70%; margin-inline: auto; }
.ux-para-style-align[data-align="center"] i:nth-child(2) { width: 100%; }
.ux-para-style-align[data-align="justify"] i { width: 100%; }
.ux-select-option.is-selected .ux-para-style-page {
    box-shadow: inset 0 0 0 1px rgba(139, 92, 246, 0.42);
}
.ux-select-option.is-selected .ux-para-style-name {
    color: inherit;
}
.ux-select-option.is-selected .ux-para-style-chip {
    color: inherit;
    opacity: 0.82;
}
.ux-para-style .ux-select-option-text-action {
    margin: 0;
}

/* ============================
   MENU D'ACTIONS (popover déclenché par bouton)
   ----------------------------
   Aligné sur .ux-select-dropdown. Pattern utilisé p.ex. par le bouton "+"
   dans la zone de saisie de l'Assistant. Différent de .ux-context-menu
   (clic droit) et de <select data-ux-custom-select>.

   ATTENTION : ne JAMAIS poser padding/border/background/border-radius/
   box-shadow via style inline ou cssText en JS — ces déclarations
   battent le CSS et masquent silencieusement les corrections de style.
   Le JS ne doit positionner que (position, top, left, width, max-height,
   z-index, display).
   ============================ */

.ux-action-menu-wrap {
    position: relative;
    display: inline-block;
    /* Le menu absolute ne doit pas etre rogne par un ancetre overflow */
    z-index: 1;
}

.ux-action-menu {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 4000;
    min-width: 240px;
    margin: 0;
    padding: 0;
    background: var(--bg-secondary, #12121a);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    box-shadow: var(--shadow-lg, 0 10px 40px rgba(0, 0, 0, 0.45));
    overflow: hidden;
    animation: uxSelectOpen 0.12s ease;
}

.ux-action-menu.open {
    display: block;
}

.ux-action-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    padding: 10px 16px;
    border: none;
    border-radius: 0;
    background: transparent;
    appearance: none;
    -webkit-appearance: none;
    color: var(--text-primary, #f0f0f5);
    font-family: inherit;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
    user-select: none;
    transition: background 0.1s ease;
}

.ux-action-menu-item:hover,
.ux-action-menu-item:focus-visible {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
    outline: none;
}

.ux-action-menu-item.is-danger {
    color: var(--error, #ef4444);
}

.ux-action-menu-item.is-danger:hover,
.ux-action-menu-item.is-danger:focus-visible {
    background: rgba(239, 68, 68, 0.12);
}

.ux-action-menu-item[disabled] {
    opacity: 0.45;
    cursor: default;
    pointer-events: none;
}

.ux-action-menu-item svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
}

.ux-action-menu-separator {
    height: 1px;
    margin: 4px 0;
    background: var(--border, rgba(255, 255, 255, 0.08));
}

/* ============================
   BOUTONS STANDARD
   ============================ */

.ux-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    /* Padding asymetrique : centrage optique (le glyphe sans-serif parait
       legerement trop bas avec un padding symetrique 12/12). */
    padding: 11px 20px 13px;
    border: none;
    border-radius: 10px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    /* Survol = liseret fluo ; clic / enfoncé = ombre interne + assombrissement. */
    transition: var(--ux-hover-rim-transition);
    user-select: none;
    white-space: nowrap;
}

/* display:inline-flex ci-dessus bat le [hidden] UA — rétablir le masquage. */
.ux-btn[hidden],
a.ux-btn[hidden],
button.ux-btn[hidden] {
    display: none !important;
}

.ux-btn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    flex-shrink: 0;
    display: block;
}

/* App Icônes : Material = fill, Feather/Lucide = trait.
   Sans cette exception, .ux-btn svg { fill:none; stroke } rend les
   icônes Material illisibles (trop grasses ou fantômes). */
svg.svg-fill,
svg.svg-fill * {
    fill: currentColor;
    stroke: none;
}
.ux-btn svg.svg-fill,
.ux-btn svg.svg-fill * {
    fill: currentColor;
    stroke: none;
    stroke-width: 0;
}

/* Bouton par défaut = Vert (action principale) */
.ux-btn-default, .ux-btn {
    background: var(--ux-btn-default);
    color: white;
}

/* Bouton primaire = Bleu */
.ux-btn-primary {
    background: var(--ux-btn-primary);
    color: white;
}

/* Bouton secondaire */
.ux-btn-secondary {
    background: var(--ux-btn-secondary);
    color: var(--text-primary, #f0f0f5);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
}

/*
 * Opt-in pour boutons custom d'apps (ex. Admin > Fournisseurs) :
 * meme liseret au survol + enfoncé au clic que .ux-btn / .btn,
 * sans imposer le look complet d'un bouton UX.
 */
.ux-pressable {
    transition: var(--ux-hover-rim-transition);
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

/* Bouton danger */
.ux-btn-danger {
    background: var(--ux-btn-danger);
    color: white;
}

/* Variations de couleur */
.ux-btn-purple {
    background: var(--ux-btn-purple);
    color: white;
}

.ux-btn-pink {
    background: var(--ux-btn-pink);
    color: white;
}

.ux-btn-orange {
    background: var(--ux-btn-orange);
    color: white;
}

.ux-btn-cyan {
    background: var(--ux-btn-cyan);
    color: white;
}

/*
 * Feedback au clic / touch — UX.runButtonPress / installButtonPressFeedback :
 * pointerdown → enfoncé ; pointerup → restauration immédiate ; click → action.
 * Rendu enfoncé : ombre interne (creux) + assombrissement fond/texte
 * + liseret clair uniforme tout autour.
 * Survol : liseret blanc fluo (voir bloc plus bas).
 */
.ux-btn.ux-btn-pressed,
.ux-dialog-btn.ux-btn-pressed,
.btn.ux-btn-pressed,
.ux-pressable.ux-btn-pressed,
.ux-dialog-close.ux-btn-pressed,
.os-dialog-close.ux-btn-pressed,
.ux-mobile-back.ux-btn-pressed,
.window-btn.ux-btn-pressed,
.taskbar-desktop-btn.ux-btn-pressed,
.taskbar-app.ux-btn-pressed,
.notification-btn.ux-btn-pressed,
.account-btn.ux-btn-pressed,
.system-tray.ux-btn-pressed,
.systasks-btn.ux-btn-pressed,
.system-panel-btn.ux-btn-pressed,
.system-panel-option.ux-btn-pressed,
.sys-control-row.ux-btn-pressed,
.notification-item-btn.ux-btn-pressed,
.notification-action-btn.ux-btn-pressed,
.account-zone.ux-btn-pressed,
.account-action-btn.ux-btn-pressed,
.account-recent-toggle.ux-btn-pressed,
.account-recent-item.ux-btn-pressed,
.account-request-btn.ux-btn-pressed,
.account-recent-remove.ux-btn-pressed,
.boreal-sys-icon.ux-btn-pressed,
.boreal-power-btn.ux-btn-pressed,
.boreal-subpanel-back.ux-btn-pressed,
.boreal-net-scan.ux-btn-pressed,
.boreal-wifi-go.ux-btn-pressed,
.boreal-vol-mute.ux-btn-pressed,
.boreal-audio-test.ux-btn-pressed,
.systasks-close.ux-btn-pressed,
.systasks-task-cancel.ux-btn-pressed,
.sysmenu-tab.ux-btn-pressed,
.mode-selector-btn.ux-btn-pressed,
.win-close-btn.ux-btn-pressed,
.ux-btn:active:not(:disabled):not([disabled]),
.ux-dialog-btn:active:not(:disabled):not([disabled]),
.btn:active:not(:disabled):not([disabled]),
.ux-pressable:active:not(:disabled):not([disabled]),
.ux-dialog-close:active,
.os-dialog-close:active,
.ux-mobile-back:active,
.window-btn:active:not(:disabled),
.taskbar-desktop-btn:active,
.taskbar-app:active,
.notification-btn:active,
.account-btn:active,
.system-tray:active,
.systasks-btn:active,
.system-panel-btn:active,
.system-panel-option:active,
.sys-control-row:active,
.notification-item-btn:active,
.notification-action-btn:active,
.account-zone:active,
.account-action-btn:active,
.account-recent-toggle:active,
.account-recent-item:active,
.account-request-btn:active,
.account-recent-remove:active,
.boreal-sys-icon:active,
.boreal-power-btn:active,
.boreal-subpanel-back:active,
.boreal-net-scan:active,
.boreal-wifi-go:active,
.boreal-vol-mute:active,
.boreal-audio-test:active,
.systasks-close:active,
.systasks-task-cancel:active,
.sysmenu-tab:active,
.mode-selector-btn:active,
.win-close-btn:active,
/* Etat enfoncé stable : toggle menu/popup / tray tant que ouvert */
.ux-btn[aria-expanded="true"],
.btn[aria-expanded="true"],
.ux-pressable[aria-expanded="true"],
.ux-btn.ux-btn-open,
.btn.ux-btn-open,
.ux-pressable.ux-btn-open,
.notification-btn.active,
.account-btn.active,
.system-tray.active,
.systasks-btn.active {
    box-shadow: var(--ux-btn-press-shadow);
    filter: var(--ux-btn-press-filter);
    transform: var(--ux-btn-press-offset);
}

.ux-btn.ux-btn-pressing,
.ux-dialog-btn.ux-btn-pressing,
.btn.ux-btn-pressing,
.ux-pressable.ux-btn-pressing,
.ux-dialog-close.ux-btn-pressing,
.os-dialog-close.ux-btn-pressing,
.window-btn.ux-btn-pressing,
.taskbar-desktop-btn.ux-btn-pressing,
.taskbar-app.ux-btn-pressing,
.system-panel-btn.ux-btn-pressing,
.system-panel-option.ux-btn-pressing,
.sys-control-row.ux-btn-pressing,
.notification-item-btn.ux-btn-pressing,
.notification-action-btn.ux-btn-pressing,
.account-zone.ux-btn-pressing,
.account-action-btn.ux-btn-pressing,
.account-recent-toggle.ux-btn-pressing,
.account-recent-item.ux-btn-pressing,
.account-request-btn.ux-btn-pressing,
.account-recent-remove.ux-btn-pressing,
.boreal-power-btn.ux-btn-pressing,
.boreal-subpanel-back.ux-btn-pressing,
.boreal-net-scan.ux-btn-pressing,
.boreal-wifi-go.ux-btn-pressing,
.boreal-vol-mute.ux-btn-pressing,
.boreal-audio-test.ux-btn-pressing,
.systasks-close.ux-btn-pressing,
.systasks-task-cancel.ux-btn-pressing,
.mode-selector-btn.ux-btn-pressing,
.win-close-btn.ux-btn-pressing {
    pointer-events: none;
}

/* Bouton désactivé — pas de cursor: not-allowed (règle plateforme) */
.ux-btn:disabled,
.ux-btn[disabled] {
    opacity: 0.45;
    cursor: default;
    box-shadow: none;
    filter: none;
    transform: none;
}

/*
 * Liseret blanc fluo au survol — contour uniquement (alpha 50 %, 0.2s).
 * Absent pendant le clic / l'état enfoncé.
 * Limite aux pointeurs fins : evite l'etat « colle » au tactile.
 */
@media (hover: hover) {
    .ux-btn:hover:not(:disabled):not([disabled]):not(:active):not(.ux-btn-pressing):not(.ux-btn-pressed):not([aria-expanded="true"]):not(.ux-btn-open),
    .ux-dialog-btn:hover:not(:disabled):not([disabled]):not(:active):not(.ux-btn-pressing):not(.ux-btn-pressed),
    .btn:hover:not(:disabled):not([disabled]):not(:active):not(.ux-btn-pressing):not(.ux-btn-pressed):not([aria-expanded="true"]):not(.ux-btn-open),
    .ux-pressable:hover:not(:disabled):not([disabled]):not(:active):not(.ux-btn-pressing):not(.ux-btn-pressed):not([aria-expanded="true"]):not(.ux-btn-open),
    .ux-segment-btn:hover:not(:disabled):not(:active):not(.ux-btn-pressing),
    .ux-select-trigger:hover:not(:disabled):not(:active):not(.ux-btn-pressed):not([aria-expanded="true"]),
    .ux-slide-delete-btn:hover:not(:active),
    .sidebar-add-btn:hover:not(:active),
    .sidebar-tab-add-btn:hover:not(:active),
    .ux-dialog-close:hover:not(:active):not(.ux-btn-pressed),
    .os-dialog-close:hover:not(:active):not(.ux-btn-pressed),
    .ux-mobile-back:hover:not(:active):not(.ux-btn-pressed):not(.ux-btn-pressing),
    .window-btn:hover:not(:active):not(.ux-btn-pressed):not(:disabled),
    .taskbar-desktop-btn:hover:not(:active):not(.ux-btn-pressed),
    .taskbar-app:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .notification-btn:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .account-btn:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .system-tray:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .systasks-btn:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .system-panel-btn:hover:not(:active):not(.ux-btn-pressed),
    .system-panel-option:hover:not(:active):not(.ux-btn-pressed),
    .sys-control-row:hover:not(:active):not(.ux-btn-pressed),
    .notification-item-btn:hover:not(:active):not(.ux-btn-pressed),
    .notification-action-btn:hover:not(:active):not(.ux-btn-pressed),
    .account-zone:hover:not(:active):not(.ux-btn-pressed),
    .account-action-btn:hover:not(:active):not(.ux-btn-pressed),
    .account-recent-toggle:hover:not(:active):not(.ux-btn-pressed),
    .account-recent-item:hover:not(:active):not(.ux-btn-pressed),
    .account-request-btn:hover:not(:active):not(.ux-btn-pressed),
    .account-recent-remove:hover:not(:active):not(.ux-btn-pressed),
    .boreal-sys-icon:hover:not(:active):not(.ux-btn-pressed),
    .boreal-power-btn:hover:not(:active):not(.ux-btn-pressed),
    .boreal-subpanel-back:hover:not(:active):not(.ux-btn-pressed),
    .boreal-net-scan:hover:not(:active):not(.ux-btn-pressed),
    .boreal-wifi-go:hover:not(:active):not(.ux-btn-pressed),
    .boreal-vol-mute:hover:not(:active):not(.ux-btn-pressed),
    .boreal-audio-test:hover:not(:active):not(.ux-btn-pressed),
    .systasks-close:hover:not(:active):not(.ux-btn-pressed),
    .systasks-task-cancel:hover:not(:active):not(.ux-btn-pressed),
    .sysmenu-tab:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .mode-selector-btn:hover:not(.active):not(:active):not(.ux-btn-pressed),
    .win-close-btn:hover:not(:active):not(.ux-btn-pressed) {
        box-shadow: var(--ux-hover-rim-shadow);
    }

    .ux-select-wrap.ux-select-disabled .ux-select-trigger:hover,
    .ux-select-trigger:disabled:hover,
    .ux-segment.is-disabled .ux-segment-btn:hover {
        box-shadow: none;
    }

    .ux-checkbox-item:hover .ux-checkbox-custom,
    .ux-radio-item:hover .ux-radio-custom,
    .ux-toggle-item:hover .ux-toggle-switch {
        box-shadow: var(--ux-hover-rim-shadow);
    }
}

/* Tailles de boutons */
.ux-btn-sm {
    padding: 7px 14px 9px;
    font-size: 13px;
}

.ux-btn-lg {
    padding: 15px 28px 17px;
    font-size: 16px;
}

/* Bouton icone-only (carre, contient un seul SVG) :
   on force le centrage parfait + un padding compact symetrique. */
.ux-btn-icon {
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    gap: 0;
    padding: 8px;
    line-height: 1;
    flex: 0 0 auto;
}
.ux-btn-icon > svg {
    display: block;
    margin: 0;
}

/* ============================
   SLIDE-TO-DELETE
   
   Principe anti double-clic :
   1. Premier clic → "Confirmer?" apparaît à droite du bouton
   2. Le container s'agrandit → pousse les boutons adjacents vers la gauche
   3. Deuxième clic → exécute l'action (le bouton "Modifier" a bougé)
   
   Structure HTML requise:
   <div class="ux-slide-delete-container">
       <button class="ux-slide-delete-btn">Supprimer</button>
       <span class="ux-slide-delete-confirm">Confirmer?</span>
   </div>
   ============================ */

.ux-slide-delete-container {
    display: inline-flex;
    align-items: center;
    height: 38px;
}

.ux-slide-delete-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 9px 14px;
    background: var(--ux-btn-danger);
    border: none;
    border-radius: 8px;
    color: white;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, var(--ux-hover-rim-transition);
    user-select: none;
    white-space: nowrap;
    flex-shrink: 0;
}

.ux-slide-delete-btn:hover {
    background: var(--ux-btn-danger-hover);
}

.ux-slide-delete-btn svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
    flex-shrink: 0;
}

.ux-slide-delete-confirm {
    color: #f87171;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    max-width: 0;
    opacity: 0;
    padding: 0;
    transition: max-width 0.3s cubic-bezier(0.4, 0, 0.2, 1), 
                opacity 0.2s ease 0.1s,
                padding 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* État révélé :
   - Le texte "Confirmer?" apparaît à droite du bouton
   - Le container s'agrandit → pousse les boutons adjacents vers la gauche
*/
.ux-slide-delete-container.revealed .ux-slide-delete-confirm {
    max-width: 90px;
    opacity: 1;
    padding-left: 10px;
}

/* ============================
   SLIDE TO CONFIRM (style iPhone "slide to unlock")

   Slider draggable de gauche a droite pour confirmer une action critique.
   Utilisation via UX.slideToConfirm({ container, label, color, onConfirm }).

   Structure HTML (generee par UX.slideToConfirm) :
   <div class="ux-slide-to-confirm">
       <div class="ux-stc-track">
           <div class="ux-stc-fill"></div>
           <div class="ux-stc-label">Glisser pour confirmer</div>
           <div class="ux-stc-handle"><svg>...</svg></div>
       </div>
   </div>
   ============================ */

.ux-slide-to-confirm {
    --ux-stc-color: #dc2626;
    --ux-stc-height: 52px;
    --ux-stc-handle-size: 44px;
    width: 100%;
    user-select: none;
    -webkit-user-select: none;
}

.ux-slide-to-confirm .ux-stc-track {
    position: relative;
    height: var(--ux-stc-height);
    border-radius: calc(var(--ux-stc-height) / 2);
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    overflow: hidden;
    display: flex;
    align-items: center;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
}

.ux-slide-to-confirm .ux-stc-fill {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: calc(var(--ux-stc-handle-size) + 8px);
    background: var(--ux-stc-color);
    border-radius: calc(var(--ux-stc-height) / 2);
    z-index: 1;
    transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.ux-slide-to-confirm .ux-stc-label {
    position: relative;
    z-index: 2;
    width: 100%;
    text-align: center;
    color: var(--text-secondary, #a0aec0);
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0.2px;
    pointer-events: none;
    padding: 0 calc(var(--ux-stc-handle-size) + 12px);
    box-sizing: border-box;
    transition: opacity 0.25s ease, color 0.2s ease;
}

.ux-slide-to-confirm .ux-stc-handle {
    position: absolute;
    top: 50%;
    left: 4px;
    width: var(--ux-stc-handle-size);
    height: var(--ux-stc-handle-size);
    margin-top: calc(var(--ux-stc-handle-size) / -2);
    border-radius: 50%;
    background: var(--ux-stc-color);
    color: #ffffff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    z-index: 3;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.2);
    touch-action: none;
    outline: none;
    transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.15s ease;
}

.ux-slide-to-confirm .ux-stc-handle:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.ux-slide-to-confirm .ux-stc-handle:focus-visible {
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25), 0 2px 8px rgba(0, 0, 0, 0.35);
}

.ux-slide-to-confirm.dragging .ux-stc-handle,
.ux-slide-to-confirm .ux-stc-handle:active {
    cursor: grabbing;
}

.ux-slide-to-confirm .ux-stc-handle svg {
    width: 22px;
    height: 22px;
}

.ux-slide-to-confirm.confirmed .ux-stc-label {
    color: #ffffff;
    opacity: 1;
}

/* ============================
   CHECKBOXES & TOGGLES
   ============================ */

.ux-checkbox-group,
.ux-toggle-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.ux-checkbox-item,
.ux-toggle-item {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    user-select: none;
}

.ux-checkbox-item input,
.ux-toggle-item input {
    position: fixed;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
}

.ux-checkbox-custom {
    width: 22px;
    height: 22px;
    border: 2px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--ux-transition-fast), border-color var(--ux-transition-fast), var(--ux-hover-rim-transition);
    flex-shrink: 0;
}

.ux-checkbox-item input:checked + .ux-checkbox-custom {
    background: var(--ux-btn-default);
    border-color: var(--ux-btn-default);
}

.ux-checkbox-custom::after {
    content: '';
    width: 12px;
    height: 12px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    opacity: 0;
    transition: opacity var(--ux-transition-fast);
}

.ux-checkbox-item input:checked + .ux-checkbox-custom::after {
    opacity: 1;
}

/* Radio — même principe que la case : input masqué + pastille circulaire (point vert) */
.ux-radio-group {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.ux-radio-item {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
    user-select: none;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.35;
    color: var(--text-primary, inherit);
}

.ux-radio-item input {
    position: fixed;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
}

.ux-radio-custom {
    width: 22px;
    height: 22px;
    border: 2px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: border-color var(--ux-transition-fast), background var(--ux-transition-fast), var(--ux-hover-rim-transition);
    flex-shrink: 0;
    box-sizing: border-box;
}

.ux-radio-item input:checked + .ux-radio-custom {
    border-color: rgba(46, 204, 113, 0.3);
    background: rgba(46, 204, 113, 0.3);
}

.ux-radio-custom::after {
    content: '';
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--ux-btn-default);
    opacity: 0;
    transform: scale(0.5);
    transition: opacity var(--ux-transition-fast), transform var(--ux-transition-fast);
}

.ux-radio-item input:checked + .ux-radio-custom::after {
    opacity: 1;
    transform: scale(1);
}

/* Toggle switch */
.ux-toggle-switch {
    width: 44px;
    height: 24px;
    background: var(--ux-toggle-off-track, var(--bg-active, rgba(255, 255, 255, 0.1)));
    border-radius: 12px;
    position: relative;
    transition: background var(--ux-transition-fast), var(--ux-hover-rim-transition);
    flex-shrink: 0;
}

.ux-toggle-switch::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background: var(--ux-toggle-off-knob, #8888a0);
    border-radius: 50%;
    transition: all var(--ux-transition-fast);
}

.ux-toggle-item input:checked + .ux-toggle-switch {
    background: rgba(46, 204, 113, 0.3);
}

.ux-toggle-item input:checked + .ux-toggle-switch::after {
    left: 22px;
    background: var(--ux-btn-default);
}

/* ============================
   SEGMENT / SWITCHS ENFONCÉS
   (UX.attachSegment — choix exclusif 2–5 options)
   ============================ */

.ux-segment {
    display: inline-flex;
    flex-wrap: nowrap;
    align-items: stretch;
    width: 100%;
    gap: 0;
    padding: 3px;
    box-sizing: border-box;
    background: var(--bg-hover, rgba(255, 255, 255, 0.04));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    user-select: none;
}

.ux-segment-btn {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0;
    padding: 8px 12px;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: var(--text-secondary, #a0aec0);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.2;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.12s ease, color 0.12s ease, var(--ux-hover-rim-transition);
    user-select: none;
}

.ux-segment-btn:disabled,
.ux-segment.is-disabled .ux-segment-btn {
    opacity: 0.45;
    cursor: default;
}

.ux-segment-btn.is-active {
    background: var(--ux-btn-secondary, rgba(255, 255, 255, 0.08));
    color: var(--text-primary, #f0f0f5);
    box-shadow: inset 0 0 0 1px var(--border, rgba(255, 255, 255, 0.06));
}

.ux-segment-btn.is-active[aria-pressed="true"] {
    /* État enfoncé stable (différent du feedback clic .ux-btn-pressed) */
    filter: none;
}

/* ============================
   ZONE EXPANDABLE (accordéon)
   UX.attachExpand — data-ux-expand
   Fermé : bouton 10px / 3px. Ouvert : chrome sur .ux-expand (bloc unique,
   même fond, sans séparateur, bords alignés — plus de décalage 1px).
   ============================ */

.ux-expand {
    width: 100%;
    box-sizing: border-box;
}

.ux-expand-toggle {
    /* Base propre — ne pas combiner avec .ux-pressable / .ux-btn */
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 12px;
    margin: 0;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    /* Haut 10px, bas 3px (remplace l’ancien 0) */
    border-radius: 10px 10px 3px 3px;
    background: var(--bg-secondary, rgba(18, 18, 26, 0.95));
    color: var(--text-primary, #f0f0f5);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    text-align: left;
    font: inherit;
    box-sizing: border-box;
    transition: var(--ux-hover-rim-transition, box-shadow 0.2s ease);
    /* Neutraliser l’héritage presse (.ux-pressable / aria-expanded / :active) */
    filter: none;
    transform: none;
    box-shadow: none;
}

.ux-expand-toggle:active,
.ux-expand-toggle:focus,
.ux-expand-toggle.ux-btn-pressed,
.ux-expand-toggle.ux-btn-pressing,
.ux-expand-toggle[aria-expanded="true"] {
    filter: none;
    transform: none;
    outline: none;
}

.ux-expand-toggle:focus-visible {
    box-shadow: var(--ux-hover-rim-shadow, 0 0 0 1px rgba(255, 255, 255, 0.5));
}

/* Ouvert : bordure + fond + radius sur le conteneur (un seul bloc) */
.ux-expand.is-open {
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px 10px 3px 3px;
    background: var(--bg-secondary, rgba(18, 18, 26, 0.95));
    overflow: hidden;
}

.ux-expand.is-open .ux-expand-toggle {
    border: none;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    filter: none;
    transform: none;
}

.ux-expand.is-open .ux-expand-panel {
    border: none;
    border-radius: 0;
    background: transparent;
}

@media (hover: hover) {
    .ux-expand-toggle:hover:not(:disabled):not([aria-expanded="true"]) {
        box-shadow: var(--ux-hover-rim-shadow, 0 0 0 1px rgba(255, 255, 255, 0.5));
    }
}

.ux-expand-toggle-main {
    display: flex;
    align-items: baseline;
    gap: 12px;
    min-width: 0;
    flex-wrap: wrap;
    flex: 1 1 auto;
}

.ux-expand-title {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary, #f0f0f5);
}

.ux-expand-meta {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary, #f0f0f5);
    font-variant-numeric: tabular-nums;
}

.ux-expand-chevron {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    color: var(--text-secondary, #a0aec0);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.28s ease;
}

.ux-expand-chevron [data-icon],
.ux-expand-chevron i,
.ux-expand-chevron svg {
    width: 18px;
    height: 18px;
}

.ux-expand-toggle[aria-expanded="true"] .ux-expand-chevron {
    transform: rotate(180deg);
}

.ux-expand-panel {
    width: 100%;
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.32s ease;
    /* Chrome porté par .ux-expand.is-open */
    border: none;
    border-radius: 0;
    background: transparent;
    overflow: hidden;
    box-sizing: border-box;
}

.ux-expand-panel.is-open {
    grid-template-rows: 1fr;
}

.ux-expand-inner {
    min-height: 0;
    overflow: hidden;
    padding: 0 12px;
    opacity: 0;
    transition: opacity 0.28s ease, padding 0.32s ease;
    box-sizing: border-box;
}

.ux-expand-panel.is-open .ux-expand-inner {
    padding: 12px;
    opacity: 1;
}

/* ============================
   FIN ZONE EXPANDABLE
   ============================ */

/* ============================
   ZONE D'IMPORT MÉDIA
   UX.attachMediaDrop — data-ux-media-drop
   Pattern Coller / Importer (réf. Cinéaste / Images).
   Boutons un peu plus hauts (min-height 34px) pour faciliter le clic.
   ============================ */

.ux-media-drop {
    position: relative;
    flex: 1;
    min-width: 0;
    box-sizing: border-box;
}

.ux-media-drop-zone {
    border: 2px dashed var(--border, rgba(255, 255, 255, 0.12));
    border-radius: 10px;
    padding: 16px;
    text-align: center;
    user-select: none;
    -webkit-user-select: none;
    position: relative;
    background: var(--bg-tertiary, rgba(255, 255, 255, 0.03));
    transition: border-color 0.15s ease, background 0.15s ease;
    box-sizing: border-box;
    min-height: 88px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.ux-media-drop-zone:hover {
    border-color: var(--accent, #4a9eff);
}

.ux-media-drop-zone.is-dragover,
.ux-media-drop-zone.drag-over {
    border-color: var(--accent, #4a9eff);
    background: color-mix(in srgb, var(--accent, #4a9eff) 12%, transparent);
}

.ux-media-drop-zone > svg,
.ux-media-drop-zone .ux-media-drop-icon {
    width: 28px;
    height: 28px;
    stroke: var(--text-secondary, #a0aec0);
    stroke-width: 1.8;
    fill: none;
    margin-bottom: 6px;
    opacity: 0.75;
    flex-shrink: 0;
}

.ux-media-drop-label {
    font-size: 12px;
    color: var(--text-secondary, #a0aec0);
    font-weight: 600;
}

.ux-media-drop-hint {
    font-size: 11px;
    color: var(--text-secondary, #a0aec0);
    opacity: 0.65;
    margin-top: 4px;
}

.ux-media-drop-actions {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    gap: 6px;
    z-index: 2;
    pointer-events: auto;
}

.ux-media-drop-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 34px;
    padding: 8px 12px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-primary, #f0f0f5);
    background: var(--bg-card, rgba(22, 22, 34, 0.95));
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 8px;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
    box-sizing: border-box;
    transition: var(--ux-hover-rim-transition, box-shadow 0.2s ease);
}

.ux-media-drop-btn svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
    flex-shrink: 0;
}

@media (hover: hover) {
    .ux-media-drop-btn:hover:not(:disabled):not(.ux-btn-pressed):not(:active) {
        box-shadow: var(--ux-hover-rim-shadow, 0 0 0 1px rgba(255, 255, 255, 0.5));
    }
}

.ux-media-drop-btn:active,
.ux-media-drop-btn.ux-btn-pressed {
    filter: brightness(0.65);
    transform: translate(1px, 1px);
}

.ux-media-drop-file {
    display: none !important;
}

/* ============================
   FIN ZONE D'IMPORT MÉDIA
   ============================ */

/* ============================
   DIALOGUES
   ============================ */

/*
 * Animation d'ouverture / fermeture :
 * - backdrop via ::before (l'overlay reste opacity:1 pour ne pas aplatir le 3D)
 * - boite : @keyframes (plus fiables que transition + classe .visible)
 * - pivot rotateX 30deg -> 0, fade-in, leger zoom-in (inverse a la fermeture)
 */
@keyframes ux-dlg-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes ux-dlg-backdrop-out {
    from { opacity: 1; }
    to { opacity: 0; }
}
@keyframes ux-dlg-panel-in {
    0% {
        opacity: 0;
        transform: rotateX(30deg) scale(0.92);
    }
    35% {
        opacity: 1;
    }
    100% {
        opacity: 1;
        transform: rotateX(0deg) scale(1);
    }
}
@keyframes ux-dlg-panel-out {
    0% {
        opacity: 1;
        transform: rotateX(0deg) scale(1);
    }
    100% {
        opacity: 0;
        transform: rotateX(30deg) scale(0.92);
    }
}

.ux-dialog-overlay {
    position: fixed;
    inset: 0;
    /* Fond transparent : le voile est sur ::before pour garder l'overlay a opacity 1
       (sinon le navigateur aplatit le rotateX des enfants). */
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 150000;
    perspective: 1200px;
    perspective-origin: 50% 40%;
}

.ux-dialog-overlay::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    opacity: 0;
    pointer-events: none;
    z-index: 0;
}

.ux-dialog-overlay.visible::before {
    animation: ux-dlg-backdrop-in 0.32s ease forwards;
}

.ux-dialog-overlay.closing {
    pointer-events: none;
}

.ux-dialog-overlay.closing::before {
    animation: ux-dlg-backdrop-out 0.28s ease forwards;
}

.ux-dialog {
    position: absolute;
    z-index: 1;
    /* Largeur maitrisee : le dialogue s'adapte a son contenu (largeur auto)
       avec un minimum confortable et un maximum raisonnable. Les dialogues qui
       ont besoin d'etre plus larges (tableaux, listes, editeurs) doivent definir
       leur propre largeur via `dialogClass` (ex. .mon-app-dlg .ux-dialog). */
    width: fit-content;
    min-width: min(360px, calc(100vw - 32px));
    max-width: min(480px, calc(100vw - 32px));
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary, #12121a);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 16px;
    box-shadow: 0 30px 100px rgba(0, 0, 0, 0.5);
    overflow: hidden;
    opacity: 0;
    transform: rotateX(30deg) scale(0.92);
    transform-origin: center center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

/* Variante large générique (formulaires, journaux, JSON). */
.ux-dlg-wide .ux-dialog {
    width: min(640px, calc(100vw - 32px));
    min-width: min(420px, calc(100vw - 32px));
    max-width: min(640px, calc(100vw - 32px));
}

/* Variante large (ex. Radio IA : prompt de jingle long, plus confortable a lire). */
.radioia-wide-dlg .ux-dialog {
    width: min(680px, calc(100vw - 32px));
    min-width: min(560px, calc(100vw - 32px));
    max-width: min(680px, calc(100vw - 32px));
}

/* Contacts : invitation par courriel */
.contacts-invite-dlg .ux-dialog {
    width: min(960px, calc(100vw - 40px));
    min-width: min(520px, calc(100vw - 40px));
    max-width: min(960px, calc(100vw - 40px));
    max-height: min(88vh, calc(100vh - 24px));
}
.contacts-invite-dlg .ux-dialog-content {
    padding: 22px 24px 20px;
}
.contacts-invite-dlg .cinv-fields {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.contacts-invite-dlg .cinv-fields .ux-field {
    gap: 7px;
}
.contacts-invite-dlg .cinv-fields .ux-textarea-auto {
    min-height: 76px;
    line-height: 1.5;
}
.contacts-invite-dlg .cinv-message-head {
    display: flex;
    align-items: center;
    gap: 4px;
}
.contacts-invite-dlg .cinv-message-head label {
    margin: 0;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--text-secondary, #a0aec0);
}
.contacts-invite-dlg .cinv-regen.ux-btn.ux-btn-icon {
    width: 26px;
    height: 26px;
    min-height: 26px;
    padding: 0;
    border-radius: 8px;
}
.contacts-invite-dlg .cinv-regen.is-busy svg {
    animation: cinv-regen-spin 0.7s linear infinite;
}
@keyframes cinv-regen-spin {
    to { transform: rotate(360deg); }
}
.contacts-invite-dlg .cinv-history {
    margin-top: 2px;
}
.contacts-invite-dlg .cinv-history .ux-expand-inner {
    padding-left: 10px;
    padding-right: 10px;
}
.contacts-invite-dlg .cinv-history-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.contacts-invite-dlg .cinv-history-item {
    appearance: none;
    -webkit-appearance: none;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    width: 100%;
    margin: 0;
    padding: 8px 12px;
    text-align: left;
    cursor: default;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    font: inherit;
    color: var(--text-primary);
    background: var(--bg-tertiary);
    border: 1px solid var(--border-hover);
    border-radius: 10px;
}
.contacts-invite-dlg .cinv-history-item:hover {
    border-color: var(--text-muted);
}
.contacts-invite-dlg .cinv-history-item:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent);
}
.contacts-invite-dlg .cinv-history-item.is-current {
    border-color: var(--accent-purple);
    background: rgba(139, 92, 246, 0.22);
    box-shadow: inset 0 0 0 2px var(--accent-purple);
}
.contacts-invite-dlg .cinv-history-item.is-new {
    flex-direction: row;
    align-items: center;
    gap: 10px;
}
.contacts-invite-dlg .cinv-history-new-mark {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    background: var(--bg-primary);
    border: 1px solid var(--border-hover);
}
.contacts-invite-dlg .cinv-history-item.is-new.is-current .cinv-history-new-mark {
    color: #fff;
    background: var(--accent);
    border-color: var(--accent);
}
.contacts-invite-dlg .cinv-history-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.contacts-invite-dlg .cinv-history-msg {
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text-primary);
}
.contacts-invite-dlg .cinv-history-meta {
    font-size: 12px;
    line-height: 1.3;
    color: var(--text-secondary);
}
.contacts-invite-dlg.is-sent .ux-dialog-footer {
    display: none;
}
.contacts-invite-dlg .cinv-send-scene {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    min-height: 280px;
    padding: 24px 12px 8px;
    text-align: center;
}
.contacts-invite-dlg .cinv-send-mark,
.contacts-invite-dlg .cinv-send-check {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    flex-shrink: 0;
}
.contacts-invite-dlg .cinv-send-mark {
    width: 72px;
    height: 72px;
    border-radius: 20px;
    background: var(--accent);
    animation: cinv-send-fly 1.15s ease-in-out infinite;
}
.contacts-invite-dlg .cinv-send-check {
    width: 88px;
    height: 88px;
    border-radius: 50%;
    background: var(--ux-btn-default, #16a34a);
    animation: cinv-send-pop 0.38s ease-out;
}
.contacts-invite-dlg .cinv-send-mark svg,
.contacts-invite-dlg .cinv-send-check svg {
    display: block;
}
.contacts-invite-dlg .cinv-send-title {
    margin: 8px 0 0;
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
}
.contacts-invite-dlg .cinv-send-sub,
.contacts-invite-dlg .cinv-send-mail {
    margin: 0;
    font-size: 14px;
    line-height: 1.45;
    color: var(--text-secondary);
}
.contacts-invite-dlg .cinv-send-mail {
    font-weight: 600;
    color: var(--text-primary);
}
@keyframes cinv-send-fly {
    0% { transform: translateY(10px); opacity: 0.55; }
    50% { transform: translateY(-12px); opacity: 1; }
    100% { transform: translateY(10px); opacity: 0.55; }
}
@keyframes cinv-send-pop {
    0% { transform: scale(0.72); opacity: 0; }
    100% { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .contacts-invite-dlg .cinv-send-mark,
    .contacts-invite-dlg .cinv-send-check {
        animation: none;
    }
}
.contacts-invite-dlg .cinv-recipient-label {
    cursor: text;
}
.contacts-invite-dlg .cinv-recipient {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    padding: 10px 12px;
    min-height: 42px;
    background: var(--bg-input, var(--bg-hover, rgba(255, 255, 255, 0.05)));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 8px;
    color: var(--text-primary, #f0f0f5);
    font: inherit;
    font-size: 14px;
    line-height: 1.4;
    white-space: nowrap;
    overflow: hidden;
    outline: none;
    cursor: text;
}
.contacts-invite-dlg .cinv-recipient:focus {
    border-color: var(--accent, #4a9eff);
}
.contacts-invite-dlg .cinv-recipient.is-empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted, #5a5a70);
    pointer-events: none;
}
.contacts-invite-dlg .cinv-apps {
    display: flex;
    flex-direction: column;
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.contacts-invite-dlg .cinv-apps-switch {
    align-self: stretch;
    margin: 0;
    color: var(--text-primary);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
}
.contacts-invite-dlg .cinv-apps-reveal {
    max-height: 0;
    margin-top: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-height 0.46s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.34s ease, margin-top 0.46s cubic-bezier(0.22, 1, 0.36, 1);
}
.contacts-invite-dlg .cinv-apps-reveal.is-open {
    opacity: 1;
    margin-top: 14px;
}
.contacts-invite-dlg .cinv-apps-reveal.is-instant {
    transition: none;
}
.contacts-invite-dlg .cinv-apps-reveal-inner {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
}
@media (prefers-reduced-motion: reduce) {
    .contacts-invite-dlg .cinv-apps-reveal {
        transition: none;
    }
}
.contacts-invite-dlg .cinv-apps-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}
.contacts-invite-dlg .cinv-label {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--text-primary);
}
.contacts-invite-dlg .cinv-count {
    flex-shrink: 0;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 6px 10px;
    user-select: none;
}
.contacts-invite-dlg .cinv-count.is-on {
    color: #fff;
    background: var(--accent-purple);
    border-color: var(--accent-purple);
}
.contacts-invite-dlg .cinv-hint,
.contacts-invite-dlg .cinv-empty,
.contacts-invite-dlg .cinv-limit {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary);
}
.contacts-invite-dlg .cinv-limit {
    color: var(--accent-purple);
    font-weight: 600;
}
.contacts-invite-dlg .cinv-search-wrap {
    position: relative;
}
.contacts-invite-dlg .cinv-search-wrap > i {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    color: var(--text-muted);
    pointer-events: none;
}
.contacts-invite-dlg .ux-dialog-content input.cinv-search {
    padding-left: 38px;
}
.contacts-invite-dlg .cinv-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
    gap: 12px;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    box-sizing: border-box;
    width: 100%;
    min-height: 92px;
    margin: 0;
    padding: 14px 42px 14px 14px;
    border: 1px solid var(--border);
    border-radius: 16px;
    background: var(--bg-primary);
    color: var(--text-primary);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset, 0 10px 24px rgba(0, 0, 0, 0.22);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card[hidden] {
    display: none;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:hover {
    border-color: var(--text-muted);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset, 0 12px 28px rgba(0, 0, 0, 0.28);
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:focus-within {
    /* Anneau intérieur : un contour externe est rogné par overflow:hidden
       du panneau, de quelques pixels à gauche et à droite. */
    outline: none;
    box-shadow: inset 0 0 0 2px var(--accent);
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-input {
    position: fixed;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-mark {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 22px;
    height: 22px;
    border-radius: 999px;
    border: 1.5px solid var(--text-muted);
    background: var(--bg-secondary);
    color: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-mark svg {
    display: block;
    width: 14px;
    height: 14px;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-icon {
    width: 42px;
    height: 42px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-icon > svg {
    display: block;
    width: 20px;
    height: 20px;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-text {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
    flex: 1;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-title {
    display: block;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card-desc {
    display: -webkit-box;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-secondary);
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:has(input:checked) {
    border-color: var(--accent-purple);
    background: color-mix(in srgb, var(--accent-purple) 22%, var(--bg-primary));
    box-shadow: inset 0 0 0 2px var(--accent-purple);
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:has(input:checked):hover,
.contacts-invite-dlg .ux-dialog-content .cinv-card:has(input:checked):focus-within {
    border-color: var(--accent-purple);
    box-shadow: inset 0 0 0 2px var(--accent-purple);
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:has(input:checked) .cinv-card-mark {
    border-color: var(--accent-purple);
    background: var(--accent-purple);
    color: #fff;
}
.contacts-invite-dlg .ux-dialog-content .cinv-card:has(input:checked) .cinv-card-title {
    color: var(--text-primary);
}
[data-theme="light"] .contacts-invite-dlg .ux-dialog-content .cinv-card {
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.7) inset, 0 8px 18px rgba(15, 18, 28, 0.08);
}
[data-theme="light"] .contacts-invite-dlg .ux-dialog-content .cinv-card:hover {
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.8) inset, 0 10px 22px rgba(15, 18, 28, 0.12);
}
@media (max-width: 640px) {
    .contacts-invite-dlg .ux-dialog-content {
        padding: 16px;
    }
    .contacts-invite-dlg .cinv-grid {
        grid-template-columns: 1fr;
    }
}

.contacts-invite-details-dlg .ux-dialog,
.contacts-invite-apps-dlg .ux-dialog {
    width: min(520px, calc(100vw - 32px));
    min-width: min(360px, calc(100vw - 32px));
    max-width: min(520px, calc(100vw - 32px));
    max-height: min(88vh, calc(100vh - 24px));
}
.contacts-invite-details-dlg .ux-dialog-content,
.contacts-invite-apps-dlg .ux-dialog-content {
    overflow-y: auto;
}

/* Applications : partage d'une fiche par courriel */
.ux-dialog-overlay.apps-share-dlg .ux-dialog {
    width: min(960px, calc(100vw - 40px));
    min-width: min(520px, calc(100vw - 40px));
    max-width: min(960px, calc(100vw - 40px));
}
.apps-share-dlg .ashare-hint {
    margin: 4px 0 10px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary, #a0aec0);
}
.apps-share-dlg .ashare-recipients {
    width: 100%;
    box-sizing: border-box;
    min-height: 44px;
    resize: none;
}
.apps-share-dlg .ashare-groups {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 8px 0 4px;
}
.apps-share-dlg .ashare-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.apps-share-dlg .ashare-group:not(:has(.ashare-person:not([hidden]))) {
    display: none;
}
.apps-share-dlg .ashare-group-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted, #94a3b8);
    padding: 6px 2px 0;
}
.apps-share-dlg .ashare-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(234px, 1fr));
    gap: 8px;
}
.apps-share-dlg .ashare-person {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    min-height: 44px;
    margin: 0;
    padding: 10px 12px;
    text-align: left;
    font: inherit;
    border: 1px solid var(--border-hover, rgba(255, 255, 255, 0.12));
    border-radius: 12px;
    background: var(--bg-tertiary, rgba(255, 255, 255, 0.04));
    color: inherit;
    cursor: default;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    outline: none;
    transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}
.apps-share-dlg .ashare-person:hover {
    border-color: var(--text-muted, #94a3b8);
}
.apps-share-dlg .ashare-person:focus-visible {
    box-shadow: inset 0 0 0 2px var(--accent, #7c3aed);
}
.apps-share-dlg .ashare-person.is-selected {
    border-color: var(--accent-purple, #7c3aed);
    background: rgba(139, 92, 246, 0.22);
    box-shadow: inset 0 0 0 2px var(--accent-purple, #7c3aed);
}
.apps-share-dlg .ashare-person[hidden] {
    display: none;
}
.apps-share-dlg .ashare-avatar {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 600;
    color: #ffffff;
    flex-shrink: 0;
    background: var(--accent-purple, #7c3aed);
}
.apps-share-dlg .ashare-name {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.25;
    color: var(--text-primary, #f0f0f5);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.apps-share-dlg .ashare-empty {
    margin: 8px 0 0;
    font-size: 13px;
    color: var(--text-muted, #94a3b8);
}
.apps-share-dlg .ashare-app {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 14px;
    padding: 8px 0;
}
.apps-share-dlg .ashare-app-icon {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    flex-shrink: 0;
}
.apps-share-dlg .ashare-app-icon svg {
    width: 22px;
    height: 22px;
}
.apps-share-dlg .ashare-app-name {
    font-size: 15px;
    font-weight: 700;
    color: var(--text-primary, #f0f0f5);
}
.apps-share-dlg .cinv-send-mail {
    white-space: normal;
    overflow-wrap: anywhere;
}
.contacts-invite-details-dlg .cid,
.contacts-invite-apps-dlg .cid {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.contacts-invite-details-dlg .cid-hint,
.contacts-invite-apps-dlg .cid-hint {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-secondary, #a0aec0);
}
.contacts-invite-details-dlg .cid-label,
.contacts-invite-apps-dlg .cid-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-secondary, #a0aec0);
}
.contacts-invite-details-dlg .cid-search {
    width: 100%;
    padding: 8px 10px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    color: #f0f0f5;
    font-size: 13px;
    font-family: inherit;
    box-sizing: border-box;
}
.contacts-invite-details-dlg .cid-apps,
.contacts-invite-apps-dlg .cid-apps {
    margin: 0;
}
.contacts-invite-details-dlg .cid-app[hidden],
.contacts-invite-apps-dlg .cid-app[hidden] {
    display: none;
}
.contacts-invite-details-dlg .cid-empty,
.contacts-invite-apps-dlg .cid-empty {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary, #a0aec0);
    line-height: 1.45;
}
.contacts-invite-details-dlg #dlg-invite-message {
    min-height: 88px;
}

/* Avatar : édition du prompt ITV avant génération de clip */
.avatar-clip-prompt-dlg .ux-dialog {
    width: min(720px, calc(100vw - 32px));
    min-width: min(560px, calc(100vw - 32px));
    max-width: min(720px, calc(100vw - 32px));
}
.avatar-clip-prompt-dlg .ux-dialog-content {
    overflow-y: auto;
}
.avatar-clip-prompt-dlg .avatar-clip-gen-prompt {
    display: block;
    width: 100%;
    box-sizing: border-box;
    min-height: 220px;
    max-height: min(52vh, 440px);
    overflow-y: auto;
    resize: vertical;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    color: #f0f0f5;
    font-size: 13px;
    line-height: 1.5;
    font-family: inherit;
}

/* Musique : régénération de pochette (prompt long, lecture confortable) */
.musique-cover-prompt-dlg .ux-dialog {
    width: min(720px, calc(100vw - 32px));
    min-width: min(560px, calc(100vw - 32px));
    max-width: min(720px, calc(100vw - 32px));
}
.musique-cover-prompt-dlg .ux-dialog-content {
    overflow-y: auto;
}
.musique-cover-prompt-dlg .musique-cover-prompt {
    display: block;
    width: 100%;
    box-sizing: border-box;
    min-height: 260px;
    max-height: min(55vh, 480px);
    overflow-y: auto;
    resize: vertical;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    color: #f0f0f5;
    font-size: 14px;
    line-height: 1.5;
    font-family: inherit;
}
.musique-cover-prompt-dlg .musique-cover-prompt-hint {
    display: block;
    margin: 8px 0 0;
    font-size: 12px;
    color: #a0aec0;
    line-height: 1.4;
}

/* Liste apps utilisant un modele (Superadmin Fournisseurs) */
.mdl-apps-wide-dlg .ux-dialog {
    width: min(720px, calc(100vw - 32px));
    min-width: min(520px, calc(100vw - 32px));
    max-width: min(720px, calc(100vw - 32px));
    max-height: min(88vh, calc(100vh - 24px));
}
.mdl-apps-wide-dlg .ux-dialog-content {
    /* Hauteur suit le contenu ; scroll seulement si le viewport est trop petit */
    overflow-y: auto;
    max-height: none;
}

/* BD : génération d'image de référence (grille sources + prompt) */
.bd-ref-gen-dlg .ux-dialog {
    width: min(920px, calc(100vw - 32px));
    min-width: min(640px, calc(100vw - 32px));
    max-width: min(920px, calc(100vw - 32px));
    max-height: min(90vh, calc(100vh - 24px));
}
.bd-ref-gen-dlg .ux-dialog-content {
    overflow-y: auto;
}
.bd-ref-gen-dlg .bd-ref-gen-section {
    margin-bottom: 16px;
}
.bd-ref-gen-dlg .bd-ref-gen-section:last-child {
    margin-bottom: 0;
}
.bd-ref-gen-dlg .bd-ref-gen-label {
    display: block;
    font-size: 13px;
    color: #a0aec0;
    margin-bottom: 10px;
}
.bd-ref-gen-dlg .bd-ref-gen-empty {
    margin: 0;
    font-size: 13px;
    color: #a0aec0;
    line-height: 1.45;
}
.bd-ref-gen-dlg .bd-ref-gen-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 12px;
    max-height: min(48vh, 440px);
    overflow-y: auto;
    padding: 2px;
}
.bd-ref-gen-dlg .bd-ref-gen-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    cursor: pointer;
    user-select: none;
    min-width: 0;
}
.bd-ref-gen-dlg .bd-ref-gen-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.bd-ref-gen-dlg .bd-ref-gen-stage {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 1 / 1;
    min-height: 140px;
    box-sizing: border-box;
    outline: 2px solid transparent;
    outline-offset: 0;
    transition: outline-color 0.15s ease;
}
.bd-ref-gen-dlg .bd-ref-gen-card:hover .bd-ref-gen-stage {
    outline-color: rgba(255, 255, 255, 0.22);
}
.bd-ref-gen-dlg .bd-ref-gen-card:has(.bd-ref-gen-radio:checked) .bd-ref-gen-stage,
.bd-ref-gen-dlg .bd-ref-gen-card:has(.bd-ref-gen-radio:focus-visible) .bd-ref-gen-stage {
    outline-color: var(--accent, #4a9eff);
}
.bd-ref-gen-dlg .bd-ref-gen-img {
    display: block;
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
}
.bd-ref-gen-dlg .bd-ref-gen-caption {
    font-size: 12px;
    color: #f0f0f5;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: center;
}
.bd-ref-gen-dlg .bd-ref-gen-prompt {
    display: block;
    width: 100%;
    box-sizing: border-box;
    min-height: 88px;
    padding: 10px 12px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    color: #f0f0f5;
    font-size: 14px;
    line-height: 1.45;
    font-family: inherit;
    resize: vertical;
}

/* BD : import de références nommées depuis une collection */
.bd-col-refs-dlg-overlay .ux-dialog {
    width: min(860px, calc(100vw - 32px));
    min-width: min(520px, calc(100vw - 32px));
    max-width: min(860px, calc(100vw - 32px));
    max-height: min(90vh, calc(100vh - 24px));
}
.bd-col-refs-dlg-overlay .ux-dialog-content {
    overflow-y: auto;
}
.bd-col-refs-dlg-hint {
    margin: 0 0 12px;
    font-size: 13px;
    color: #a0aec0;
    line-height: 1.45;
}
.bd-col-refs-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
}
.bd-col-refs-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 8px;
    border-radius: 10px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.03);
    cursor: pointer;
    user-select: none;
}
.bd-col-refs-card.is-already {
    opacity: 0.45;
    cursor: default;
}
.bd-col-refs-check {
    position: absolute;
    top: 14px;
    left: 14px;
    z-index: 2;
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: #4a9eff;
}
.bd-col-refs-stage {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-radius: 8px;
    overflow: hidden;
    border: 2px solid transparent;
}
.bd-col-refs-card:hover:not(.is-already) .bd-col-refs-stage {
    border-color: rgba(255, 255, 255, 0.2);
}
.bd-col-refs-card:has(.bd-col-refs-check:checked) .bd-col-refs-stage {
    border-color: #4a9eff;
}
.bd-col-refs-img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    display: block;
}
.bd-col-refs-meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.bd-col-refs-name {
    font-size: 13px;
    color: #f0f0f5;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.bd-col-refs-sub {
    font-size: 11px;
    color: #a0aec0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ux-dialog-overlay.visible .ux-dialog {
    animation: ux-dlg-panel-in 0.38s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.ux-dialog-overlay.closing .ux-dialog {
    animation: ux-dlg-panel-out 0.28s cubic-bezier(0.4, 0, 1, 1) forwards;
}

@media (prefers-reduced-motion: reduce) {
    .ux-dialog-overlay.visible::before {
        animation: ux-dlg-backdrop-in 0.15s ease forwards;
    }
    .ux-dialog-overlay.closing::before {
        animation: ux-dlg-backdrop-out 0.12s ease forwards;
    }
    .ux-dialog {
        transform: none;
    }
    .ux-dialog-overlay.visible .ux-dialog {
        animation: ux-dlg-backdrop-in 0.15s ease forwards;
    }
    .ux-dialog-overlay.closing .ux-dialog {
        animation: ux-dlg-backdrop-out 0.12s ease forwards;
    }
}

.ux-dialog-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 16px;
    background: var(--bg-tertiary, #1a1a25);
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    cursor: grab;
    flex-shrink: 0;
}

.ux-dialog-header:active {
    cursor: grabbing;
}

.ux-dialog-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--ux-btn-purple);
}

.ux-dialog-close {
    /*
     * Zone sensible maximale dans la barre de titre (annule le padding header).
     * Le carre visible n'apparait qu'au survol via ::before, avec marges egales
     * haut / bas / droite (8px = ancienne marge droite effective).
     */
    position: relative;
    align-self: stretch;
    width: 52px;
    min-width: 52px;
    height: auto;
    min-height: 0;
    padding: 0;
    margin: -10px -16px -10px 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    cursor: pointer;
    box-sizing: border-box;
    transition: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    /* Neutralise liseret / presse globaux sur la grande hit-zone. */
    box-shadow: none !important;
    filter: none !important;
    transform: none !important;
}

/* Carre visible au survol uniquement (marges 8px haut / bas / droite). */
.ux-dialog-close::before {
    content: '';
    position: absolute;
    top: 8px;
    right: 8px;
    bottom: 8px;
    aspect-ratio: 1 / 1;
    width: auto;
    height: auto;
    border-radius: 8px;
    background: transparent;
    pointer-events: none;
    transition: background var(--ux-transition-fast), var(--ux-hover-rim-transition);
    z-index: 0;
}

@media (hover: hover) {
    .ux-dialog-close:hover:not(:active):not(.ux-btn-pressed)::before {
        background: rgba(239, 68, 68, 0.2);
        box-shadow: var(--ux-hover-rim-shadow);
    }
}

.ux-dialog-close:active::before,
.ux-dialog-close.ux-btn-pressed::before {
    background: rgba(239, 68, 68, 0.28);
    box-shadow: var(--ux-btn-press-shadow);
    filter: var(--ux-btn-press-filter);
}

.ux-dialog-close svg {
    position: relative;
    z-index: 1;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    display: block;
    stroke: #8888a0;
    pointer-events: none;
    transition: stroke var(--ux-transition-fast), transform var(--ux-transition-fast);
}

@media (hover: hover) {
    .ux-dialog-close:hover svg {
        stroke: var(--ux-btn-danger);
    }
}

.ux-dialog-close:active svg,
.ux-dialog-close.ux-btn-pressed svg {
    stroke: var(--ux-btn-danger);
    transform: var(--ux-btn-press-offset);
}

.ux-dialog-content {
    padding: 16px 20px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-primary, #d0d0d8);
    overflow-y: auto;
    /* Ne pas etirer le contenu : la fenetre suit le texte (pas un grand vide). */
    flex: 0 1 auto;
    min-height: 0;
    user-select: text;
    -webkit-user-select: text;
}

.ux-dialog-content p {
    margin: 0;
}

/* Largeur intelligente des dialogues : un message simple (texte seul, rendu
   dans un <p> enfant direct du contenu) se lit sur quelques lignes au lieu
   d'une seule ligne tres longue. Les dialogues riches definissent leur propre
   largeur via leur contenu (divs, champs, textarea) et ne sont pas affectes. */
.ux-dialog-content > p {
    max-width: 460px;
}

.ux-dialog-content label {
    color: var(--text-secondary, #a0aec0);
}

/* Champs de saisie dans les dialogues OS.
   Le HTML du dialogue vit dans le document OS : le CSS d'app (iframe) ne s'applique
   pas. Sans ces règles, un <input> natif reste gris et le <label> se colle à côté. */
.ux-dialog-content .ux-field,
.ux-dialog-content .field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 100%;
    margin: 0;
}
.ux-dialog-content .ux-field > label,
.ux-dialog-content .ux-field > span,
.ux-dialog-content .field > label {
    display: block;
    margin: 0;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--text-secondary, #a0aec0);
}
.ux-dialog-content .ux-field-error {
    margin: 0;
    min-height: 0;
    font-size: 12px;
    line-height: 1.4;
    color: #f87171;
}
.ux-dialog-content .ux-input,
.ux-dialog-content input[type="text"]:not(.ux-pin-input),
.ux-dialog-content input[type="email"],
.ux-dialog-content input[type="url"],
.ux-dialog-content input[type="password"],
.ux-dialog-content input[type="search"],
.ux-dialog-content input[type="tel"],
.ux-dialog-content input[type="number"],
.ux-dialog-content input[type="datetime-local"],
.ux-dialog-content textarea {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    padding: 10px 12px;
    background: var(--bg-input, var(--bg-hover, rgba(255, 255, 255, 0.05)));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 8px;
    color: var(--text-primary, #f0f0f5);
    font: inherit;
    font-size: 14px;
    outline: none;
}
.ux-dialog-content .ux-input:focus,
.ux-dialog-content input[type="text"]:not(.ux-pin-input):focus,
.ux-dialog-content input[type="email"]:focus,
.ux-dialog-content input[type="url"]:focus,
.ux-dialog-content input[type="password"]:focus,
.ux-dialog-content input[type="search"]:focus,
.ux-dialog-content input[type="tel"]:focus,
.ux-dialog-content input[type="number"]:focus,
.ux-dialog-content input[type="datetime-local"]:focus,
.ux-dialog-content textarea:focus {
    border-color: var(--accent, #4a9eff);
}
.ux-dialog-content .ux-input::placeholder,
.ux-dialog-content input[type="text"]:not(.ux-pin-input)::placeholder,
.ux-dialog-content input[type="email"]::placeholder,
.ux-dialog-content input[type="url"]::placeholder,
.ux-dialog-content input[type="password"]::placeholder,
.ux-dialog-content input[type="search"]::placeholder,
.ux-dialog-content input[type="tel"]::placeholder,
.ux-dialog-content textarea::placeholder {
    color: var(--text-muted, #5a5a70);
}

/* Neutraliser le fond blanc impose par l'autofill du navigateur (Chrome, Edge)
   sur les champs reconnus (courriel, mot de passe...). Sans cela, le champ passe
   en fond blanc des qu'une valeur connue est saisie/proposee, ce qui casse le
   theme sombre. L'astuce : un box-shadow interne opaque couvre le fond force, et
   text-fill-color garde le texte lisible. La transition tres longue empeche le
   flash blanc au focus. */
.ux-dialog-content input:-webkit-autofill,
.ux-dialog-content input:-webkit-autofill:hover,
.ux-dialog-content input:-webkit-autofill:focus,
.ux-dialog-content input:-webkit-autofill:active,
.ux-dialog-content textarea:-webkit-autofill {
    -webkit-text-fill-color: var(--text-primary, #f0f0f5);
    -webkit-box-shadow: 0 0 0 1000px var(--bg-secondary, #12121a) inset;
    box-shadow: 0 0 0 1000px var(--bg-secondary, #12121a) inset;
    caret-color: var(--text-primary, #f0f0f5);
    border-color: var(--border, rgba(255, 255, 255, 0.08));
    transition: background-color 99999s ease-in-out 0s;
}

/* ============================
   SAISIE DE CODE (PIN / OTP) — une case par chiffre (UX.attachPinInputs)
   ============================ */
.ux-pin-inputs {
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: nowrap;
}

.ux-pin-input {
    width: 44px;
    height: 52px;
    text-align: center;
    font-size: 22px;
    font-weight: 600;
    background: var(--bg-hover, rgba(255, 255, 255, 0.05));
    border: 2px solid var(--border, rgba(255, 255, 255, 0.12));
    border-radius: 10px;
    color: var(--text-primary, #f0f0f5);
    font-family: 'Courier New', monospace;
    caret-color: var(--accent, #4a9eff);
    transition: border-color var(--ux-transition-fast), background var(--ux-transition-fast);
}

.ux-pin-input:focus {
    outline: none;
    border-color: var(--accent, #4a9eff);
    background: var(--bg-active, rgba(255, 255, 255, 0.08));
}

.ux-dialog-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
    padding: 12px 20px 16px;
    flex-shrink: 0;
}

.ux-dialog-footer:empty {
    display: none;
    padding: 0;
}

/* Bouton pousse a gauche (ex: Supprimer), le reste reste a droite */
.ux-dialog-footer .ux-dialog-btn-left {
    margin-right: auto;
}

/* Bouton sur sa propre ligne pleine largeur, separe sous les autres (ex: Fermer)
   Un filet discret au-dessus marque la separation. */
.ux-dialog-footer .ux-dialog-btn-block {
    flex-basis: 100%;
    width: 100%;
    justify-content: center;
    margin-top: 6px;
    position: relative;
}

.ux-dialog-footer .ux-dialog-btn-block::before {
    content: '';
    position: absolute;
    top: -8px;
    left: 0;
    right: 0;
    height: 1px;
    background: rgba(255, 255, 255, 0.08);
}

.ux-dialog-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 9px 20px 11px;
    border-radius: 10px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    user-select: none;
    /* Survol = liseret fluo ; clic / enfoncé = ombre interne + assombrissement. */
    transition: var(--ux-hover-rim-transition);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    background: var(--bg-hover, rgba(255, 255, 255, 0.05));
    color: var(--text-primary, #f0f0f5);
}

/* Icone (SVG) prefixant le libelle d'un bouton de dialogue */
.ux-dialog-btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.ux-dialog-btn-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.ux-dialog-btn.primary {
    background: var(--ux-btn-default);
    border: none;
    color: white;
}

.ux-dialog-btn.danger {
    background: rgba(231, 76, 60, 0.2);
    border-color: rgba(231, 76, 60, 0.3);
    color: var(--ux-btn-danger);
}

/* ============================
   INFO BAR / TOAST  (UX.infoBar) — MODE FLOTTANT
   ----------------------------
   Toast flottant en OVERLAY dans un coin de la fenetre :
   - jamais full-width, jamais colle bord a bord,
   - ne POUSSE JAMAIS le contenu de l'app (aucune reservation d'espace,
     aucun padding sur <body>, aucun redimensionnement),
   - n'occupe aucune place dans le flux (position: fixed, hors flux),
   - s'empile dans le coin choisi (bottom-right par defaut).
   Le toast peut recouvrir une petite partie du contenu : chaque app
   choisit le coin (UX.infoBar.setDefaultPosition / option position) pour
   ne masquer ni commande, ni bouton, ni texte important.
   ============================ */

.ux-infobar-stack {
    position: fixed;
    z-index: 20000;
    display: flex;
    gap: 10px;
    max-width: min(420px, calc(100vw - 32px));
    pointer-events: none;
}

.ux-infobar-stack--bottom-right  { right: 20px; bottom: 20px; flex-direction: column-reverse; align-items: flex-end; }
.ux-infobar-stack--bottom-left   { left: 20px;  bottom: 20px; flex-direction: column-reverse; align-items: flex-start; }
.ux-infobar-stack--top-right     { right: 20px; top: 20px;    flex-direction: column;         align-items: flex-end; }
.ux-infobar-stack--top-left      { left: 20px;  top: 20px;    flex-direction: column;         align-items: flex-start; }
.ux-infobar-stack--bottom-center { left: 50%; transform: translateX(-50%); bottom: 20px; flex-direction: column-reverse; align-items: center; }
.ux-infobar-stack--top-center    { left: 50%; transform: translateX(-50%); top: 20px;    flex-direction: column;         align-items: center; }

.ux-infobar {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    max-width: 420px;
    padding: 12px 14px;
    background: var(--bg-secondary, #161b22);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-left: 3px solid var(--ux-info);
    border-radius: 10px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
    font-size: 14px;
    line-height: 1.4;
    color: var(--text-primary, #f0f0f5);
    pointer-events: auto;
    user-select: none;
    box-sizing: border-box;
    opacity: 0;
    transition: opacity .2s ease, transform .24s cubic-bezier(.16, 1, .3, 1);
    will-change: transform, opacity;
}

/* Sens d'entree selon le coin d'ancrage (glissement depuis le bord) */
.ux-infobar-stack--bottom-right .ux-infobar,
.ux-infobar-stack--top-right .ux-infobar    { transform: translateX(24px); }
.ux-infobar-stack--bottom-left .ux-infobar,
.ux-infobar-stack--top-left .ux-infobar     { transform: translateX(-24px); }
.ux-infobar-stack--top-center .ux-infobar   { transform: translateY(-24px); }
.ux-infobar-stack--bottom-center .ux-infobar{ transform: translateY(24px); }

.ux-infobar.ux-infobar--visible {
    opacity: 1;
    transform: translate(0, 0);
}

/* La sortie reutilise le transform de base du coin (retrait du --visible)
   et eteint l'opacite. */
.ux-infobar--leaving {
    opacity: 0;
}

.ux-infobar__icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    margin-top: 1px;
    stroke: currentColor;
}

.ux-infobar__message {
    flex: 1 1 auto;
    min-width: 0;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}

.ux-infobar__actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.ux-infobar__action {
    appearance: none;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    padding: 5px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, filter .15s ease;
}

.ux-infobar__action:hover {
    background: rgba(255, 255, 255, 0.06);
    border-color: rgba(255, 255, 255, 0.25);
}

.ux-infobar__action--primary {
    background: var(--accent, var(--ux-btn-primary));
    border-color: transparent;
    color: #fff;
}

.ux-infobar__action--primary:hover {
    filter: brightness(1.12);
    background: var(--accent, var(--ux-btn-primary));
    border-color: transparent;
}

.ux-infobar__action--danger {
    background: var(--ux-error);
    border-color: transparent;
    color: #fff;
}

.ux-infobar__action--danger:hover {
    filter: brightness(1.12);
    background: var(--ux-error);
    border-color: transparent;
}

.ux-infobar__close {
    appearance: none;
    background: transparent;
    border: none;
    color: var(--text-secondary, rgba(255,255,255,0.55));
    /* Cible tactile >= 44px (mobile). */
    width: 44px;
    height: 44px;
    margin: -10px -10px -10px 0;
    border-radius: 8px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background .15s ease, color .15s ease;
    -webkit-tap-highlight-color: transparent;
}

.ux-infobar__close svg {
    width: 14px;
    height: 14px;
}

.ux-infobar__close:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-primary, #fff);
}

.ux-infobar--success { border-left-color: var(--ux-success); }
.ux-infobar--success .ux-infobar__icon { color: var(--ux-success); }

.ux-infobar--error { border-left-color: var(--ux-error); }
.ux-infobar--error .ux-infobar__icon { color: var(--ux-error); }

.ux-infobar--info { border-left-color: var(--ux-info); }
.ux-infobar--info .ux-infobar__icon { color: var(--ux-info); }

.ux-infobar--warning { border-left-color: var(--ux-warning); }
.ux-infobar--warning .ux-infobar__icon { color: var(--ux-warning); }

/* ============================
   PANEL RESIZER (redimensionnement de panneaux)
   ============================ */

/**
 * Composant de panneau redimensionnable
 * 
 * Usage:
 *   <div class="ux-resizable-layout">
 *       <aside class="ux-panel ux-panel-left" id="left-panel">...</aside>
 *       <div class="ux-resizer ux-resizer-left" id="left-resizer"></div>
 *       <main class="ux-panel-main">...</main>
 *       <div class="ux-resizer ux-resizer-right" id="right-resizer"></div>
 *       <aside class="ux-panel ux-panel-right" id="right-panel">...</aside>
 *   </div>
 * 
 * JavaScript:
 *   const leftResizer = UX.resizer({
 *       resizerId: 'left-resizer',
 *       panelId: 'left-panel',
 *       side: 'left',
 *       minWidth: 200,
 *       maxWidth: 500,
 *       storageKey: 'myapp_left_panel',
 *       collapsible: true
 *   });
 */

/* Layout conteneur */
.ux-resizable-layout {
    display: flex;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

/* Panneaux latéraux */
.ux-panel {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg-secondary, #12121a);
    flex-shrink: 0;
    /* Pas de transition par défaut - géré par .ux-panel-animating pour collapse/expand */
}

.ux-panel-left {
    width: 280px;
    min-width: 200px;
    border-right: 1px solid var(--border, rgba(255, 255, 255, 0.08));
}

.ux-panel-right {
    width: 320px;
    min-width: 200px;
    border-left: 1px solid var(--border, rgba(255, 255, 255, 0.08));
}

/* Zone principale centrale */
.ux-panel-main {
    flex: 1;
    min-width: 200px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* Barre de redimensionnement verticale */
.ux-resizer {
    width: 6px;
    background: var(--ux-resizer-bg, rgba(255, 255, 255, 0.06));
    cursor: col-resize;
    flex-shrink: 0;
    position: relative;
    transition: background 0.2s ease;
    -webkit-user-select: none;
    user-select: none;
    z-index: 10;
    /* Tactile : le redimensionnement doit recevoir les pointermove. */
    touch-action: none;
}

.ux-resizer:hover,
.ux-resizer.ux-resizer-dragging {
    background: var(--accent, #8b5cf6);
}

/* Indicateur visuel central - barre verticale */
.ux-resizer::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 3px;
    height: 40px;
    background: var(--ux-resizer-color, var(--accent, #8b5cf6));
    opacity: 0.7;
    border-radius: 2px;
    transition: all 0.2s ease;
}

.ux-resizer:hover::after,
.ux-resizer.ux-resizer-dragging::after {
    background: rgba(255, 255, 255, 0.9);
    opacity: 1;
    height: 60px;
    box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}

/* État fermé du panneau - GAUCHE */
.ux-resizer-left.ux-resizer-collapsed {
    background: linear-gradient(90deg, var(--accent, #8b5cf6), rgba(139, 92, 246, 0.7));
    cursor: pointer;
    width: 8px;
}

.ux-resizer-left.ux-resizer-collapsed::after {
    width: 3px;
    height: 50px;
    background: rgba(255, 255, 255, 0.7);
    opacity: 1;
}

/* Chevron indiquant qu'on peut réouvrir - vers la droite */
.ux-resizer-left.ux-resizer-collapsed::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, calc(-50% - 35px));
    width: 0;
    height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-left: 6px solid rgba(255, 255, 255, 0.8);
}

/* État fermé du panneau - DROITE */
.ux-resizer-right.ux-resizer-collapsed {
    background: linear-gradient(270deg, var(--accent, #8b5cf6), rgba(139, 92, 246, 0.7));
    cursor: pointer;
    width: 8px;
}

.ux-resizer-right.ux-resizer-collapsed::after {
    width: 3px;
    height: 50px;
    background: rgba(255, 255, 255, 0.7);
    opacity: 1;
}

/* Chevron indiquant qu'on peut réouvrir - vers la gauche */
.ux-resizer-right.ux-resizer-collapsed::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, calc(-50% - 35px));
    width: 0;
    height: 0;
    border-top: 5px solid transparent;
    border-bottom: 5px solid transparent;
    border-right: 6px solid rgba(255, 255, 255, 0.8);
}

.ux-resizer.ux-resizer-collapsed:hover {
    background: var(--accent-hover, #7c3aed);
    filter: brightness(1.1);
}

/* Panneau collapsé */
.ux-panel-collapsed {
    min-width: 0 !important;
    width: 0 !important;
    overflow: hidden;
    flex: none !important;
    border: none !important;
}

.ux-panel-collapsed > * {
    opacity: 0;
    pointer-events: none;
}

/* Animation de transition */
.ux-panel-animating {
    transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1), 
                min-width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* PERFORMANCE: Désactiver les transitions pendant le drag */
.ux-panel-resizing,
.ux-panel-resizing * {
    transition: none !important;
}

/* Empêcher la sélection de texte pendant le resize */
body.ux-resizing,
body.ux-resizing * {
    user-select: none !important;
    -webkit-user-select: none !important;
    cursor: col-resize !important;
}

/* Désactiver les pointer-events sur les iframes pendant le resize */
body.ux-resizing iframe {
    pointer-events: none !important;
}

/* Mode vertical (side 'top' / 'bottom') : barre horizontale, panneau redimensionné en hauteur */
.ux-resizer-top,
.ux-resizer-bottom {
    width: auto;
    height: 6px;
    cursor: row-resize;
}
.ux-resizer-top::after,
.ux-resizer-bottom::after {
    width: 40px;
    height: 3px;
}
.ux-resizer-top:hover::after,
.ux-resizer-top.ux-resizer-dragging::after,
.ux-resizer-bottom:hover::after,
.ux-resizer-bottom.ux-resizer-dragging::after {
    width: 60px;
    height: 3px;
}
.ux-resizer-top.ux-resizer-collapsed,
.ux-resizer-bottom.ux-resizer-collapsed {
    width: auto;
    height: 8px;
    cursor: pointer;
    background: var(--accent, #8b5cf6);
}
.ux-panel-y.ux-panel-collapsed {
    width: auto !important;
    height: 0 !important;
    min-height: 0 !important;
}
.ux-panel-y.ux-panel-animating {
    transition: height 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
body.ux-resizing.ux-resizing-y,
body.ux-resizing.ux-resizing-y * {
    cursor: row-resize !important;
}

/* Tooltip au survol du resizer fermé */
.ux-resizer.ux-resizer-collapsed[data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    padding: 6px 12px;
    background: var(--bg-tertiary, #1a1a25);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.1));
    border-radius: 6px;
    font-size: 12px;
    color: var(--text-primary, #f0f0f5);
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
    z-index: 100;
    width: auto;
    height: auto;
}

.ux-resizer-left.ux-resizer-collapsed[data-tooltip]::after {
    left: calc(100% + 8px);
}

.ux-resizer-right.ux-resizer-collapsed[data-tooltip]::after {
    right: calc(100% + 8px);
}

.ux-resizer.ux-resizer-collapsed:hover[data-tooltip]::after {
    opacity: 1;
}

/* ============================
   RESPONSIVE
   ============================ */

@media (max-width: 768px) {
    .ux-dialog {
        /* Largeur au contenu (message court) ; plafond ecran. */
        width: fit-content;
        min-width: min(280px, calc(100vw - 32px));
        max-width: min(400px, calc(100vw - 32px));
    }
    
    .ux-infobar-stack {
        width: 100%;
    }
    .ux-infobar {
        font-size: 13px;
    }
    .ux-infobar--visible {
        padding: 9px 12px;
    }
}

@media (max-width: 480px) {
    .ux-dialog-footer {
        flex-direction: column;
        align-items: stretch;
    }
    
    /* Boutons empiles mais pas etires a 100 % : largeur du libelle + marge. */
    .ux-dialog-btn {
        width: auto;
        min-width: 7.5em;
        max-width: 100%;
        align-self: flex-end;
        justify-content: center;
        text-align: center;
    }

    /* Plusieurs boutons : chacun sur sa ligne, alignes a droite. */
    .ux-dialog-footer .ux-dialog-btn-left {
        align-self: flex-start;
        margin-right: 0;
    }

    /* En colonne, flex-basis se rapporte a la hauteur : neutraliser pour eviter
       que le bouton bloc ne s'etire verticalement. */
    .ux-dialog-footer .ux-dialog-btn-block {
        flex-basis: auto;
        width: 100%;
        align-self: stretch;
    }
}

/* ============================
   APP LOADER (écran de chargement global)
   ============================ */

/**
 * Loader plein écran pour les apps
 * 
 * Usage:
 *   1. Ajouter la classe "app-loading" au <body>
 *   2. Ajouter le HTML du loader (ou utiliser UX.showLoader())
 *   3. Appeler UX.appReady() quand les données sont chargées
 * 
 * Exemple HTML:
 *   <body class="app-loading">
 *       <div class="ux-app-loader">
 *           <div class="ux-app-loader-spinner"></div>
 *       </div>
 *       <!-- contenu de l'app -->
 *   </body>
 */

/* État de chargement - cache tout le contenu sauf le loader */
body.app-loading > *:not(.ux-app-loader):not(script):not(link):not(style) {
    visibility: hidden !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

body.app-loading .ux-app-loader {
    visibility: visible !important;
    opacity: 1 !important;
}

/* Transition fluide à la fin du chargement
   IMPORTANT: Exclure les éléments qui gèrent leur propre opacité (toasts, modals, overlays)
   Sinon l'animation force opacity:1 et override leur état par défaut (opacity:0).
   CRITIQUE: .ux-tooltip DOIT être exclu. L'infobulle est un enfant direct de body
   dont l'état caché EST opacity:0 ; une animation terminée avec fill-mode:forwards
   épingle opacity:1 au niveau animation de la cascade et écrase DEFINITIVEMENT la
   règle .ux-tooltip{opacity:0} -> bulle impossible à masquer (bug « le tooltip ne
   disparaît jamais » observé 3 jours en production sur 120secondes et admin/logs). */
body.app-loaded > *:not(.ux-app-loader):not(.toast-notification):not(.modal):not(.ux-infobar-stack):not(.ux-dialog-overlay):not(.auth-overlay):not(.ux-tooltip):not(.sysmenu-panel):not(.notification-panel):not(.system-panel):not(.account-panel):not(.auth-panel):not(.boreal-av-panel):not(.systasks-panel):not(#intro-overlay) {
    animation: uxAppFadeIn 0.3s ease forwards;
}

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

/* Container du loader */
.ux-app-loader {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-primary, #0a0a0f);
    z-index: 99999;
    transition: opacity 0.3s ease, visibility 0.3s ease;
}

/* Animation de disparition */
.ux-app-loader.hiding {
    opacity: 0;
    visibility: hidden;
}

/* Spinner animé — anneau aurore Boréal (mêmes teintes que .ux-boreal-play-ring)
   Zones de couleur franches + intercalaires sombres : la rotation se lit
   clairement (contrairement à un dégradé continu lisse). */
.ux-app-loader-spinner {
    --ux-loader-boreal: conic-gradient(
        from 0deg,
        #34d399 0deg 48deg,
        rgba(255, 255, 255, 0.06) 48deg 60deg,
        #22d3ee 60deg 108deg,
        rgba(255, 255, 255, 0.06) 108deg 120deg,
        #6366f1 120deg 168deg,
        rgba(255, 255, 255, 0.06) 168deg 180deg,
        #a78bfa 180deg 228deg,
        rgba(255, 255, 255, 0.06) 228deg 240deg,
        #ec4899 240deg 288deg,
        rgba(255, 255, 255, 0.06) 288deg 300deg,
        #84cc16 300deg 348deg,
        rgba(255, 255, 255, 0.06) 348deg 360deg
    );
    width: 48px;
    height: 48px;
    border-radius: 50%;
    position: relative;
    background: var(--ux-loader-boreal);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
            mask: radial-gradient(farthest-side, transparent calc(100% - 3.5px), #000 calc(100% - 3px));
    filter: saturate(1.35);
    animation: uxSpinnerRotate 1.35s linear infinite;
}

.ux-app-loader-spinner::before,
.ux-app-loader-spinner::after {
    content: none;
    display: none;
}

@keyframes uxSpinnerRotate {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .ux-app-loader-spinner {
        animation: none;
    }
}

/* Variante avec message */
.ux-app-loader-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
}

.ux-app-loader-message {
    color: var(--text-secondary, #a0aec0);
    font-size: 14px;
    font-weight: 500;
}

/* ============================
   BARRE DE PROGRESSION (UX.progressBar)

   Spectre aurore Boréal (= sync locale OS / spinner).
   Composant AUTONOME — ne pas coupler au loader plein écran.
   ============================ */
.ux-progress {
    width: 100%;
    max-width: 360px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
}

.ux-progress__track {
    height: 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(255, 255, 255, 0.12);
    overflow: hidden;
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
}

.ux-progress__bar {
    height: 100%;
    width: 0%;
    border-radius: inherit;
    background: linear-gradient(
        90deg,
        #34d399 0%,
        #22d3ee 20%,
        #6366f1 40%,
        #a78bfa 60%,
        #ec4899 80%,
        #84cc16 100%
    );
    background-size: 200% 100%;
    filter: saturate(1.35);
    box-shadow: 0 0 12px rgba(34, 211, 238, 0.35);
    transition: width 0.35s ease-out;
    will-change: width;
}

.ux-progress.is-looping .ux-progress__bar {
    transition: none;
    animation: uxProgressAuroraShimmer 1.6s linear infinite;
}

.ux-progress__meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    min-height: 1.2em;
}

.ux-progress__label {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary, #a0aec0);
    line-height: 1.35;
    min-width: 0;
}

.ux-progress__pct {
    flex-shrink: 0;
    min-width: 3.5em;
    text-align: right;
    font-size: 13px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary, #a0aec0);
    line-height: 1.2;
}

.ux-progress.is-pct-hidden .ux-progress__pct {
    display: none;
}

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

@media (prefers-reduced-motion: reduce) {
    .ux-progress.is-looping .ux-progress__bar {
        animation: none;
    }
    .ux-progress__bar {
        transition: none;
    }
}

/* ============================
   CONTOUR DE PROGRESSION (UX.borderProgress)

   Suit le périmètre d’une zone rectangulaire à coins arrondis
   (même spectre aurore que le spinner / la barre).
   ============================ */
.ux-border-progress {
    position: absolute;
    pointer-events: none;
    z-index: 2;
    overflow: hidden;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.ux-border-progress.is-visible {
    opacity: 1;
}
.ux-border-progress__svg {
    display: block;
    /* Largeur/hauteur posées en px par le JS.
       max-* : certains thèmes forcent une taille sur `.app-icon-image svg`
       (corrigé aussi via sélecteur `>` enfant direct du glyphe). */
    max-width: none !important;
    max-height: none !important;
    overflow: hidden;
    filter: saturate(1.35);
}
.ux-border-progress__track {
    stroke: rgba(255, 255, 255, 0.08);
}
.ux-border-progress.is-looping .ux-border-progress__bar {
    opacity: 0;
}
.ux-border-progress.is-determinate .ux-border-progress__bar {
    opacity: 0;
}
.ux-border-progress.is-determinate .ux-border-progress__segs {
    opacity: 1;
}
.ux-border-progress:not(.is-looping):not(.is-determinate) .ux-border-progress__segs,
.ux-border-progress:not(.is-looping):not(.is-determinate) .ux-border-progress__bar {
    opacity: 0;
}

/* Cible qui porte le contour (icône, bouton Synchroniser, etc.) */
.ux-icon-border-progress {
    position: relative;
}

/* Bouton d’action occupé : chrome sombre, texte blanc.
   L’animation vit uniquement sur le périmètre (UX.borderProgress).
   Pas de fond accent/bleu, pas d’anneau dans le bouton.
   Opt-in auto via busyChrome (token de classe ux-btn / srv-btn / btn). */
button.ux-busy,
.ux-btn.ux-busy,
.btn.ux-busy,
.srv-btn.ux-busy,
.ux-btn-primary.ux-busy,
.srv-btn-primary.ux-busy,
.ux-btn:disabled.ux-busy,
.srv-btn:disabled.ux-busy,
.ux-btn-primary:disabled.ux-busy,
.srv-btn-primary:disabled.ux-busy,
.ux-btn.ux-busy:hover,
.srv-btn.ux-busy:hover,
.ux-btn-primary.ux-busy:hover,
.srv-btn-primary.ux-busy:hover,
.ux-btn:disabled.ux-busy:hover,
.srv-btn:disabled.ux-busy:hover,
.ux-btn-primary:disabled.ux-busy:hover,
.srv-btn-primary:disabled.ux-busy:hover {
    background: #0D0D0D !important;
    color: #fff !important;
    border-color: transparent !important;
    opacity: 1 !important;
    box-shadow: none !important;
    filter: none !important;
}
.ux-busy > .ux-app-loader-spinner,
.ux-busy > .srv-ux-spin,
button.ux-busy .ux-app-loader-spinner,
.ux-btn.ux-busy .ux-app-loader-spinner,
.srv-btn.ux-busy .ux-app-loader-spinner,
.btn.ux-busy .ux-app-loader-spinner,
button.ux-busy .srv-ux-spin,
.ux-btn.ux-busy .srv-ux-spin,
.srv-btn.ux-busy .srv-ux-spin,
.btn.ux-busy .srv-ux-spin {
    display: none !important;
}

/* ============================
   TEXTAREA AUTO-RESIZE
   
   Règle OBLIGATOIRE : tout champ multiligne de contenu
   utilise `.ux-textarea-auto` pour s'adapter en hauteur
   selon son contenu, sans scroll interne tant que
   maxHeight n'est pas atteint (ou jamais avec `-fit`).
   
   Usage:
     <textarea class="ux-textarea-auto" rows="1"></textarea>
     <textarea class="ux-textarea-auto ux-textarea-auto-fit"></textarea>
   
   JavaScript (auto-init au chargement pour `.ux-textarea-auto`) :
     UX.autoResize(el);                      // élément dynamique
     UX.autoResizeAll('.ux-textarea-auto');
     UX.autoResize(el, { maxHeight: null }); // sans plafond
   
   Options par défaut:
     - minHeight: hauteur initiale (ou 60px)
     - maxHeight: 400px (null = illimité, pas de scroll)
     - resetOnEmpty: true (revient à minHeight si vide)
   ============================ */

.ux-textarea-auto {
    width: 100%;
    min-height: 60px;
    max-height: 400px;
    padding: 12px 16px;
    background: var(--bg-hover, rgba(255, 255, 255, 0.05));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    color: var(--text-primary, #f0f0f5);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.5;
    resize: none;
    overflow: hidden;
    box-sizing: border-box;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.ux-textarea-auto:focus {
    outline: none;
    border-color: var(--accent, #4a9eff);
    box-shadow: 0 0 0 3px rgba(74, 158, 255, 0.15);
}

.ux-textarea-auto::placeholder {
    color: var(--text-secondary, #a0aec0);
    opacity: 0.7;
}

/* Variante compacte - pour les commentaires */
.ux-textarea-auto-sm {
    min-height: 44px;
    padding: 10px 14px;
    font-size: 13px;
    border-radius: 8px;
}

/* Variante grande - pour les descriptions longues (plafond 600px) */
.ux-textarea-auto-lg {
    min-height: 100px;
    max-height: 600px;
    padding: 16px 20px;
    font-size: 15px;
}

/* Variante contenu long (prompts, gouvernance, system prompts…) :
   hauteur illimitée, AUCUN scroll interne — la page scrolle. */
.ux-textarea-auto-fit {
    min-height: 80px;
    max-height: none;
}

/* ============================
   MOBILE NAV (navigation panneau mobile)
   ============================ */

/**
 * Transition mobile : le panneau principal se superpose au menu
 * (glisse depuis la droite et le couvre). Pas de layout 200vw.
 *
 * Structure HTML attendue :
 *   <div class="app-container ux-mobile-nav" id="app-container">
 *     <aside class="sidebar ux-panel" id="sidebar">...</aside>
 *     <div class="ux-resizer" id="sidebar-resizer"></div>
 *     <main class="main-content ux-panel-main">...</main>
 *   </div>
 *
 * Activation : UX.mobileNav({ containerId, breakpoint })
 * Classe d'état : .ux-mobile-show-main sur le container
 */

/* ------------------------------------------------------------------
   Barre de titre d'app unifiee (.ux-app-titlebar) — UX.appTitlebar
   Liste (nom + chrome) et section (retour + titre) partagent
   hauteur, typo et taille de boutons.

   Modes (classes posees par UX.appTitlebar) :
   - .ux-app-titlebar-in-os          : app dans l'iframe OS
   - .ux-app-titlebar-is-mobile      : mode mobile (OS ou viewport)
   - .ux-app-titlebar-exclusive      : URL directe (pas de chrome)
   OS + desktop : barre masquee (titre/boutons = mobile only).
   ------------------------------------------------------------------ */
/* Transparent par defaut (se fond dans un panneau parent sombre).
   Sous-fenetres OS (lecteur Courriel, etc.) : fond opaque via
   [data-ux-subwindow-chrome] — sinon le CSS d'un document embarque
   (ex. body blanc d'un courriel HTML) transparait derriere le titre. */
.ux-app-titlebar {
    display: flex;
    align-items: center;
    gap: 10px;
    height: 52px;
    min-height: 52px;
    padding: 0 12px;
    margin: 0;
    background: transparent;
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.06));
    flex-shrink: 0;
    box-sizing: border-box;
}

.ux-app-titlebar[data-ux-subwindow-chrome] {
    background: var(--bg-secondary, #161b22);
}

.ux-app-titlebar-title {
    flex: 1;
    min-width: 0;
    font-size: 17px;
    font-weight: 600;
    color: var(--text-primary, #f0f0f5);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
}

.ux-app-titlebar-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    margin-left: auto;
}

.ux-app-titlebar-btn {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    background: var(--bg-tertiary, rgba(30, 30, 45, 0.8));
    color: var(--text-primary, #f0f0f5);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: var(--ux-hover-rim-transition, box-shadow 0.2s ease);
    flex-shrink: 0;
    user-select: none;
    padding: 0;
    -webkit-tap-highlight-color: transparent;
}

.ux-app-titlebar-btn svg {
    width: 18px;
    height: 18px;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
}

.ux-app-titlebar-btn.ux-btn-pressed,
.ux-app-titlebar-btn:active {
    box-shadow: var(--ux-btn-press-shadow);
    filter: var(--ux-btn-press-filter);
    transform: var(--ux-btn-press-offset);
}

.ux-app-titlebar-btn-close:hover {
    background: #ef4444;
    border-color: #ef4444;
    color: #fff;
}

/* Retour liste mobile : flèche bas (réduire l'app). Sous-fenêtre
   (`data-ux-subwindow-chrome`) : même bouton, icône flèche gauche (Retour). */
.ux-app-titlebar-back {
    display: none;
}

/* URL directe / app exclusive : aucun chrome (ni Retour, ni min/fermer) */
.ux-app-titlebar:not(.ux-app-titlebar-in-os) .ux-app-titlebar-actions,
.ux-app-titlebar.ux-app-titlebar-exclusive .ux-app-titlebar-actions,
.ux-app-titlebar:not(.ux-app-titlebar-in-os) .ux-app-titlebar-back,
.ux-app-titlebar.ux-app-titlebar-exclusive .ux-app-titlebar-back {
    display: none !important;
}

/* OS + desktop : barre masquee (chrome fenetre OS suffit ; titre/boutons = mobile only) */
.ux-app-titlebar.ux-app-titlebar-in-os:not(.ux-app-titlebar-is-mobile) {
    display: none !important;
}

/* OS + mobile : Retour a gauche, pas de Minimiser (Fermer reste) */
.ux-app-titlebar.ux-app-titlebar-in-os.ux-app-titlebar-is-mobile .ux-app-titlebar-back {
    display: flex !important;
}

.ux-app-titlebar.ux-app-titlebar-in-os.ux-app-titlebar-is-mobile .ux-app-titlebar-minimize {
    display: none !important;
}

/* Alias mobile : meme barre, affichee seulement en mobile via media query */
.ux-mobile-main-bar {
    display: none;
    position: sticky;
    top: 0;
    z-index: 30;
}

.ux-mobile-main-title {
    /* herite de .ux-app-titlebar-title */
}

.ux-mobile-back {
    /* herite de .ux-app-titlebar-btn ; display gere en media query */
    display: none;
}

@media (hover: hover) {
    .ux-app-titlebar-btn:hover:not(:active):not(.ux-btn-pressed):not(.ux-btn-pressing):not(.ux-app-titlebar-btn-close) {
        box-shadow: var(--ux-hover-rim-shadow);
    }
}

/* Activation par mode OS global (html.os-mode-mobile) — source de vérité
   quand l'app tourne dans le shell. Fallback @media pour pages sans data-os-mode. */
/* Chaîne de hauteur : l'app doit remplir l'iframe (pas un 100vh parent
   gonflé). Pas de !important ici — theme-listener verrouille en px sous
   zoom Android. */
html.os-mode-mobile,
html.os-mode-mobile body {
    height: 100%;
    max-height: 100%;
    overflow: hidden;
}

html.os-mode-mobile .ux-mobile-nav {
        position: relative !important;
        width: 100% !important;
        max-width: 100% !important;
        height: 100%;
        max-height: 100%;
        min-height: 0;
        overflow: hidden !important;
        transform: none !important;
    }

html.os-mode-mobile .ux-mobile-nav > .ux-resizer {
        display: none !important;
    }

    /* Menu : pleine surface, reste visible sous le contenu */
html.os-mode-mobile .ux-mobile-nav > .ux-panel,
html.os-mode-mobile .ux-mobile-nav > .sidebar,
html.os-mode-mobile .ux-mobile-nav > .ux-panel-left {
        width: 100% !important;
        min-width: 0 !important;
        max-width: none !important;
        flex: 1 1 auto !important;
        height: 100% !important;
        max-height: 100% !important;
        border-right: none !important;
        position: relative !important;
        left: auto !important;
        transform: none !important;
        /* Sous le panneau contenu (les apps mettent souvent z-index:200 sur .sidebar) */
        z-index: 1 !important;
    }

    /* Contenu : hors écran à droite, puis couvre le menu */
html.os-mode-mobile .ux-mobile-nav > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav > .main-content,
html.os-mode-mobile .ux-mobile-nav > .main-area {
        position: absolute !important;
        top: 0 !important;
        left: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        width: 100% !important;
        min-width: 0 !important;
        max-width: none !important;
        height: auto !important;
        max-height: none !important;
        flex: none !important;
        z-index: 300 !important;
        overflow-x: hidden !important;
        overflow-y: auto !important;
        -webkit-overflow-scrolling: touch;
        background: var(--bg-primary, #0a0a0f) !important;
        transform: translate3d(100%, 0, 0) !important;
        /* Pas de transition tant que .ux-mobile-nav-ready n'est pas pose
           (evite l'animation « panneau qui se ferme » a l'ouverture). */
        transition: none !important;
        box-shadow: none !important;
        pointer-events: none !important;
        visibility: visible !important;
        opacity: 1 !important;
        padding: 0 !important;
    }

html.os-mode-mobile .ux-mobile-nav.ux-mobile-nav-ready > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-nav-ready > .main-content,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-nav-ready > .main-area {
        transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important;
    }

html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main > .main-content,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main > .main-area {
        transform: translate3d(0, 0, 0) !important;
        box-shadow: -12px 0 32px rgba(0, 0, 0, 0.45) !important;
        pointer-events: auto !important;
    }

html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .main-content,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .main-area {
        transform: none !important;
    }

/* ------------------------------------------------------------------
 * Layouts adaptatifs (UX.mobileNav adaptiveLayouts)
 * - slide  : téléphone — contenu couvre 100 % (défaut), transition slide
 * - split  : tablette / fold — peek avec libellés (--ux-mobile-peek ≈ 260px),
 *            pas de transition (les deux panneaux coexistent)
 * ------------------------------------------------------------------ */
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .sidebar,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-left,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel,
html.os-mode-mobile #app-container.ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .sidebar,
html.os-mode-mobile #app-container.ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-left {
        width: var(--ux-mobile-peek, 260px) !important;
        min-width: var(--ux-mobile-peek, 260px) !important;
        max-width: var(--ux-mobile-peek, 260px) !important;
        flex: 0 0 var(--ux-mobile-peek, 260px) !important;
        border-right: 1px solid var(--border, rgba(255, 255, 255, 0.08)) !important;
        z-index: 2 !important;
        /* Pas d'anim de largeur : split = coexistence immédiate des 2 panneaux */
        transition: none !important;
}

html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .main-content,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .main-area,
html.os-mode-mobile #app-container.ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .main-content,
html.os-mode-mobile #app-container.ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-main {
        left: var(--ux-mobile-peek, 260px) !important;
        width: calc(100% - var(--ux-mobile-peek, 260px)) !important;
        right: auto !important;
        transition: none !important;
}

/* Split + ready : neutreiser la transition transform héritée du mode slide */
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-nav-ready > .ux-panel-main,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-nav-ready > .main-content,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-nav-ready > .main-area {
        transition: none !important;
}

/* Split ouvert : chrome — X à droite, pas de ← ; titre liste opaque
   pour masquer la scrollbar qui passe sous la barre (pas de flou). */
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open > .sidebar > .ux-app-titlebar .ux-app-titlebar-close,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open > .ux-panel-left > .ux-app-titlebar .ux-app-titlebar-close {
        display: none !important;
}
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open .ux-mobile-back {
        display: none !important;
}
html.os-mode-mobile .ux-mobile-nav .ux-mobile-split-close {
        display: none !important;
}
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open .ux-mobile-split-close {
        display: flex !important;
        margin-left: auto !important;
        flex-shrink: 0 !important;
}
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open .ux-mobile-main-bar {
        display: flex !important;
        align-items: center !important;
        gap: 10px !important;
}
html.os-mode-mobile .ux-mobile-nav.ux-mobile-split-open .ux-mobile-main-title {
        flex: 1 1 auto !important;
        min-width: 0 !important;
}
/* Titre « Paramètres » : fond opaque, pas de backdrop-filter — la
   scrollbar du panneau gauche peut passer dessous sans apparaître en flou. */
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split > .sidebar > .ux-app-titlebar.ux-frost-bar,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split > .ux-panel-left > .ux-app-titlebar.ux-frost-bar {
        position: sticky !important;
        overflow: visible !important;
        background: var(--bg-primary, #0a0a0f) !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        /* Couvre aussi la gouttière scrollbar (overlay) sous la barre */
        z-index: 30 !important;
}
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split > .sidebar > .ux-app-titlebar.ux-frost-bar::after,
html.os-mode-mobile .ux-mobile-nav.ux-mobile-layout-split > .ux-panel-left > .ux-app-titlebar.ux-frost-bar::after {
        content: '';
        position: absolute;
        top: 0;
        right: -12px;
        width: 14px;
        height: 100%;
        background: var(--bg-primary, #0a0a0f);
        pointer-events: none;
        z-index: 1;
}

/* Fallback hors shell OS (pages directes) */
@media (max-width: 760px) {
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .sidebar,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-left {
        width: var(--ux-mobile-peek, 260px) !important;
        min-width: var(--ux-mobile-peek, 260px) !important;
        max-width: var(--ux-mobile-peek, 260px) !important;
        flex: 0 0 var(--ux-mobile-peek, 260px) !important;
        border-right: 1px solid var(--border, rgba(255, 255, 255, 0.08)) !important;
        z-index: 2 !important;
        transition: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-show-main > .ux-panel-main {
        left: var(--ux-mobile-peek, 260px) !important;
        width: calc(100% - var(--ux-mobile-peek, 260px)) !important;
        right: auto !important;
        transition: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-nav-ready > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split.ux-mobile-nav-ready > .ux-panel-main {
        transition: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-split-open > .sidebar > .ux-app-titlebar .ux-app-titlebar-close {
        display: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-split-open .ux-mobile-back {
        display: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav .ux-mobile-split-close {
        display: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-split-open .ux-mobile-split-close {
        display: flex !important;
        margin-left: auto !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split > .sidebar > .ux-app-titlebar.ux-frost-bar {
        position: sticky !important;
        overflow: visible !important;
        background: var(--bg-primary, #0a0a0f) !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        z-index: 30 !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-layout-split > .sidebar > .ux-app-titlebar.ux-frost-bar::after {
        content: '';
        position: absolute;
        top: 0;
        right: -12px;
        width: 14px;
        height: 100%;
        background: var(--bg-primary, #0a0a0f);
        pointer-events: none;
    }
}

html.os-mode-mobile .ux-mobile-nav .ux-mobile-main-bar {
        display: flex !important;
        align-items: center !important;
        height: 52px !important;
        min-height: 52px !important;
        margin: 0 !important;
        padding: 0 12px !important;
        /* Verre fumé (même tokens que .ux-frost-bar) — contenu scrollable sous la barre */
        background: var(--ux-frost-bg, rgba(10, 10, 15, 0.55)) !important;
        -webkit-backdrop-filter: var(--ux-frost-blur, blur(8px));
        backdrop-filter: var(--ux-frost-blur, blur(8px));
        border-bottom: 1px solid var(--ux-frost-border, rgba(255, 255, 255, 0.1)) !important;
        box-sizing: border-box !important;
        position: sticky !important;
        top: 0 !important;
        z-index: 50 !important;
        width: 100% !important;
        max-width: none !important;
    }

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    html.os-mode-mobile .ux-mobile-nav .ux-mobile-main-bar {
        background: var(--ux-frost-bg-fallback, rgba(10, 10, 15, 0.96)) !important;
    }
}

html.os-mode-mobile .ux-mobile-nav .ux-mobile-back,
html.os-mode-mobile .ux-mobile-nav .ux-app-titlebar-btn {
        display: flex !important;
        width: 36px !important;
        height: 36px !important;
    }

    /* Ne pas forcer l'affichage du bouton Minimiser en mobile */
html.os-mode-mobile .ux-mobile-nav .ux-app-titlebar-minimize {
        display: none !important;
    }

html.os-mode-mobile .ux-mobile-nav.ux-mobile-show-main .content-section.active > .section-title {
        display: none;
    }

html[data-os-mode]:not(.os-mode-mobile) .ux-mobile-nav {
        width: auto !important;
        transform: none !important;
    }

html[data-os-mode]:not(.os-mode-mobile) .ux-mobile-nav > .ux-panel-main,
html[data-os-mode]:not(.os-mode-mobile) .ux-mobile-nav > .main-content,
html[data-os-mode]:not(.os-mode-mobile) .ux-mobile-nav > .main-area {
        position: relative !important;
        transform: none !important;
        box-shadow: none !important;
        pointer-events: auto !important;
        inset: auto !important;
    }

/* Fallback hors shell (pas de data-os-mode) — seuil 760 */
@media (max-width: 760px) {
    html:not([data-os-mode]) .ux-mobile-nav {
        position: relative !important;
        width: 100% !important;
        max-width: 100% !important;
        height: 100% !important;
        max-height: 100% !important;
        min-height: 0 !important;
        overflow: hidden !important;
        transform: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav > .ux-resizer { display: none !important; }
    html:not([data-os-mode]) .ux-mobile-nav > .ux-panel,
    html:not([data-os-mode]) .ux-mobile-nav > .sidebar,
    html:not([data-os-mode]) .ux-mobile-nav > .ux-panel-left {
        width: 100% !important;
        min-width: 0 !important;
        max-width: none !important;
        flex: 1 1 auto !important;
        height: 100% !important;
        max-height: 100% !important;
        border-right: none !important;
        position: relative !important;
        left: auto !important;
        transform: none !important;
        z-index: 1 !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav > .ux-panel-main,
    html:not([data-os-mode]) .ux-mobile-nav > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav > .main-area {
        position: absolute !important;
        top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important;
        width: 100% !important; min-width: 0 !important; max-width: none !important;
        height: auto !important; max-height: none !important; flex: none !important;
        z-index: 300 !important;
        overflow-x: hidden !important; overflow-y: auto !important;
        -webkit-overflow-scrolling: touch;
        background: var(--bg-primary, #0a0a0f) !important;
        transform: translate3d(100%, 0, 0) !important;
        transition: none !important;
        box-shadow: none !important;
        pointer-events: none !important;
        visibility: visible !important; opacity: 1 !important; padding: 0 !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-nav-ready > .ux-panel-main,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-nav-ready > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-nav-ready > .main-area {
        transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main > .ux-panel-main,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main > .main-area {
        transform: translate3d(0, 0, 0) !important;
        box-shadow: -12px 0 32px rgba(0, 0, 0, 0.45) !important;
        pointer-events: auto !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .ux-panel-main,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav.ux-mobile-show-main.ux-mobile-ime-ok > .main-area {
        transform: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav .ux-mobile-main-bar {
        display: flex !important; align-items: center !important;
        height: 52px !important; min-height: 52px !important;
        margin: 0 !important; padding: 0 12px !important;
        background: var(--ux-frost-bg, rgba(10, 10, 15, 0.55)) !important;
        -webkit-backdrop-filter: var(--ux-frost-blur, blur(8px));
        backdrop-filter: var(--ux-frost-blur, blur(8px));
        border-bottom: 1px solid var(--ux-frost-border, rgba(255, 255, 255, 0.1)) !important;
        box-sizing: border-box !important;
        position: sticky !important; top: 0 !important; z-index: 50 !important;
        width: 100% !important; max-width: none !important;
    }
    @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
        html:not([data-os-mode]) .ux-mobile-nav .ux-mobile-main-bar {
            background: var(--ux-frost-bg-fallback, rgba(10, 10, 15, 0.96)) !important;
        }
    }
    html:not([data-os-mode]) .ux-mobile-nav .ux-mobile-back,
    html:not([data-os-mode]) .ux-mobile-nav .ux-app-titlebar-btn {
        display: flex !important; width: 36px !important; height: 36px !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav .ux-app-titlebar-minimize { display: none !important; }
}

/* Chrome mobile : Retour et Fermer = glyphe seul.
   Au clic, disque plein en vidéo inverse (fond = texte, glyphe = fond).
   Spécificité au moins égale aux règles 36px de .ux-mobile-nav. */
html.os-mode-mobile .ux-mobile-back,
html.os-mode-mobile .ux-mobile-nav .ux-mobile-back,
html.os-mode-mobile .ux-app-titlebar-back,
html.os-mode-mobile .ux-mobile-nav .ux-app-titlebar-back,
html.os-mode-mobile .ux-app-titlebar-close,
html.os-mode-mobile .ux-mobile-nav .ux-app-titlebar-close,
html.os-mode-mobile .ux-mobile-split-close,
html.os-mode-mobile .ux-app-titlebar-is-mobile .ux-app-titlebar-back,
html.os-mode-mobile .ux-app-titlebar-is-mobile .ux-app-titlebar-close {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    filter: none !important;
    transform: none !important;
    border-radius: 50% !important;
    color: var(--text-primary) !important;
    width: 44px !important;
    height: 44px !important;
    min-width: 44px !important;
    min-height: 44px !important;
    padding: 0 !important;
    -webkit-tap-highlight-color: transparent;
}

html.os-mode-mobile .ux-mobile-back svg,
html.os-mode-mobile .ux-mobile-nav .ux-mobile-back svg,
html.os-mode-mobile .ux-app-titlebar-back svg,
html.os-mode-mobile .ux-app-titlebar-close svg,
html.os-mode-mobile .ux-mobile-split-close svg {
    width: 22px !important;
    height: 22px !important;
    stroke: currentColor !important;
    stroke-width: 2.25 !important;
    fill: none !important;
}

html.os-mode-mobile .ux-mobile-back:active,
html.os-mode-mobile .ux-mobile-back.ux-btn-pressed,
html.os-mode-mobile .ux-mobile-nav .ux-mobile-back:active,
html.os-mode-mobile .ux-mobile-nav .ux-mobile-back.ux-btn-pressed,
html.os-mode-mobile .ux-app-titlebar-back:active,
html.os-mode-mobile .ux-app-titlebar-back.ux-btn-pressed,
html.os-mode-mobile .ux-app-titlebar-close:active,
html.os-mode-mobile .ux-app-titlebar-close.ux-btn-pressed,
html.os-mode-mobile .ux-mobile-split-close:active,
html.os-mode-mobile .ux-mobile-split-close.ux-btn-pressed,
html.os-mode-mobile .ux-app-titlebar-btn-close:active,
html.os-mode-mobile .ux-app-titlebar-btn-close.ux-btn-pressed {
    background: var(--text-primary) !important;
    color: var(--bg-primary) !important;
    border-color: transparent !important;
    box-shadow: none !important;
    filter: none !important;
    transform: none !important;
}

@media (hover: hover) {
    html.os-mode-mobile .ux-mobile-back:hover:not(:active):not(.ux-btn-pressed),
    html.os-mode-mobile .ux-app-titlebar-back:hover:not(:active):not(.ux-btn-pressed),
    html.os-mode-mobile .ux-app-titlebar-close:hover:not(:active):not(.ux-btn-pressed),
    html.os-mode-mobile .ux-app-titlebar-btn-close:hover:not(:active):not(.ux-btn-pressed),
    html.os-mode-mobile .ux-mobile-split-close:hover:not(:active):not(.ux-btn-pressed) {
        background: transparent !important;
        border-color: transparent !important;
        color: var(--text-primary) !important;
        box-shadow: none !important;
        filter: none !important;
    }
}

@media (max-width: 760px) {
    html:not([data-os-mode]) .ux-mobile-back,
    html:not([data-os-mode]) .ux-mobile-nav .ux-mobile-back,
    html:not([data-os-mode]) .ux-app-titlebar-back,
    html:not([data-os-mode]) .ux-app-titlebar-close,
    html:not([data-os-mode]) .ux-mobile-split-close {
        background: transparent !important;
        border: none !important;
        box-shadow: none !important;
        filter: none !important;
        transform: none !important;
        border-radius: 50% !important;
        color: var(--text-primary) !important;
        width: 44px !important;
        height: 44px !important;
        min-width: 44px !important;
        min-height: 44px !important;
        padding: 0 !important;
    }
    html:not([data-os-mode]) .ux-mobile-back svg,
    html:not([data-os-mode]) .ux-app-titlebar-back svg,
    html:not([data-os-mode]) .ux-app-titlebar-close svg,
    html:not([data-os-mode]) .ux-mobile-split-close svg {
        width: 22px !important;
        height: 22px !important;
        stroke: currentColor !important;
        stroke-width: 2.25 !important;
        fill: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-back:active,
    html:not([data-os-mode]) .ux-mobile-back.ux-btn-pressed,
    html:not([data-os-mode]) .ux-app-titlebar-back:active,
    html:not([data-os-mode]) .ux-app-titlebar-back.ux-btn-pressed,
    html:not([data-os-mode]) .ux-app-titlebar-close:active,
    html:not([data-os-mode]) .ux-app-titlebar-close.ux-btn-pressed,
    html:not([data-os-mode]) .ux-mobile-split-close:active,
    html:not([data-os-mode]) .ux-mobile-split-close.ux-btn-pressed {
        background: var(--text-primary) !important;
        color: var(--bg-primary) !important;
        border-color: transparent !important;
        box-shadow: none !important;
        filter: none !important;
        transform: none !important;
    }
}

@media (min-width: 761px) {
    html:not([data-os-mode]) .ux-mobile-nav {
        width: auto !important;
        transform: none !important;
    }
    html:not([data-os-mode]) .ux-mobile-nav > .ux-panel-main,
    html:not([data-os-mode]) .ux-mobile-nav > .main-content,
    html:not([data-os-mode]) .ux-mobile-nav > .main-area {
        position: relative !important;
        transform: none !important;
        box-shadow: none !important;
        pointer-events: auto !important;
        inset: auto !important;
    }
}

/* ============================
   MOBILE DRAWER (hamburger)
   UX.mobileDrawer — tiroir sidebar + overlay
   Ne pas confondre avec UX.mobileNav (slide 200vw).
   ============================ */

.ux-mobile-drawer-toggle {
    display: none;
    position: fixed;
    top: 10px;
    left: 10px;
    z-index: 160;
    width: 40px;
    height: 40px;
    padding: 0;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    background: var(--bg-secondary, rgba(18, 18, 26, 0.95));
    color: var(--text-primary, #f0f0f5);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
}

.ux-mobile-drawer-toggle svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
}

.ux-mobile-drawer-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 150;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}

/* Critique : jamais display:block sans .visible — sinon l'overlay
   transparent bloque tous les clics dans l'app (bug UX 2026-07). */
.ux-mobile-drawer-overlay.visible {
    display: block;
    opacity: 1;
    pointer-events: auto;
}

@media (max-width: 768px) {
    .ux-mobile-drawer-toggle {
        display: flex;
    }

    html.ux-drawer-is-open .ux-mobile-drawer-toggle {
        opacity: 0;
        pointer-events: none;
    }

    .ux-mobile-drawer-host > .ux-resizer {
        display: none !important;
    }

    .ux-mobile-drawer-host > .ux-mobile-drawer-target,
    .ux-mobile-drawer-host > .sidebar.ux-mobile-drawer-target,
    .ux-mobile-drawer-host > .ux-panel-left.ux-mobile-drawer-target {
        position: fixed !important;
        top: 0 !important;
        left: 0 !important;
        bottom: 0 !important;
        height: 100% !important;
        max-height: 100% !important;
        width: min(320px, 85vw) !important;
        max-width: 85vw !important;
        min-width: 0 !important;
        z-index: 200 !important;
        transform: translateX(-105%);
        transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        box-shadow: none;
        border-right: 1px solid var(--border, rgba(255, 255, 255, 0.08)) !important;
    }

    .ux-mobile-drawer-host > .ux-mobile-drawer-target.ux-drawer-open,
    .ux-mobile-drawer-host > .ux-mobile-drawer-target.open {
        transform: translateX(0);
        box-shadow: 4px 0 24px rgba(0, 0, 0, 0.45);
    }

    /* Marge pour que le hamburger ne recouvre pas le contenu principal */
    .ux-mobile-drawer-host > .ux-panel-main,
    .ux-mobile-drawer-host > .main-content,
    .ux-mobile-drawer-host > .main-area {
        padding-top: 0;
    }
}

@media (min-width: 769px) {
    .ux-mobile-drawer-toggle,
    .ux-mobile-drawer-overlay {
        display: none !important;
    }

    .ux-mobile-drawer-host > .ux-mobile-drawer-target {
        transform: none !important;
        position: relative !important;
        max-width: none !important;
    }
}

/* ProductivIA brand typography */
.productivia-brand {
    white-space: nowrap;
}
.productivia-brand .pia-ia {
    font-size: 0.72em;
    position: relative;
    top: -0.35em;
    font-weight: 700;
    letter-spacing: 0.02em;
}

/* ===== UX Player ===== */

.ux-player {
    background: var(--bg-card, rgba(18, 18, 26, 0.95));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.06));
    border-radius: 10px;
    padding: 12px 16px;
    user-select: none;
}

.ux-player-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
    min-height: 28px;
}

/* Zone titre + temps : a droite du label en largeur pleine ;
   en mode etroit, scroll horizontal pour tout afficher. */
.ux-player-header-scroll {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.ux-player-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted, #a0aec0);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin: 0;
    min-width: 0;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ux-player-header-scroll > .ux-player-time {
    flex-shrink: 0;
    margin-left: auto;
}

.ux-player-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    /* Toujours a droite, meme si le label est vide ou display:none
       (apps qui affichent le titre ailleurs, ex. Musique). */
    margin-left: auto;
}

/* Mode etroit : titre + temps colles, scroll horizontal ; icons fixes */
.ux-player-narrow .ux-player-header-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
}
.ux-player-narrow .ux-player-header-scroll::-webkit-scrollbar {
    height: 4px;
}
.ux-player-narrow .ux-player-header-scroll::-webkit-scrollbar-thumb {
    background-color: var(--ux-scrollbar-thumb, rgba(255, 255, 255, 0.14));
    border: none;
    border-radius: 999px;
}
.ux-player-narrow .ux-player-label {
    flex: 0 0 auto;
    overflow: visible;
    text-overflow: unset;
    max-width: none;
}
.ux-player-narrow .ux-player-header-scroll > .ux-player-time {
    margin-left: 0;
}

.ux-player-controls {
    display: flex;
    align-items: center;
    gap: 12px;
}

.ux-player-play {
    position: relative;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: var(--accent, #4a9eff);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    user-select: none;
    transition: transform 0.15s, background 0.15s;
    overflow: visible;
}

.ux-player-skip {
    position: relative;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-primary, #f0f0f5);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: background 0.15s, transform 0.15s;
}

.ux-player-skip svg {
    width: 16px;
    height: 16px;
}

.ux-player-skip:hover {
    background: rgba(255, 255, 255, 0.14);
}

.ux-player-skip:active {
    transform: scale(0.95);
}

.ux-player-play svg {
    width: 16px;
    height: 16px;
}

.ux-player-play:hover {
    transform: scale(1.08);
}

.ux-player-play:active {
    transform: scale(0.95);
}

/* Anneau aurore Boréal — progression de lecture (UX.player / UX.videoPlayer / UX.playButton)
   Les couleurs du spectre apparaissent progressivement selon --ux-play-progress (0..1).
   Pas de rotation : l'arc révèle la position dans le média. */
.ux-player-play::before,
.ux-video-player-play::before {
    content: '';
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    background: conic-gradient(
        from -90deg,
        #34d399 0deg,
        #22d3ee 60deg,
        #6366f1 120deg,
        #a78bfa 180deg,
        #ec4899 240deg,
        #84cc16 300deg,
        #34d399 360deg
    );
    --_ux-play-arc: calc(var(--ux-play-progress, 0) * 360deg);
    -webkit-mask-image:
        conic-gradient(from -90deg, #000 0deg, #000 var(--_ux-play-arc), transparent var(--_ux-play-arc)),
        radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    -webkit-mask-composite: source-in;
    mask-image:
        conic-gradient(from -90deg, #000 0deg, #000 var(--_ux-play-arc), transparent var(--_ux-play-arc)),
        radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    mask-composite: intersect;
    filter: saturate(1.35);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
.ux-player-play.has-progress::before,
.ux-video-player-play.has-progress::before {
    opacity: 1;
}

/* Anneau aurore Boréal — mode « actif » tournant (ex. cartes Musique via .ux-boreal-play-ring) */
@keyframes ux-boreal-play-spin {
    to { transform: rotate(360deg); }
}
.ux-boreal-play-ring.is-active::before {
    content: '';
    position: absolute;
    inset: -6px;
    border-radius: 50%;
    background: conic-gradient(
        from 0deg,
        #34d399 0deg,
        #22d3ee 60deg,
        #6366f1 120deg,
        #a78bfa 180deg,
        #ec4899 240deg,
        #84cc16 300deg,
        #34d399 360deg
    );
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    mask: radial-gradient(farthest-side, transparent calc(100% - 2.5px), #000 calc(100% - 2px));
    filter: saturate(1.35);
    animation: ux-boreal-play-spin 11s linear infinite;
    pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
    .ux-boreal-play-ring.is-active::before {
        animation: none;
        background: conic-gradient(#34d399, #22d3ee, #a78bfa, #ec4899, #34d399);
    }
}

/* Variante minimale : bouton play/pause + anneau seul (UX.playButton) */
.ux-player-button-only {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
}
.ux-player-button-only .ux-player-play {
    width: 48px;
    height: 48px;
}
.ux-player-button-only .ux-player-play svg {
    width: 20px;
    height: 20px;
}
.ux-player-button-only.ux-player-btn-sm .ux-player-play {
    width: 36px;
    height: 36px;
}
.ux-player-button-only.ux-player-btn-sm .ux-player-play svg {
    width: 16px;
    height: 16px;
}
.ux-player-button-only.ux-player-btn-lg .ux-player-play {
    width: 64px;
    height: 64px;
}
.ux-player-button-only.ux-player-btn-lg .ux-player-play svg {
    width: 26px;
    height: 26px;
}
.ux-player-button-only.ux-player-btn-lg .ux-player-play::before {
    inset: -8px;
}

.ux-player-wf-stack {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* Pas de gap : la hauteur de pile = hauteur onde seule → centrage
       vertical exact avec le bouton play (align-items: center). */
    gap: 0;
    position: relative;
    justify-content: center;
}

.ux-player-wf-wrap {
    flex: 1;
    min-width: 0;
    height: 48px;
    cursor: pointer;
    position: relative;
    border-radius: 4px;
}

/* Hauteur fixe = bouton play (36px) + anneau (inset -6 → 48px) */
.ux-player-wf-stack > .ux-player-wf-wrap {
    flex: 0 0 48px;
    height: 48px;
    max-height: 48px;
    align-self: stretch;
}

/* Sous-onde (chrono etroit / graduations optionnelles) hors flux :
   ne decale jamais le centrage play ↔ wave */
.ux-player-under {
    display: none;
    flex-direction: column;
    min-width: 0;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    margin-top: 4px;
    pointer-events: none;
}

.ux-player-narrow .ux-player-under,
.ux-player-has-ruler .ux-player-under {
    display: flex;
}

.ux-player-time-ruler {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 10px;
    line-height: 1.2;
    color: var(--text-muted, #6b7280);
    padding: 0 2px;
    user-select: none;
}

.ux-player-time-ruler-tick {
    flex: 0 0 auto;
}

/* Chrono sous l'onde : reserve (timeRuler / legacy) — plus utilise en mode etroit */
.ux-player-time-below {
    display: none;
    font-size: 11px;
    line-height: 1.2;
    font-family: var(--font-mono, monospace);
    color: var(--text-muted, #a0aec0);
    padding: 0 2px;
    white-space: nowrap;
    user-select: none;
    text-align: left;
}

.ux-player-narrow .ux-player-time-ruler {
    display: none !important;
}

.ux-player-wf-wrap canvas {
    width: 100%;
    height: 100%;
    display: block;
}

.ux-player-dl {
    width: 26px;
    height: 26px;
    border: none;
    background: transparent;
    color: var(--text-muted, #6b7280);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
    flex-shrink: 0;
    padding: 0;
    transition: color 0.15s, background 0.15s;
    user-select: none;
}
.ux-player-dl svg { width: 14px; height: 14px; }
.ux-player-dl:hover { color: var(--text-primary, #f0f0f5); background: rgba(255,255,255,0.06); }

.ux-player-time {
    font-size: 12px;
    font-family: var(--font-mono, monospace);
    color: var(--text-muted, #a0aec0);
    white-space: nowrap;
    min-width: 0;
    text-align: right;
    flex-shrink: 0;
}

/* ===== Mode compact : temps empile (cur / dur) dans le header ===== */
.ux-player-compact .ux-player-controls {
    gap: 10px;
}
.ux-player-side {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-width: 0;
}
.ux-player-compact .ux-player-header-scroll > .ux-player-time {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.15;
    min-width: 0;
    text-align: right;
    gap: 1px;
}
.ux-player-narrow.ux-player-compact .ux-player-header-scroll > .ux-player-time {
    align-items: flex-start;
    text-align: left;
}
.ux-player-compact .ux-player-time-cur {
    color: var(--accent, #4a9eff);
    font-weight: 600;
}
.ux-player-compact .ux-player-time-dur {
    color: var(--text-muted, #6b7280);
    font-size: 11px;
}
.ux-player-side-icons {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
}

.ux-player-vol-wrap {
    position: relative;
    flex-shrink: 0;
}

.ux-player-vol-btn {
    position: relative;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--text-muted, #a0aec0);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    user-select: none;
    touch-action: none;
    transition: color 0.15s, background 0.15s;
    --ux-vol-progress: 1;
}

/* Anneau de volume : arc vert (= niveau), epaisseur 2px */
.ux-player-vol-btn::before {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    background: conic-gradient(
        from -90deg,
        #34d399 0deg,
        #34d399 calc(var(--ux-vol-progress, 1) * 360deg),
        rgba(52, 211, 153, 0.22) calc(var(--ux-vol-progress, 1) * 360deg)
    );
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 100%);
    mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 100%);
    pointer-events: none;
}

.ux-player-vol-btn svg {
    width: 14px;
    height: 14px;
    position: relative;
    z-index: 1;
}

.ux-player-vol-btn:hover {
    color: var(--text-primary, #f0f0f5);
    background: rgba(255, 255, 255, 0.06);
}

.ux-player-vol-popup {
    position: absolute;
    top: calc(100% + 8px);
    right: -10px;
    background: var(--bg-secondary, rgba(18, 18, 26, 0.98));
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 8px;
    padding: 14px 12px;
    width: 120px;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-4px);
    transition: opacity 0.15s, transform 0.15s;
    z-index: var(--z-dropdown, 100);
    box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,0.4));
    cursor: ew-resize;
    touch-action: none;
    user-select: none;
}

.ux-player-vol-popup.open {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.ux-player-vol-track {
    width: 100%;
    height: 2px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 1px;
    position: relative;
    cursor: ew-resize;
    /* Hit area verticale elargie (invisible) pour faciliter le drag */
    padding: 10px 0;
    margin: -10px 0;
    background-clip: content-box;
    box-sizing: content-box;
}

.ux-player-vol-fill {
    height: 2px;
    background: #34d399;
    border-radius: 1px;
    width: 100%;
    pointer-events: none;
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}

.ux-player-vol-thumb {
    width: 14px;
    height: 14px;
    background: #fff;
    border-radius: 50%;
    position: absolute;
    top: 50%;
    left: 100%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.55), 0 0 2px rgba(255, 255, 255, 0.35);
    pointer-events: none;
}

/* =====================================================
   Lecteur video (UX.videoPlayer)
   ===================================================== */
.ux-video-player {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #000;
    border-radius: 10px;
    overflow: hidden;
    user-select: none;
    outline: none;
    font-family: inherit;
    cursor: default;
}

.ux-video-player:focus-visible {
    box-shadow: 0 0 0 2px var(--accent, #4a9eff);
}

.ux-video-player-el {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    background: #000;
    display: block;
    cursor: pointer;
    object-fit: contain;
}

/* Android : masquer artwork MediaPlayer avant 1ʳᵉ frame (theme-listener.js).
   opacity ignoré par SurfaceView → visibility. */
html.boreal-android video.boreal-android-video-pending {
    visibility: hidden !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

/* Contournement écran noir Chrome : frames peintes sur canvas, <video> invisible */
.ux-video-player-el.is-painted {
    opacity: 0;
}
.ux-video-player-paint {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    pointer-events: auto;
    cursor: pointer;
    background: #000;
    object-fit: contain;
}

/* Chromakey : canvas transparent pour laisser voir le damier (.ux-checker-stage) */
.ux-video-player.has-chroma {
    background: transparent;
}
.ux-video-player.has-chroma .ux-video-player-el {
    background: transparent;
}
.ux-video-player.has-chroma .ux-video-player-paint {
    background: transparent;
}

.ux-video-player.is-fullscreen {
    border-radius: 0;
    aspect-ratio: auto;
    height: 100%;
}

/* Mode fill : occupe tout le parent, coins carrés, sans bordure */
.ux-video-player.is-fill {
    border-radius: 0;
    aspect-ratio: auto;
    height: 100%;
    width: 100%;
    border: none;
    box-shadow: none;
}

/* Gros bouton play central (visible en pause uniquement) */
.ux-video-player-bigplay {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(1);
    width: 72px;
    height: 72px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s, transform 0.2s, background 0.2s;
    z-index: 3;
}

.ux-video-player.is-paused .ux-video-player-bigplay {
    backdrop-filter: blur(6px);
}

.ux-video-player-bigplay svg {
    width: 32px;
    height: 32px;
    margin-left: 4px;
}

.ux-video-player.is-paused .ux-video-player-bigplay {
    opacity: 1;
    pointer-events: auto;
}

/* Mode clavier : on masque le gros bouton PLAY central pour ne pas gener la visualisation.
   Reactive au prochain mouvement de souris > 15 px. */
.ux-video-player.keyboard-mode .ux-video-player-bigplay {
    opacity: 0;
    pointer-events: none;
}

/* Pendant un chargement (spinner visible) ou en cas d'erreur, on cache le gros
   bouton PLAY pour eviter de superposer play + spinner (UX confuse). */
.ux-video-player.is-loading .ux-video-player-bigplay,
.ux-video-player.has-error .ux-video-player-bigplay {
    opacity: 0 !important;
    pointer-events: none !important;
}

.ux-video-player-bigplay:hover {
    background: rgba(0, 0, 0, 0.75);
    transform: translate(-50%, -50%) scale(1.08);
}

/* Spinner de chargement */
.ux-video-player-loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
    z-index: 4;
}

.ux-video-player-loading.visible {
    opacity: 1;
}

.ux-video-player-spinner {
    width: 44px;
    height: 44px;
    border: 3px solid rgba(255, 255, 255, 0.18);
    border-top-color: #fff;
    border-radius: 50%;
    animation: ux-video-player-spin 0.8s linear infinite;
}

@keyframes ux-video-player-spin {
    to { transform: rotate(360deg); }
}

.ux-video-player-loading-msg {
    color: rgba(255, 255, 255, 0.85);
    font-size: 12px;
    text-align: center;
    margin-top: 10px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
    min-height: 16px;
}

.ux-video-player-loading {
    flex-direction: column;
}

/* Overlay d'erreur */
.ux-video-player-error {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.85);
    backdrop-filter: blur(4px);
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s;
    z-index: 7;
}

.ux-video-player-error.visible {
    opacity: 1;
    pointer-events: auto;
}

.ux-video-player-error-icon {
    width: 48px;
    height: 48px;
    color: #ef4444;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ux-video-player-error-icon i,
.ux-video-player-error-icon svg {
    width: 48px;
    height: 48px;
    display: block;
}

.ux-video-player-error-title {
    font-size: 16px;
    font-weight: 600;
    color: #fff;
    max-width: 80%;
}

.ux-video-player-error-desc {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.7);
    max-width: 80%;
    line-height: 1.5;
}

.ux-video-player-error-retry {
    margin-top: 8px;
}

/* Thumbnail preview (popup sur hover timeline) */
.ux-video-player-thumb {
    position: absolute;
    left: 0;
    bottom: 80px;
    background: rgba(0, 0, 0, 0.85);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 6px;
    padding: 4px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.1s;
    z-index: 5;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}

.ux-video-player-thumb.visible {
    opacity: 1;
}

.ux-video-player-thumb canvas {
    display: block;
    border-radius: 4px;
    background: #111;
}

.ux-video-player-thumb-time {
    text-align: center;
    color: #fff;
    font-size: 11px;
    font-family: var(--font-mono, monospace);
    padding: 3px 0 1px;
    letter-spacing: 0.3px;
}

/* Barre de controles (bottom)
   bottom:-1px + padding bas +1 : couvre les ecarts subpixel (GPU / DPR)
   qui laissaient 1 px de video a pleine luminosite sous le degrade. */
.ux-video-player-controls {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 14px 13px;
    background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.35) 60%, rgba(0,0,0,0) 100%);
    color: #fff;
    opacity: 0;
    transform: translateY(4px);
    pointer-events: none;
    transition: opacity 0.2s, transform 0.2s;
    z-index: 6;
    overflow: visible;
}

.ux-video-player.controls-visible .ux-video-player-controls,
.ux-video-player.is-paused .ux-video-player-controls {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.ux-video-player-play {
    position: relative;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: background 0.15s, transform 0.15s;
    overflow: visible;
    user-select: none;
}

.ux-video-player-play svg {
    width: 14px;
    height: 14px;
}

.ux-video-player-play:hover {
    background: rgba(255, 255, 255, 0.25);
}

.ux-video-player-play:active {
    transform: scale(0.95);
}

.ux-video-player-time {
    font-size: 12px;
    font-family: var(--font-mono, monospace);
    color: rgba(255, 255, 255, 0.9);
    white-space: nowrap;
    min-width: 80px;
    flex-shrink: 0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

.ux-video-player-wf-wrap {
    flex: 1;
    min-width: 0;
    height: 36px;
    cursor: pointer;
    position: relative;
    border-radius: 4px;
}

.ux-video-player-wf-wrap canvas {
    width: 100%;
    height: 100%;
    display: block;
}

.ux-video-player-fs {
    width: 32px;
    height: 32px;
    border: none;
    background: transparent;
    color: rgba(255, 255, 255, 0.9);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    flex-shrink: 0;
    border-radius: 6px;
    transition: background 0.15s, color 0.15s;
}

.ux-video-player-fs svg {
    width: 18px;
    height: 18px;
}

.ux-video-player-fs .ux-fs-exit { display: none; }
.ux-video-player.is-fullscreen .ux-video-player-fs .ux-fs-enter { display: none; }
.ux-video-player.is-fullscreen .ux-video-player-fs .ux-fs-exit { display: block; }

.ux-video-player-fs:hover {
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
}

/* Volume (meme structure que UX.player) */
.ux-video-player-vol-wrap {
    position: relative;
    flex-shrink: 0;
}

.ux-video-player-vol-btn {
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: rgba(255, 255, 255, 0.9);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: background 0.15s, color 0.15s;
}

.ux-video-player-vol-btn svg {
    width: 18px;
    height: 18px;
}

.ux-video-player-vol-btn:hover {
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
}

.ux-video-player-vol-popup {
    position: absolute;
    bottom: calc(100% + 8px);
    right: -4px;
    background: rgba(18, 18, 26, 0.98);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    padding: 14px 12px;
    width: 120px;
    opacity: 0;
    pointer-events: none;
    transform: translateY(4px);
    transition: opacity 0.15s, transform 0.15s;
    z-index: var(--z-dropdown, 100);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    cursor: ew-resize;
    touch-action: none;
    user-select: none;
}

.ux-video-player-vol-popup.open {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.ux-video-player-vol-track {
    width: 100%;
    height: 2px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 1px;
    position: relative;
    cursor: ew-resize;
    padding: 10px 0;
    margin: -10px 0;
    background-clip: content-box;
    box-sizing: content-box;
}

.ux-video-player-vol-fill {
    height: 2px;
    background: #34d399;
    border-radius: 1px;
    width: 100%;
    pointer-events: none;
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
}

.ux-video-player-vol-thumb {
    width: 14px;
    height: 14px;
    background: #fff;
    border-radius: 50%;
    position: absolute;
    top: 50%;
    left: 100%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.55), 0 0 2px rgba(255, 255, 255, 0.35);
    pointer-events: none;
}

/* Masquer le curseur natif quand les controles sont caches pendant la lecture */
.ux-video-player.is-playing:not(.controls-visible) {
    cursor: none;
}

/* Correcteur orthographique des champs de saisie (ux/src/42-context-defaults.js) :
   couche transparente calquee sur l'input / textarea actif, seul le
   soulignement des mots est visible. */
.ux-spell-mirror {
    position: fixed;
    left: 0;
    top: 0;
    margin: 0;
    overflow: hidden;
    pointer-events: none;
    color: transparent;
    -webkit-text-fill-color: transparent;
    text-shadow: none;
    background: transparent;
    box-shadow: none;
    outline: none;
    transform-origin: 0 0;
    user-select: none;
    -webkit-user-select: none;
}
.ux-spell-mirror.is-menu-open {
    visibility: hidden !important;
}
::highlight(mio-spell-field) {
    text-decoration: underline wavy var(--ux-spell-underline, #e5484d);
    text-decoration-thickness: 1.5px;
    text-decoration-skip-ink: none;
}

/* Menu contextuel generique (UX.contextMenu) */
.ux-context-menu {
    position: fixed;
    /* Doit etre au-dessus de tous les overlays applicatifs : agent flottant
       (panel 8999, FAB 9000), modales, loaders. Reste sous le canal
       mentions OS (999999) qui est reserve aux notifications systeme
       critiques. */
    z-index: 999998;
    background: var(--bg-secondary, #12121a);
    color: var(--text-primary, #f0f0f5);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: 10px;
    padding: 0;
    min-width: 180px;
    box-shadow: var(--shadow-lg, 0 10px 40px rgba(0, 0, 0, 0.45));
    animation: uxCtxFadeIn 0.12s ease;
    overflow: hidden;
}

@keyframes uxCtxFadeIn {
    from { opacity: 0; transform: scale(0.96); }
    to { opacity: 1; transform: scale(1); }
}

.ux-context-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 14px;
    box-sizing: border-box;
    background: none;
    border: none;
    color: var(--text-primary, #f0f0f5);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
    text-align: left;
}

.ux-context-menu-item:hover {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
}

.ux-context-menu-item svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

/* Item avec description (sous-texte) : disposition en colonne, texte qui s'enroule. */
.ux-context-menu-item.has-desc {
    align-items: flex-start;
    white-space: normal;
    padding: 11px 14px;
}
.ux-context-menu-item.has-desc svg {
    margin-top: 2px;
}
.ux-context-menu-item-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.ux-context-menu-item-label {
    font-weight: 600;
}
.ux-context-menu-item-desc {
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-secondary, #a0aec0);
    white-space: normal;
    max-width: 300px;
}
/* Menu « + » de l'agent : descriptions de mode lisibles, sans colonne etroite. */
.ux-context-menu.is-wide {
    width: min(480px, calc(100vw - 16px));
}
.ux-context-menu.is-wide .ux-context-menu-item-body {
    flex: 1;
}
.ux-context-menu.is-wide .ux-context-menu-item-desc {
    max-width: none;
}
.ux-context-menu-item-check {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    margin-left: auto;
    margin-top: 1px;
    align-self: flex-start;
    color: #4ade80;
}
.ux-context-menu-item.is-selected .ux-context-menu-item-label {
    color: var(--text-primary, #f0f0f5);
}
/* Sous-menus (item.submenu) : fleche a droite, ligne parente marquee tant que le sous-menu est ouvert. */
.ux-context-menu-item-arrow {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-left: auto;
    padding-left: 12px;
    box-sizing: content-box;
    color: var(--text-secondary, #a0aec0);
}
.ux-context-menu-item.has-submenu.is-open {
    background: var(--bg-hover, rgba(255, 255, 255, 0.06));
}
.ux-context-menu-item.has-submenu.is-open .ux-context-menu-item-arrow,
.ux-context-menu-item.has-submenu:hover .ux-context-menu-item-arrow {
    color: var(--text-primary, #f0f0f5);
}
.ux-context-menu.ux-context-submenu {
    animation: uxCtxSubIn 0.1s ease;
}
@keyframes uxCtxSubIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.ux-context-menu-item.danger {
    color: #ef4444;
}

.ux-context-menu-item.danger:hover {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
}

.ux-context-menu-separator {
    display: block;
    height: 1px;
    margin: 0;
    padding: 0;
    border: none;
    background: var(--border, rgba(255, 255, 255, 0.08));
    flex-shrink: 0;
}

/* Visualiseur micro (UX.micLevelWaveform) — canvas block, dimensions fixees par l’app */
.ux-mic-level-waveform {
    display: block;
    vertical-align: middle;
    max-width: 100%;
}

/* ============================================================================
   SUPPRESSION D'ELEMENTS DE LISTE (.nav-item-deletable)

   Pattern UX standard pour rendre n'importe quel item de liste de sidebar
   supprimable. Voir documentation : app UX, section "Suppression dans la
   sidebar". Utilisable avec n'importe quel contenu (.nav-item, ou un item
   personnalise comme .history-item dans l'app Images).

   Structure DOM attendue :
     .nav-item-deletable                  // wrapper, overflow:hidden
       .nav-item-deletable-slide          // contenu glissant (translateX)
         <ITEM>                           // .nav-item ou tout autre conteneur
         .nav-item-delete-zone            // zone rouge a droite (souris)
           .nav-item-trash-btn            // bouton corbeille
           .nav-item-confirm-text         // « Confirmer ? »
       .nav-item-swipe-bg                 // zone rouge derriere (tactile)

   Etats CSS :
     hover-revealed     -> Hover 0.5s sur l'actif : zone rouge 48px
     confirm-revealed   -> Clic corbeille : zone 140px + texte
     swiping            -> Touch drag en cours
     swiped             -> Swipe valide (>30px) : slide a -60px
   ============================================================================ */

.nav-item-deletable {
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
}

.nav-item-deletable-slide {
    display: flex;
    align-items: center;
    position: relative;
    z-index: 1;
    background: var(--bg-secondary, transparent);
    will-change: transform;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Item interieur : on autorise n'importe quelle classe (pas seulement
   .nav-item) en visant le premier enfant du slide qui n'est pas la zone
   de suppression. Cela laisse les apps utiliser leur propre layout (ex:
   .history-item avec image + meta dans Images). */
.nav-item-deletable .nav-item-deletable-slide > :not(.nav-item-delete-zone) {
    flex: 1;
    min-width: 0;
}

.nav-item-deletable .nav-item {
    border-radius: 0;
}

/* Les spans texte sont ellipsises ; l'icone circulaire (.nav-item-icon) est
   exclue pour conserver son centrage flex (initiales/SVG au centre du rond). */
.nav-item-deletable .nav-item span:not(.nav-item-icon):not(.nav-item-body) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: block;
}

.nav-item-delete-zone {
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    width: 0;
    min-width: 0;
    opacity: 0;
    overflow: hidden;
    background: rgba(239, 68, 68, 0.5);
    flex-shrink: 0;
    user-select: none;
    transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1),
                min-width 0.25s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.2s ease;
}

.nav-item-deletable.hover-revealed .nav-item-delete-zone {
    width: 48px;
    min-width: 48px;
    opacity: 1;
}

.nav-item-deletable.confirm-revealed .nav-item-delete-zone {
    width: 140px;
    min-width: 140px;
    opacity: 1;
    justify-content: flex-start;
}

.nav-item-trash-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    min-width: 48px;
    align-self: stretch;
    cursor: pointer;
    background: #ef4444;
}

.nav-item-trash-btn:active {
    background: #dc2626;
}

.nav-item-trash-btn svg {
    width: 18px;
    height: 18px;
    stroke: white;
    fill: none;
    stroke-width: 2;
    flex-shrink: 0;
}

.nav-item-confirm-text {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    flex: 1;
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    white-space: nowrap;
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
    cursor: default;
    letter-spacing: 0.02em;
    transition: max-width 0.25s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.2s ease 0.05s;
}

.nav-item-confirm-text svg {
    flex-shrink: 0;
    stroke: rgba(255, 255, 255, 0.6);
}

.nav-item-deletable.confirm-revealed .nav-item-confirm-text {
    max-width: 100px;
    opacity: 1;
}

.nav-item-swipe-bg {
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #ef4444;
    z-index: 0;
    cursor: pointer;
    user-select: none;
    opacity: 0;
    transition: background 0.15s ease, opacity 0.15s ease;
}

.nav-item-deletable.swiping .nav-item-swipe-bg,
.nav-item-deletable.swiped .nav-item-swipe-bg {
    opacity: 1;
}

.nav-item-swipe-bg:active {
    background: #dc2626;
}

.nav-item-swipe-bg svg {
    width: 18px;
    height: 18px;
    stroke: white;
    fill: none;
    stroke-width: 2;
}

/* Fond actif rouge tres leger pendant suppression (souris ou tactile) */
.nav-item-deletable.swiped .nav-item-deletable-slide > :not(.nav-item-delete-zone),
.nav-item-deletable.swiping .nav-item-deletable-slide > :not(.nav-item-delete-zone),
.nav-item-deletable.confirm-revealed .nav-item-deletable-slide > :not(.nav-item-delete-zone) {
    background: rgba(239, 68, 68, 0.1);
}

.nav-item-deletable.swiped .nav-item-deletable-slide {
    transform: translateX(-60px);
}

/* ============================================================================
   BARRE DE RECHERCHE SIDEBAR (.sidebar-search-row + .sidebar-search-input)

   Pattern UX standard : champ de filtre en tête du panneau de gauche
   (hauteur 46 px, fond --bg-tertiary, icône loupe à gauche).
   Le bouton « + » optionnel (.sidebar-add-btn) reste defini dans l'app UX
   quand une creation locale est pertinente. Markup :

     <div class="sidebar-search-row">
       <div class="sidebar-search-input-wrap">
         <svg class="sidebar-search-icon" viewBox="0 0 24 24" fill="none"
              stroke="currentColor" stroke-width="2" width="16" height="16">
           <circle cx="11" cy="11" r="8"/>
           <line x1="21" y1="21" x2="16.65" y2="16.65"/>
         </svg>
         <input type="text" class="sidebar-search-input" placeholder="Rechercher...">
       </div>
     </div>

   Voir : app UX, section « Structure standard du panneau de gauche ».
   ============================================================================ */

.sidebar-search-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 14px 16px 10px;
    flex-shrink: 0;
}

.sidebar-search-input-wrap {
    flex: 1;
    position: relative;
    display: flex;
    align-items: center;
    min-width: 0;
}

.sidebar-search-icon {
    position: absolute;
    left: 10px;
    width: 16px;
    height: 16px;
    color: var(--text-muted, #5a5a70);
    pointer-events: none;
    flex-shrink: 0;
}

.sidebar-search-icon svg {
    width: 16px;
    height: 16px;
    display: block;
}

.sidebar-search-input {
    width: 100%;
    height: 46px;
    box-sizing: border-box;
    padding: 0 12px 0 36px;
    background: var(--bg-tertiary, #1a1a25);
    border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    border-radius: var(--radius-md, 10px);
    color: var(--text-primary, #f0f0f5);
    font-family: inherit;
    font-size: 13px;
    outline: none;
    appearance: none;
    -webkit-appearance: none;
    color-scheme: dark;
    transition: border-color var(--transition-fast, 0.15s ease);
}

.sidebar-search-input::placeholder {
    color: var(--text-muted, #5a5a70);
}

.sidebar-search-input:focus {
    border-color: var(--accent, #4a9eff);
}

/* ============================================================================
   ONGLETS DE PANNEAU (.sidebar-tabs-row + .sidebar-tab + .sidebar-tab-add-btn)

   Pattern UX standard pour la barre d'onglets en haut du panneau de gauche.
   Contient :
     - N onglets (.sidebar-tab) qui se partagent la largeur restante
     - Un bouton "+" (.sidebar-tab-add-btn) optionnel, a droite, qui cree un
       nouvel item en fonction de l'onglet actif (l'app gere l'action via
       UX.sidebarTabs.attach({ onAdd })).

   Wrap : si les onglets ne tiennent plus sur une ligne, ils passent a la
   ligne suivante (flex-wrap). Le "+" reste en haut a droite (premiere rangee).
   Un libelle n'est JAMAIS coupe au milieu d'un mot : c'est l'onglet entier
   qui bascule. Dernier recours si UN onglet depasse la largeur du panneau :
   ellipsis sur ce bouton seul (max-width: 100%).

   Convention mio.land : ne PAS dupliquer le bouton "+ Nouveau X" sur une ligne
   separee sous les onglets. On integre le "+" dans la barre d'onglets.

   Markup attendu :
     <div class="sidebar-tabs-row">
       <div class="sidebar-tabs">
         <button class="sidebar-tab active" data-tab="history"><span>Historique</span></button>
         <button class="sidebar-tab" data-tab="projects"><span>Projets</span></button>
       </div>
       <button class="sidebar-tab-add-btn" title="Nouvel element">
         <svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
       </button>
     </div>
     <div class="sidebar-tab-contents">
       <div class="sidebar-tab-content active" data-tab="history">...</div>
       <div class="sidebar-tab-content" data-tab="projects">...</div>
     </div>

   Voir : app UX, section "Onglets" (demo + API). Onglets de contenu (page) :
   .ux-tabs / .ux-tab plus bas.
   ============================================================================ */

.sidebar-tabs-row {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    min-height: 40px;
    padding: 4px 8px 0;
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    flex-shrink: 0;
    min-width: 0;
}

/* Variante : pas d'onglets, juste le bouton "+" - on l'aligne a droite
   pour rester coherent avec le pattern standard (onglets a gauche, "+" a droite). */
.sidebar-tabs-row-add-only {
    justify-content: flex-end;
}

.sidebar-tabs {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 0;
    flex: 1;
    align-items: stretch;
    min-width: 0;
}

.sidebar-tab {
    flex: 1 0 auto;
    max-width: 100%;
    padding: 0 8px;
    border: none;
    background: transparent;
    color: var(--text-secondary, rgba(255, 255, 255, 0.6));
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
    border-bottom: 2px solid transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 36px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Pas de transition : feedback :active instantane au pointerdown. */
}

.sidebar-tab:hover {
    color: var(--text-primary, #fff);
    background: rgba(255, 255, 255, 0.03);
}

.sidebar-tab:active {
    background: var(--accent, #8b5cf6) !important;
    color: #fff !important;
}

.sidebar-tab.active {
    color: var(--text-primary, #fff);
    border-bottom-color: var(--accent, #8b5cf6);
}

/* Compteur optionnel a droite du libelle (ex: "Historique 100"). Pattern
   utilise par Harmonie, Exercices, etc. Mis en sourdine au repos, pleine
   opacite quand l'onglet est actif. */
.sidebar-tab .tab-count {
    font-size: 10px;
    font-weight: 600;
    color: currentColor;
    opacity: 0.6;
    line-height: 1;
    margin-left: 4px;
}

.sidebar-tab.active .tab-count { opacity: 1; }

/* Bouton "+" a droite : compact, couleur accent, signale l'affordance de
   creation. L'app le wire via UX.sidebarTabs.attach({ onAdd }). */
.sidebar-tab-add-btn {
    flex-shrink: 0;
    align-self: flex-start;
    margin-top: 4px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid rgba(74, 158, 255, 0.25);
    border-radius: 6px;
    background: linear-gradient(135deg, rgba(74, 158, 255, 0.10), rgba(74, 158, 255, 0.04));
    color: var(--accent, #4a9eff);
    cursor: pointer;
    user-select: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .15s, border-color .15s, transform .08s, var(--ux-hover-rim-transition);
}

.sidebar-tab-add-btn:hover {
    background: linear-gradient(135deg, rgba(74, 158, 255, 0.18), rgba(74, 158, 255, 0.08));
    border-color: rgba(74, 158, 255, 0.45);
}

.sidebar-tab-add-btn:active {
    transform: scale(0.94);
}

.sidebar-tab-add-btn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    stroke-width: 2.2;
    fill: none;
    display: block;
}

/* Conteneurs de contenu d'onglet : panneaux superposes (position absolute)
   pour bascules instantanees. Toggle visibility plutot que display:none/block
   afin d'eviter un layout pass complet sur le panneau entrant. */
.sidebar-tab-contents {
    flex: 1;
    position: relative;
    min-height: 0;
    overflow: hidden;
}

.sidebar-tab-content {
    position: absolute;
    inset: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    visibility: hidden;
    pointer-events: none;
    z-index: 0;
    contain: layout paint style;
}

.sidebar-tab-content.active {
    visibility: visible;
    pointer-events: auto;
    z-index: 1;
}

/* ============================================================================
   ONGLETS DE CONTENU (.ux-tabs + .ux-tab)

   Barre d'onglets de PAGE (detail, fiche, Admin > Utilisateurs), pas de
   sidebar. Les onglets sont dimensionnes au contenu (icone + libelle) et
   PASSENT A LA LIGNE des qu'ils ne tiennent plus (2 lignes ou plus).
   Interdit : overflow-x / scroll horizontal / libelle coupe.

   Markup :
     <div class="ux-tabs" role="tablist">
       <button type="button" class="ux-tab active" data-tab="info" role="tab">
         <svg ...></svg><span>Information</span>
       </button>
       <button type="button" class="ux-tab" data-tab="apps" role="tab">...</button>
     </div>
     <div class="ux-tab-panels">
       <div class="ux-tab-panel active" data-tab="info">...</div>
       <div class="ux-tab-panel" data-tab="apps">...</div>
     </div>

   JS : UX.tabs.attach(tabsEl, { contents: panelsEl, onChange })
        (alias de UX.sidebarTabs.attach — memes options).

   Demo : app UX > Onglets > « Onglets de contenu (wrap) ».
   ============================================================================ */

.ux-tabs,
.user-tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    align-content: flex-start;
    gap: 0;
    padding: 0;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    background: var(--bg-secondary, rgba(18, 18, 26, 0.95));
    border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
    flex-shrink: 0;
}

.ux-tab,
.user-tab {
    background: transparent;
    border: none;
    padding: 12px 16px;
    color: var(--text-secondary, rgba(255, 255, 255, 0.6));
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    user-select: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    font-weight: 500;
    flex: 0 0 auto;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

.ux-tab svg,
.user-tab svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    flex-shrink: 0;
}

.ux-tab:hover,
.user-tab:hover {
    color: var(--text-primary, #f0f0f5);
}

.ux-tab.active,
.user-tab.active {
    color: var(--accent, #4a9eff);
    border-bottom-color: var(--accent, #4a9eff);
    font-weight: 600;
}

.ux-tab .tab-count,
.user-tab .tab-count {
    font-size: 10px;
    font-weight: 600;
    color: currentColor;
    opacity: 0.6;
    line-height: 1;
    margin-left: 2px;
}

.ux-tab.active .tab-count,
.user-tab.active .tab-count {
    opacity: 1;
}

.ux-tab-panels {
    min-width: 0;
}

.ux-tab-panel {
    display: none;
}

.ux-tab-panel.active {
    display: block;
}

/* ============================================================================
   UX.tooltip  -  Infobulle Material Design (survol)

   Remplace les infobulles natives du navigateur (attribut title) par une
   bulle solide, rectangulaire, avec une largeur maximale qui force le retour
   a la ligne du texte (au lieu d'une longue ligne horizontale illisible).

   - Surface inverse (sombre sur theme clair, claire sur theme sombre) facon
     Material Design 3.
   - Elevation (ombre), coins arrondis, petite fleche orientee vers la cible.
   - Apparition/disparition animees (fade + scale + leger glissement).

   S'utilise partout via l'attribut title (auto-converti) ou data-ux-tooltip.
   ============================================================================ */
.ux-tooltip {
    /* Une seule forme SVG (rectangle arrondi + fleche) dessine le fond complet.
       Le conteneur ne porte plus ni background ni border, pour eviter toute
       distinction entre le rectangle et la fleche. */
    /* Verre givre : la couche .ux-tooltip-glass floute la page (backdrop-filter).
       Densite alignee sur .ux-frost-float (~0.72) pour que le texte derriere
       ne reste pas lisible. Le fill SVG reste un cran plus leger afin que le
       flou transperce encore sur le corps de la bulle. */
    --ux-tip-bg: rgba(16, 16, 26, 0.70);
    --ux-tip-glass: rgba(10, 10, 16, 0.62);
    --ux-tip-border: rgba(255, 255, 255, 0.18);
    --ux-tip-blur: blur(24px);
    --ux-arrow-h: 9px;
    --ux-tip-svg-w: 0px;
    --ux-tip-svg-h: 0px;
    /* Forme commune (rectangle + fleche) pour clipper l'aurore exactement sur
       le fond. Pilotee par JS (meme path que le SVG de fond). */
    --ux-tip-clip: none;
    /* Etats de l'animation "page de livre" : l'axe de rotation est la pointe de
       la fleche (transform-origin pose en px par JS). Pilotes par placement.
       Appliques sur .ux-tooltip-flip, PAS ici : un transform sur ce conteneur
       empecherait backdrop-filter de flouter la page. */
    --ux-tip-flip-closed: perspective(720px) scale(0.94);
    --ux-tip-flip-open: perspective(720px) scale(1);
    position: fixed;
    top: 0;
    left: 0;
    /* Toujours au-dessus de tout (grille d'apps, fenetres, dialogues OS qui
       montent jusqu'a ~100000). Une infobulle est l'element transitoire le
       plus prioritaire visuellement. */
    z-index: 2147483600;
    width: max-content;
    max-width: min(220px, calc(100vw - 24px));
    box-sizing: border-box;
    padding: 0;
    border-radius: 8px;
    background: transparent;
    border: 0;
    color: #f4f4fb;
    font-family: var(--font-ui, 'Inter', -apple-system, BlinkMacSystemFont, sans-serif);
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: 0.1px;
    text-align: left;
    overflow: visible;
    pointer-events: none;
    /* opacity reste a 1 : une opacite < 1 (ou will-change: opacity) sur cet
       ancetre isole le stacking context et tue le verre givre. Le masquage
       passe par visibility ; le fondu vit sur .ux-tooltip-flip. */
    opacity: 1;
    /* DEFENSE EN PROFONDEUR : visibility est discrete, insensible aux
       animations d'opacite type uxAppFadeIn (fill-mode:forwards). */
    visibility: hidden;
    transition: visibility 0s linear 0.24s;
}

.ux-tooltip.visible {
    visibility: visible;
    /* Apparition immediate : pas de delai sur le basculement de visibility. */
    transition-delay: 0s;
}

/* Animation 3D isolee : le verre givre reste hors de ce wrapper pour que
   backdrop-filter echantillonne vraiment la page derriere la bulle. */
.ux-tooltip-flip {
    position: relative;
    z-index: 1;
    opacity: 0;
    transform: var(--ux-tip-flip-closed, perspective(720px) scale(0.94));
    transition:
        transform 0.24s cubic-bezier(0.33, 1.06, 0.6, 1),
        opacity 0.16s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}
.ux-tooltip.visible .ux-tooltip-flip {
    opacity: 1;
    transform: var(--ux-tip-flip-open, perspective(720px) scale(1));
}

/* La bulle et TOUTES ses couches (verre givre, fond SVG aurore, texte) sont
   totalement insensibles a la souris : aucune interception possible du
   pointeur, donc aucune perturbation de la detection du survol de l'element
   declencheur (mouseleave et :hover restent fiables, meme quand la bulle
   recouvre l'element ou ses voisins). NE JAMAIS retirer. */
.ux-tooltip,
.ux-tooltip * {
    pointer-events: none !important;
}

.ux-tooltip-text {
    /* Le padding vit ICI, jamais sur le bloc clampe. Chromium peint la ligne
       suivant un -webkit-line-clamp lorsque le padding est sur le meme element :
       elle sort alors de la forme SVG (texte sous la bulle). */
    position: relative;
    z-index: 2;
    padding: 8px 12px;
}
.ux-tooltip-clamp {
    display: -webkit-box;
    -webkit-line-clamp: 12;
    line-clamp: 12;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: break-word;
    word-break: normal;
    white-space: normal;
}

/* Variante large : textes longs (cartes, fiches). Plus large, typo plus
   petite, pas de clamp, fond plus opaque pour se distinguer de la carte. */
.ux-tooltip[data-size="lg"] {
    max-width: min(420px, calc(100vw - 32px));
    font-size: 11px;
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: 0;
    --ux-tip-bg: rgba(12, 12, 20, 0.90);
    --ux-tip-glass: rgba(8, 8, 14, 0.82);
    --ux-tip-border: rgba(255, 255, 255, 0.30);
}
.ux-tooltip[data-size="lg"] .ux-tooltip-text {
    padding: 12px 14px;
}
.ux-tooltip[data-size="lg"] .ux-tooltip-clamp {
    display: block;
    -webkit-line-clamp: unset;
    line-clamp: unset;
    overflow: visible;
    overflow-wrap: break-word;
    white-space: pre-line;
}

/* Verre givre : rectangle du corps (pas la fleche). Chromium n'applique PAS
   backdrop-filter sur un element qui a aussi clip-path / overflow:hidden :
   on ne clippe donc pas cette couche sur le path SVG. Posee SOUS le SVG,
   hors du wrapper 3D (.ux-tooltip-flip), pour flouter vraiment la page. */
.ux-tooltip-glass {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    border-radius: 8px;
    background: var(--ux-tip-glass, rgba(10, 10, 16, 0.62));
    -webkit-backdrop-filter: var(--ux-tip-blur, blur(24px));
    backdrop-filter: var(--ux-tip-blur, blur(24px));
}

/* Fond SVG unique : un seul path ferme contient le rectangle arrondi ET la
   fleche. Le stroke suit donc le contour complet sans aucune jonction visible.
   C'est aussi cette forme qui PROJETTE l'aurore boreale a l'EXTERIEUR via des
   drop-shadow colores animes (vert / cyan / violet / rose) : la lueur emane du
   contour exact (fleche comprise) sans jamais empieter sur l'interieur. */
.ux-tooltip-bg {
    position: absolute;
    left: 0;
    top: 0;
    width: var(--ux-tip-svg-w);
    height: var(--ux-tip-svg-h);
    pointer-events: none;
    overflow: visible;
    z-index: 1;
    /* Halo autour du contour. Intensité volontairement douce ;
       en clair, uniquement du noir (pas d'aurore colorée). */
    filter:
        drop-shadow(0 1px 3px rgba(0, 0, 0, 0.26))
        drop-shadow(0 0 3px rgba(52, 211, 153, 0.35))
        drop-shadow(0 0 6px rgba(167, 139, 250, 0.26));
}
.ux-tooltip[data-placement="bottom"] .ux-tooltip-bg {
    top: calc(-1 * var(--ux-arrow-h));
}
.ux-tooltip[data-placement="right"] .ux-tooltip-bg {
    left: calc(-1 * var(--ux-arrow-h));
}
.ux-tooltip-bg-shape {
    fill: var(--ux-tip-bg);
    stroke: var(--ux-tip-border);
    stroke-width: 1;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
}


/* Repli historique : sans backdrop-filter (verre givre indisponible), on rend
   le fond SVG quasi opaque pour garder un interieur sombre lisible. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .ux-tooltip {
        --ux-tip-bg: rgba(24, 24, 36, 0.97);
        --ux-tip-glass: rgba(14, 14, 22, 0.96);
    }
    [data-theme="light"] .ux-tooltip {
        --ux-tip-bg: rgba(255, 255, 255, 0.98);
        --ux-tip-glass: rgba(255, 255, 255, 0.96);
    }
}

@media (prefers-reduced-motion: reduce) {
    .ux-tooltip {
        transition: none;
    }
    .ux-tooltip-flip,
    .ux-tooltip.visible .ux-tooltip-flip {
        transition: none;
        transform: none;
    }
    /* On garde le halo aurore (statique, via le filtre par defaut du fond)
       pour l'identite visuelle, mais sans derive animee. */
    .ux-tooltip-bg {
        animation: none;
    }
}

/* ============================================================
   DAMIER MEDIA / DOCUMENTS — letterbox sans cadre
   Reference : docs/rules/03-ux.md (Damier letterbox)
   Demo : app UX > Damier
   ============================================================ */

:root {
    --ux-checker-bg: #0a0a0a;
    --ux-checker-tile: #141414;
    --ux-checker-image:
        linear-gradient(45deg, var(--ux-checker-tile) 25%, transparent 25%),
        linear-gradient(-45deg, var(--ux-checker-tile) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, var(--ux-checker-tile) 75%),
        linear-gradient(-45deg, transparent 75%, var(--ux-checker-tile) 75%);
}

html[data-theme="light"] {
    --ux-checker-bg: #f0eee8;
    --ux-checker-tile: #e2e0d8;
}

.ux-checker-stage {
    background-color: var(--ux-checker-bg, #0a0a0a);
    background-image: var(--ux-checker-image);
    background-size: 40px 40px;
    background-position: 0 0, 0 20px, 20px -20px, -20px 0;
}

/* Surface media/document au ratio : AUCUN contour ni ombre.
   Le damier de .ux-checker-stage marque les zones hors contenu. */
.ux-media-frame {
    position: relative;
    flex-shrink: 0;
    background: transparent;
    border: none;
    box-shadow: none;
    outline: none;
    overflow: hidden;
}
.ux-media-frame img,
.ux-media-frame video,
.ux-media-frame .ux-video-player,
.ux-media-frame iframe {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: transparent;
    border: none;
    box-shadow: none;
}

/* ============================================================
   BARRE VERRE FUMÉ (frost) — sticky + backdrop-filter
   Reference : docs/rules/03-ux.md (Barre verre fumé)
   Demo : app UX > Verre fumé
   Incident Actualité 2026-07-29 : sans fond opaque sur le conteneur
   qui scrolle, Chromium n'applique PAS le flou en thème sombre
   (le mode clair « marche » par accident grâce au fond #f7f7f4).

   Tokens : une seule source pour .ux-frost-bar, titlebars mobile
   et .ux-mobile-main-bar (liste + section).
   ============================================================ */

:root {
    --ux-frost-bg: rgba(10, 10, 15, 0.55);
    --ux-frost-bg-fallback: rgba(10, 10, 15, 0.96);
    --ux-frost-blur: blur(8px);
    --ux-frost-border: rgba(255, 255, 255, 0.1);
}

[data-theme="light"] {
    --ux-frost-bg: rgba(247, 247, 244, 0.55);
    --ux-frost-bg-fallback: rgba(247, 247, 244, 0.96);
    --ux-frost-border: rgba(0, 0, 0, 0.12);
}

/**
 * Conteneur qui scrolle et qui contient .ux-frost-bar.
 * OBLIGATOIRE : fond opaque (sinon backdrop-filter inerte en sombre).
 */
.ux-frost-scroll {
    background: var(--bg-primary, #0a0a0f);
}

/* Panneau / sidebar qui scrolle sous une titlebar frost */
.ux-panel.ux-frost-scroll,
.sidebar.ux-frost-scroll {
    overflow-x: hidden;
    overflow-y: auto;
}

/**
 * Barre sticky au-dessus du contenu qui défile.
 * Ne pas ajouter saturate() : inutile et parfois trompeur au debug.
 */
.ux-frost-bar {
    position: sticky;
    top: 0;
    z-index: 8;
    background: var(--ux-frost-bg);
    -webkit-backdrop-filter: var(--ux-frost-blur);
    backdrop-filter: var(--ux-frost-blur);
    border-bottom: 1px solid var(--ux-frost-border);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .ux-frost-bar {
        background: var(--ux-frost-bg-fallback);
    }
}

/**
 * Titlebar d'app (liste) + barre section mobile : verre fumé par défaut.
 * Opt-out : data-ux-no-frost sur la barre ou un ancêtre.
 * UX.appTitlebar / UX.mobileNav posent .ux-frost-bar + .ux-frost-scroll.
 */
.ux-app-titlebar.ux-frost-bar:not([data-ux-no-frost]),
.ux-mobile-main-bar.ux-frost-bar:not([data-ux-no-frost]) {
    background: var(--ux-frost-bg);
    -webkit-backdrop-filter: var(--ux-frost-blur);
    backdrop-filter: var(--ux-frost-blur);
    border-bottom-color: var(--ux-frost-border);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .ux-app-titlebar.ux-frost-bar:not([data-ux-no-frost]),
    .ux-mobile-main-bar.ux-frost-bar:not([data-ux-no-frost]) {
        background: var(--ux-frost-bg-fallback);
    }
}

/* Titlebar sticky dans un panneau / sidebar qui scrolle */
.ux-frost-scroll > .ux-app-titlebar,
.sidebar.ux-frost-scroll > .ux-app-titlebar,
.ux-panel.ux-frost-scroll > .ux-app-titlebar {
    position: sticky;
    top: 0;
    z-index: 8;
    flex-shrink: 0;
}

/* Opt-out explicite */
[data-ux-no-frost].ux-frost-bar,
[data-ux-no-frost] .ux-frost-bar {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* Variante lecture claire (ex. .main-content.reading-light) */
.reading-light .ux-frost-bar,
.reading-light.ux-frost-scroll .ux-frost-bar {
    background: rgba(247, 247, 244, 0.55);
    border-bottom-color: rgba(0, 0, 0, 0.12);
}

.reading-light .ux-frost-scroll,
.reading-light.ux-frost-scroll {
    background: #f7f7f4;
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .reading-light .ux-frost-bar,
    .reading-light.ux-frost-scroll .ux-frost-bar {
        background: rgba(247, 247, 244, 0.97);
    }
}

/* ============================================================
   VERRE FUMÉ FLOTTANT — HUD / pastilles / panneaux sur media
   Reference : app UX > Verre fumé ; usage type : Carte
   ============================================================ */

.ux-frost-float {
    background: rgba(10, 10, 15, 0.72);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    color: var(--text-primary, #f0f0f5);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.30), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}

html[data-theme="light"] .ux-frost-float {
    background: rgba(255, 255, 255, 0.88);
    border-color: rgba(0, 0, 0, 0.12);
    color: var(--text-primary, #1a1a22);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10), 0 4px 8px 3px rgba(0, 0, 0, 0.06);
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .ux-frost-float {
        background: rgba(10, 10, 15, 0.96);
    }
    html[data-theme="light"] .ux-frost-float {
        background: #ffffff;
    }
}

.ux-frost-float--pill {
    border-radius: 100px;
}

.ux-frost-float--panel {
    border-radius: 16px;
}

.ux-frost-float--chip {
    border-radius: 12px;
}

/* Scène démo / carte : damier + UI flottante par-dessus */
.ux-frost-scene {
    position: relative;
    overflow: visible;
    border-radius: 0;
    min-height: 320px;
}

.ux-frost-scene > .ux-checker-stage {
    position: absolute;
    inset: 0;
    overflow: hidden;
    border-radius: inherit;
}

.ux-frost-scene-ui {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.ux-frost-scene-ui > * {
    pointer-events: auto;
}

.ux-frost-scene-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

.ux-frost-scene-top-center {
    flex: 1 1 auto;
    display: flex;
    justify-content: center;
    min-width: 0;
}

.ux-frost-scene-bottom {
    margin-top: auto;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 10px;
}

.ux-frost-icon-btn {
    width: 44px;
    height: 44px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    cursor: pointer;
    font: inherit;
    color: var(--text-secondary, #a0aec0);
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.ux-frost-icon-btn svg {
    width: 20px;
    height: 20px;
    stroke: currentColor;
    stroke-width: 2;
    fill: none;
}

.ux-frost-icon-btn:hover {
    color: var(--text-primary, #f0f0f5);
}

.ux-frost-icon-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ux-frost-hud {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    padding: 8px 16px;
    cursor: pointer;
    font: inherit;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}

.ux-frost-hud-stat {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 56px;
}

.ux-frost-hud-stat .val {
    font-weight: 700;
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 13px;
    color: #34d399;
}

.ux-frost-hud-stat .lbl {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted, #67828f);
    margin-top: 2px;
}

.ux-frost-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    font-size: 12px;
    color: var(--text-secondary, #a0aec0);
    font-family: 'DM Mono', ui-monospace, monospace;
}

.ux-frost-chip strong {
    color: var(--text-primary, #f0f0f5);
    font-weight: 600;
}

/* Animation pivot (axe haut) — sans rebond. Ex. reset parcours Carte */
.ux-hinge-anchor {
    position: relative;
    perspective: 820px;
    perspective-origin: 50% 0%;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
}

.ux-hinge-panel {
    position: absolute;
    top: calc(100% + 10px);
    left: 0;
    right: 0;
    margin-left: auto;
    margin-right: auto;
    width: min(280px, calc(100vw - 48px));
    display: none;
    flex-direction: column;
    overflow: hidden;
    z-index: 20;
    transform-origin: top center;
    transform-style: preserve-3d;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
    will-change: transform, opacity;
}

.ux-hinge-panel.open {
    display: flex;
    animation: uxHingeFlipIn 0.34s cubic-bezier(0.2, 0, 0, 1) both;
}

@keyframes uxHingeFlipIn {
    from {
        opacity: 0.35;
        transform: rotateX(-92deg);
    }
    to {
        opacity: 1;
        transform: rotateX(0deg);
    }
}

.ux-hinge-panel-header {
    padding: 12px 14px 10px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    font-size: 13px;
    font-weight: 600;
}

.ux-hinge-panel-body {
    padding: 12px 14px 14px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.ux-hinge-panel-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}

.ux-hinge-panel-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #67828f);
}

.ux-hinge-panel-value {
    font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 14px;
    font-weight: 700;
    color: #34d399;
}

.ux-hinge-panel-hint {
    margin: 2px 0 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-secondary, #a0aec0);
}

.ux-hinge-panel-action {
    margin-top: 4px;
    width: 100%;
    padding: 10px 12px;
    border: 1px solid rgba(239, 68, 68, 0.45);
    border-radius: 10px;
    background: rgba(239, 68, 68, 0.16);
    color: #fecaca;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.ux-hinge-panel-action:hover {
    box-shadow: var(--ux-hover-rim-shadow, 0 0 0 1px rgba(255, 255, 255, 0.5));
}


/* ============================================================
   BARRE D'ACTIONS COMPACTE (icônes seules si manque d'espace)
   Reference : docs/rules/03-ux.md (Barre d'actions compacte)
   Demo : app UX > Boutons > Barre d'actions compacte
   JS : UX.attachToolbarCompact / data-ux-toolbar-compact
   ============================================================ */

.ux-toolbar,
[data-ux-toolbar-compact] {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 8px;
    min-width: 0;
    /* overflow:hidden pour le compact (mesure scrollWidth) + marge interne
       pour ne pas rogner le liseret de survol (.ux-btn box-shadow) */
    overflow: hidden;
    padding: 4px;
    margin: -4px;
}

.ux-toolbar-spacer {
    flex: 1 1 auto;
    min-width: 0;
}

/* Boutons : jamais de wrap de libellé, jamais de shrink (sinon texte coupé) */
[data-ux-toolbar-compact] > button,
[data-ux-toolbar-compact] > .ux-btn,
[data-ux-toolbar-compact] > a.ux-btn,
[data-ux-toolbar-compact] > a[role="button"] {
    flex-shrink: 0;
    white-space: nowrap;
}

[data-ux-toolbar-compact] > button > span,
[data-ux-toolbar-compact] > .ux-btn > span,
[data-ux-toolbar-compact] .ux-toolbar-label {
    white-space: nowrap;
}

/* Mode compact : libellés masqués, icônes seules */
[data-ux-toolbar-compact].is-compact > button > span,
[data-ux-toolbar-compact].is-compact > .ux-btn > span,
[data-ux-toolbar-compact].is-compact > a > span,
[data-ux-toolbar-compact].is-compact .ux-toolbar-label {
    display: none !important;
}

[data-ux-toolbar-compact].is-compact > button,
[data-ux-toolbar-compact].is-compact > .ux-btn,
[data-ux-toolbar-compact].is-compact > a.ux-btn {
    gap: 0;
}

/* ============================================================
   IDENTITÉ VISUELLE APPAREIL (os/device-identity)
   Silhouette + couleur de format : icône 24×24, hero 160×100
   ============================================================ */
.device-visual {
    display: inline-block;
    vertical-align: middle;
    color: currentColor;
    flex-shrink: 0;
}
.device-visual-icon {
    width: 24px;
    height: 24px;
}
.device-visual-hero {
    width: 160px;
    height: 100px;
}
.device-visual-icon-wrap {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: var(--device-color, var(--text-primary, #f0f0f5));
    flex-shrink: 0;
}
.device-visual-hero-wrap {
    width: 168px;
    height: 108px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--device-color, var(--text-primary, #f0f0f5));
}
.device-visual.svg-stroke {
    fill: none;
    stroke: currentColor;
}
.device-visual .dv-screen {
    fill: currentColor;
}
.device-visual-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
    overflow: hidden;
    color: var(--device-color, currentColor);
    box-sizing: border-box;
}
.device-visual-wrap-icon {
    width: 100%;
    height: 100%;
    min-width: 22px;
    min-height: 22px;
    border-radius: inherit;
}
.device-visual-wrap-hero {
    overflow: visible;
}
.device-visual-wrap .device-visual,
.device-visual-wrap svg {
    color: inherit !important;
    stroke: currentColor;
}

/* ============================================================
   SCROLLBAR PLATEFORME (capsule, rail invisible, sans degrade d'accent)
   Reference : docs/rules/03-ux.md + /os/scrollbar.css
   Meme pastille que la grille d'icones du bureau.
   Desktop 10px / tactile-mobile 1px via --ux-scrollbar-size
   ============================================================ */

:root {
    --ux-scrollbar-size: 10px;
    --ux-scrollbar-thumb: rgba(255, 255, 255, 0.14);
    --ux-scrollbar-thumb-hover: rgba(255, 255, 255, 0.20);
}

html.os-mode-mobile,
body.mode-mobile {
    --ux-scrollbar-size: 1px;
    --ux-scrollbar-thumb: rgba(255, 255, 255, 0.32);
    --ux-scrollbar-thumb-hover: rgba(255, 255, 255, 0.45);
}

[data-theme="light"] {
    --ux-scrollbar-thumb: rgba(0, 0, 0, 0.21);
    --ux-scrollbar-thumb-hover: rgba(0, 0, 0, 0.32);
}

[data-theme="light"].os-mode-mobile,
html.os-mode-mobile[data-theme="light"],
body.mode-mobile[data-theme="light"] {
    --ux-scrollbar-thumb: rgba(0, 0, 0, 0.32);
    --ux-scrollbar-thumb-hover: rgba(0, 0, 0, 0.45);
}

::-webkit-scrollbar {
    width: var(--ux-scrollbar-size, 10px) !important;
    height: var(--ux-scrollbar-size, 10px) !important;
}

::-webkit-scrollbar-track {
    background: transparent !important;
    border-radius: 999px;
}

::-webkit-scrollbar-thumb {
    background-color: var(--ux-scrollbar-thumb, rgba(255, 255, 255, 0.14));
    background-image: none;
    border: 2px solid transparent;
    background-clip: padding-box;
    border-radius: 999px;
}

::-webkit-scrollbar-thumb:hover {
    background-color: var(--ux-scrollbar-thumb-hover, rgba(255, 255, 255, 0.20));
    background-image: none;
}

html.os-mode-mobile ::-webkit-scrollbar,
body.mode-mobile ::-webkit-scrollbar {
    width: 1px !important;
    height: 1px !important;
}

html.os-mode-mobile ::-webkit-scrollbar-thumb,
body.mode-mobile ::-webkit-scrollbar-thumb {
    border: none !important;
    background-clip: border-box;
    border-radius: 0;
}

html.os-mode-mobile .ux-select-dropdown::-webkit-scrollbar,
html.os-mode-mobile .ux-select-scroll::-webkit-scrollbar,
body.mode-mobile .ux-select-dropdown::-webkit-scrollbar,
body.mode-mobile .ux-select-scroll::-webkit-scrollbar {
    width: var(--ux-scrollbar-size, 1px) !important;
    height: var(--ux-scrollbar-size, 1px) !important;
}

html.os-mode-mobile .ux-select-dropdown::-webkit-scrollbar-thumb,
html.os-mode-mobile .ux-select-scroll::-webkit-scrollbar-thumb,
body.mode-mobile .ux-select-dropdown::-webkit-scrollbar-thumb,
body.mode-mobile .ux-select-scroll::-webkit-scrollbar-thumb {
    border: none !important;
    background-clip: border-box;
    border-radius: 0;
}

::-webkit-scrollbar-corner {
    background: transparent;
}

::-webkit-scrollbar-button {
    display: none !important;
    width: 0 !important;
    height: 0 !important;
}

/* ============================================================
   PASTILLE IA — marque discrète de contenu généré
   Tampon serveur : os/image-ai-badge.php (`ai_badge: true` sur /api/image.php)
   Démo : app UX > Pastille IA
   Spec : lettres IA uniquement, Montserrat Black, double calque
          blanc + noir semi-transparent, 4.2 % du petit côté.
   ============================================================ */

.ux-ai-badge {
    --ux-ai-badge-shift: 0.055em;
    position: relative;
    display: inline-block;
    flex-shrink: 0;
    pointer-events: none;
    user-select: none;
    overflow: visible;
    font-family: 'Montserrat', var(--font-display, sans-serif);
    font-weight: 900;
    font-size: 36px;
    letter-spacing: -0.07em;
    line-height: 1;
    color: transparent;
}

.ux-ai-badge--lg {
    font-size: 88px;
}

.ux-ai-badge--in-frame {
    position: absolute;
    right: 2.8%;
    bottom: 2.8%;
    font-size: 4.2cqh;
    width: auto;
    height: auto;
}

.ux-ai-badge-slot {
    display: block;
    visibility: hidden;
}

.ux-ai-badge-ia {
    position: absolute;
    left: 0;
    top: 0;
    font: inherit;
    letter-spacing: inherit;
    line-height: inherit;
}

.ux-ai-badge-ia--ink {
    color: rgba(0, 0, 0, 0.20);
    transform: translate(var(--ux-ai-badge-shift), var(--ux-ai-badge-shift));
}

.ux-ai-badge-ia--paper {
    color: rgba(255, 255, 255, 0.24);
    transform: translate(calc(var(--ux-ai-badge-shift) * -1), calc(var(--ux-ai-badge-shift) * -1));
}

/* ============================================
   THEME CLAIR — composants partagés
   Les tokens (--bg-*, --text-*, --border) suffisent pour la plupart
   des surfaces. Overrides ci-dessous : couleurs encore en dur.
   Damier letterbox (.ux-checker-stage) : tokens --ux-checker-bg / --ux-checker-tile.
   ============================================ */

[data-theme="light"] .ux-model-info-tip {
    background: #ffffff;
    border: 1px solid var(--border, rgba(0, 0, 0, 0.12));
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
    color: var(--text-primary, #1a1a22);
}
[data-theme="light"] .ux-model-info-tip .model-info-tip-title {
    color: var(--text-primary, #1a1a22);
}
[data-theme="light"] .ux-model-info-tip .model-info-tip-excerpt,
[data-theme="light"] .ux-model-info-tip .model-info-tip-specs {
    color: var(--text-secondary, #5c5c6e);
}

[data-theme="light"] .ux-infobar {
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
}
[data-theme="light"] .ux-infobar__action {
    border-color: var(--border, rgba(0, 0, 0, 0.12));
}
[data-theme="light"] .ux-infobar__action:hover {
    background: var(--bg-hover, rgba(0, 0, 0, 0.04));
}

[data-theme="light"] .ux-dialog {
    box-shadow: 0 30px 100px rgba(0, 0, 0, 0.18);
}
[data-theme="light"] .ux-dialog-footer .ux-dialog-btn-block::before {
    background: var(--border, rgba(0, 0, 0, 0.12));
}

[data-theme="light"] .ux-tooltip {
    --ux-tip-bg: rgba(255, 255, 255, 0.78);
    --ux-tip-glass: rgba(247, 247, 244, 0.72);
    --ux-tip-border: rgba(0, 0, 0, 0.12);
    color: #1a1a22;
}
[data-theme="light"] .ux-tooltip[data-size="lg"] {
    --ux-tip-bg: rgba(255, 255, 255, 0.96);
    --ux-tip-glass: rgba(252, 252, 250, 0.92);
    --ux-tip-border: rgba(0, 0, 0, 0.20);
}

[data-theme="light"] .ux-tooltip-bg {
    filter:
        drop-shadow(0 1px 3px rgba(0, 0, 0, 0.16))
        drop-shadow(0 4px 10px rgba(0, 0, 0, 0.10));
}

[data-theme="light"] .ux-select-trigger:focus {
    background-color: rgba(109, 40, 217, 0.06);
}

[data-theme="light"] .ux-select-dropdown {
    background: #ffffff;
    color: var(--text-primary, #1a1a22);
    border-color: var(--border, rgba(0, 0, 0, 0.12));
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
}

[data-theme="light"] .ux-select-option:has(.ux-para-style) {
    border-bottom-color: rgba(0, 0, 0, 0.06);
}
[data-theme="light"] .ux-para-style-chip {
    background: rgba(0, 0, 0, 0.05);
}
[data-theme="light"] .ux-para-style-chip-on {
    background: rgba(109, 40, 217, 0.10);
}
[data-theme="light"] .ux-para-style-page {
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
}

[data-theme="light"] .ux-context-menu {
    background: #ffffff;
    color: #1a1a22;
    border-color: rgba(0, 0, 0, 0.12);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.14);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

[data-theme="light"] .ux-context-menu-item {
    color: #1a1a22;
}

[data-theme="light"] .ux-context-menu-item:hover {
    background: rgba(0, 0, 0, 0.05);
}

[data-theme="light"] .ux-context-menu-item-desc {
    color: #5c5c6e;
}

[data-theme="light"] .ux-context-menu-item.is-selected .ux-context-menu-item-label {
    color: #1a1a22;
}

[data-theme="light"] .ux-context-menu-item.has-submenu.is-open {
    background: rgba(0, 0, 0, 0.05);
}
[data-theme="light"] .ux-context-menu-separator {
    background: rgba(0, 0, 0, 0.10);
}

/* ============================================
   Tuile d'icone d'app (mode sombre)
   Classe : .ux-app-tile  +  --app-icon-color
   Repos = intermediaire couleur/neon
   Survol = carre plat (couleur pleine + glyphe blanc)
   Calques d'ombre identiques aux deux etats (transition du halo).

   Contact (.ux-person-tile) : meme recette, toujours rond.
   Le rayon et l'anneau --person-ring sont poses apres ce bloc.
   ============================================ */

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .app-icon-image,
html:not([data-theme="light"]) .app-card .app-icon,
html:not([data-theme="light"]) .app-icon-large {
    --_tile: var(--app-icon-color, var(--card-accent, var(--app-color, #6366f1)));
    --app-icon-neon: color-mix(in srgb, var(--_tile) 42%, #ffffff);
    color: var(--app-icon-neon);
    position: relative;
    overflow: visible !important;
    background: color-mix(in srgb, var(--_tile) 52%, #141820) !important;
    border: 1px solid color-mix(in srgb, var(--_tile) 38%, rgba(255, 255, 255, 0.08));
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.08) inset,
        0 4px 16px rgba(0, 0, 0, 0.42),
        0 0 20px color-mix(in srgb, var(--_tile) 30%, transparent);
    transition: transform 0.15s ease-out, box-shadow 0.3s ease, background 0.3s ease, border-color 0.3s ease, color 0.3s ease;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .app-icon-image::before,
html:not([data-theme="light"]) .app-card .app-icon::before,
html:not([data-theme="light"]) .app-icon-large::before {
    content: '';
    position: absolute;
    inset: 14%;
    border-radius: 50%;
    background: var(--_tile);
    filter: blur(10px);
    opacity: 0.28;
    pointer-events: none;
    z-index: 0;
    transition: opacity 0.3s ease;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .app-icon-image > svg,
html:not([data-theme="light"]) .app-card .app-icon > svg,
html:not([data-theme="light"]) .app-icon-large > svg {
    position: relative;
    z-index: 1;
    color: var(--app-icon-neon);
    transition: filter 0.3s ease, stroke 0.3s ease, fill 0.3s ease, stroke-width 0.3s ease;
    filter:
        drop-shadow(0 0 5px color-mix(in srgb, var(--_tile) 48%, transparent))
        drop-shadow(2px 2px 3px rgba(0, 0, 0, 0));
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg[fill="none"],
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg.svg-stroke,
html:not([data-theme="light"]) .app-icon-image > svg[fill="none"],
html:not([data-theme="light"]) .app-icon-image > svg.svg-stroke,
html:not([data-theme="light"]) .app-card .app-icon > svg[fill="none"],
html:not([data-theme="light"]) .app-card .app-icon > svg.svg-stroke,
html:not([data-theme="light"]) .app-icon-large > svg[fill="none"],
html:not([data-theme="light"]) .app-icon-large > svg.svg-stroke {
    stroke: var(--app-icon-neon) !important;
    stroke-width: 1.65;
    fill: none !important;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg[fill="currentColor"],
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg.svg-fill,
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile) > svg.svg-fill *,
html:not([data-theme="light"]) .app-icon-image > svg[fill="currentColor"],
html:not([data-theme="light"]) .app-icon-image > svg.svg-fill,
html:not([data-theme="light"]) .app-card .app-icon > svg[fill="currentColor"],
html:not([data-theme="light"]) .app-card .app-icon > svg.svg-fill,
html:not([data-theme="light"]) .app-card .app-icon > svg.svg-fill *,
html:not([data-theme="light"]) .app-icon-large > svg[fill="currentColor"],
html:not([data-theme="light"]) .app-icon-large > svg.svg-fill {
    fill: var(--app-icon-neon) !important;
    stroke: none !important;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .app-icon:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .app-icon:hover .app-icon-image,
html:not([data-theme="light"]) .app-card:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .app-card:hover .app-icon,
html:not([data-theme="light"]) .cinv-card:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .taskbar-app:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .sidebar-app-item:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .color-app-item:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .app-list-item:hover :is(.ux-app-tile, .ux-person-tile),
html:not([data-theme="light"]) .default-app-item:hover :is(.ux-app-tile, .ux-person-tile) {
    background: var(--_tile) !important;
    border-color: transparent;
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0) inset,
        0 8px 30px rgba(0, 0, 0, 0.5),
        0 0 20px color-mix(in srgb, var(--_tile) 0%, transparent);
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover::before,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .app-icon:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .app-icon:hover .app-icon-image::before,
html:not([data-theme="light"]) .app-card:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .app-card:hover .app-icon::before,
html:not([data-theme="light"]) .taskbar-app:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .sidebar-app-item:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .color-app-item:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .app-list-item:hover :is(.ux-app-tile, .ux-person-tile)::before,
html:not([data-theme="light"]) .default-app-item:hover :is(.ux-app-tile, .ux-person-tile)::before {
    opacity: 0;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .app-icon:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .app-icon:hover .app-icon-image > svg,
html:not([data-theme="light"]) .app-card:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .app-card:hover .app-icon > svg,
html:not([data-theme="light"]) .taskbar-app:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .sidebar-app-item:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .color-app-item:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .app-list-item:hover :is(.ux-app-tile, .ux-person-tile) > svg,
html:not([data-theme="light"]) .default-app-item:hover :is(.ux-app-tile, .ux-person-tile) > svg {
    filter:
        drop-shadow(0 0 5px color-mix(in srgb, var(--_tile) 0%, transparent))
        drop-shadow(2px 2px 3px rgba(0, 0, 0, 0.5));
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg[fill="none"],
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg.svg-stroke,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile) > svg[fill="none"],
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile) > svg.svg-stroke,
html:not([data-theme="light"]) .app-icon:hover .app-icon-image > svg[fill="none"],
html:not([data-theme="light"]) .app-icon:hover .app-icon-image > svg.svg-stroke,
html:not([data-theme="light"]) .app-card:hover .app-icon > svg[fill="none"],
html:not([data-theme="light"]) .app-card:hover .app-icon > svg.svg-stroke {
    stroke: #ffffff !important;
    stroke-width: 1.5;
    fill: none !important;
}

html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg[fill="currentColor"],
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg.svg-fill,
html:not([data-theme="light"]) :is(.ux-app-tile, .ux-person-tile):hover > svg.svg-fill *,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile) > svg[fill="currentColor"],
html:not([data-theme="light"]) :hover > :is(.ux-app-tile, .ux-person-tile) > svg.svg-fill,
html:not([data-theme="light"]) .app-icon:hover .app-icon-image > svg[fill="currentColor"],
html:not([data-theme="light"]) .app-icon:hover .app-icon-image > svg.svg-fill,
html:not([data-theme="light"]) .app-card:hover .app-icon > svg[fill="currentColor"],
html:not([data-theme="light"]) .app-card:hover .app-icon > svg.svg-fill,
html:not([data-theme="light"]) .app-card:hover .app-icon > svg.svg-fill * {
    fill: #ffffff !important;
    stroke: none !important;
}

/* Pastilles compactes (taskbar, titre de fenetre, listes) : meme recette, halo plus court. */
html:not([data-theme="light"]) :is(.ux-app-tile-sm, .ux-person-tile-sm) {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.08) inset,
        0 2px 8px rgba(0, 0, 0, 0.4),
        0 0 10px color-mix(in srgb, var(--_tile) 24%, transparent);
}
html:not([data-theme="light"]) :is(.ux-app-tile-sm, .ux-person-tile-sm)::before {
    filter: blur(5px);
    opacity: 0.22;
}
html:not([data-theme="light"]) :is(.ux-app-tile-sm, .ux-person-tile-sm):hover,
html:not([data-theme="light"]) :hover > :is(.ux-app-tile-sm, .ux-person-tile-sm),
html:not([data-theme="light"]) .taskbar-app:hover :is(.ux-app-tile-sm, .ux-person-tile-sm) {
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0) inset,
        0 4px 12px rgba(0, 0, 0, 0.45),
        0 0 10px color-mix(in srgb, var(--_tile) 0%, transparent);
}

/* Tuile d'icone d'app (mode clair)
   Carre plat (couleur d'app) + glyphe blanc + leger ombrage du dessin.
   Sans le fill blanc, svg.svg-fill * (UX global) pose fill:currentColor et
   les icones Material deviennent noires (couleur de texte du theme clair).
   overflow: visible (comme en mode sombre) : les pastilles BETA et le compteur
   de non-lus debordent volontairement du coin de la tuile et ne doivent pas
   etre rognes par le border-radius. */
[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) {
    --_tile: var(--app-icon-color, var(--card-accent, var(--app-color, #6366f1)));
    color: #ffffff;
    position: relative;
    overflow: visible;
    background: var(--_tile) !important;
    border: none;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    transition: transform 0.15s ease-out, box-shadow 0.3s ease, background 0.3s ease;
}

[data-theme="light"] .app-icon-image,
[data-theme="light"] .app-card .app-icon,
[data-theme="light"] .app-icon-large {
    color: #ffffff;
}

[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg {
    position: relative;
    z-index: 1;
    color: #ffffff;
    filter: drop-shadow(1px 1px 1.5px rgba(0, 0, 0, 0.22));
}

[data-theme="light"] .app-icon-image > svg,
[data-theme="light"] .app-card .app-icon > svg,
[data-theme="light"] .app-icon-large > svg {
    color: #ffffff;
    filter: drop-shadow(1px 1px 1.5px rgba(0, 0, 0, 0.22));
}

[data-theme="light"] :is(.ux-app-tile, .ux-person-tile):hover,
[data-theme="light"] :hover > :is(.ux-app-tile, .ux-person-tile) {
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
}

[data-theme="light"] :is(.ux-app-tile, .ux-person-tile):hover > svg,
[data-theme="light"] :hover > :is(.ux-app-tile, .ux-person-tile) > svg,
[data-theme="light"] .app-icon:hover .app-icon-image > svg,
[data-theme="light"] .app-card:hover .app-icon > svg {
    filter: drop-shadow(2px 2px 3px rgba(0, 0, 0, 0.5));
}

[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg[fill="none"],
[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg.svg-stroke,
[data-theme="light"] .app-icon-image > svg[fill="none"],
[data-theme="light"] .app-icon-image > svg.svg-stroke,
[data-theme="light"] .app-card .app-icon > svg[fill="none"],
[data-theme="light"] .app-card .app-icon > svg.svg-stroke,
[data-theme="light"] .app-icon-large > svg[fill="none"],
[data-theme="light"] .app-icon-large > svg.svg-stroke {
    stroke: #ffffff !important;
    stroke-width: 1.5;
    fill: none !important;
}

[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg[fill="currentColor"],
[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg[fill="currentColor"] *,
[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg.svg-fill,
[data-theme="light"] :is(.ux-app-tile, .ux-person-tile) > svg.svg-fill *,
[data-theme="light"] .app-icon-image > svg[fill="currentColor"],
[data-theme="light"] .app-icon-image > svg[fill="currentColor"] *,
[data-theme="light"] .app-icon-image > svg.svg-fill,
[data-theme="light"] .app-icon-image > svg.svg-fill *,
[data-theme="light"] .app-card .app-icon > svg[fill="currentColor"],
[data-theme="light"] .app-card .app-icon > svg[fill="currentColor"] *,
[data-theme="light"] .app-card .app-icon > svg.svg-fill,
[data-theme="light"] .app-card .app-icon > svg.svg-fill *,
[data-theme="light"] .app-icon-large > svg[fill="currentColor"],
[data-theme="light"] .app-icon-large > svg[fill="currentColor"] *,
[data-theme="light"] .app-icon-large > svg.svg-fill,
[data-theme="light"] .app-icon-large > svg.svg-fill * {
    fill: #ffffff !important;
    stroke: none !important;
}

/* Pastille de contact : meme recette que la tuile d'app, toujours ronde.
   --person-ring separe deux pastilles superposees (transparent = aucun anneau). */
.ux-person-tile {
    border-radius: 50% !important;
    /* Halo (::before) et initiales restent dans leur pastille : deux pastilles
       superposées ne mélangent pas leurs calques (initiales de la première au-dessus
       du fond de la seconde). */
    isolation: isolate;
}
/* Les initiales ne sont pas un SVG : ce calque les garde au-dessus du halo. */
.ux-person-glyph {
    position: relative;
    z-index: 1;
    line-height: 1;
    color: inherit;
    text-shadow: inherit;
}

html:not([data-theme="light"]) .ux-person-tile {
    text-shadow: 0 0 8px color-mix(in srgb, var(--_tile) 50%, transparent);
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 0 0 1px rgba(255, 255, 255, 0.08) inset,
        0 4px 16px rgba(0, 0, 0, 0.42),
        0 0 20px color-mix(in srgb, var(--_tile) 30%, transparent);
}

html:not([data-theme="light"]) .ux-person-tile-sm {
    text-shadow: 0 0 5px color-mix(in srgb, var(--_tile) 40%, transparent);
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 0 0 1px rgba(255, 255, 255, 0.08) inset,
        0 2px 8px rgba(0, 0, 0, 0.4),
        0 0 10px color-mix(in srgb, var(--_tile) 24%, transparent);
}

html:not([data-theme="light"]) .ux-person-tile:hover,
html:not([data-theme="light"]) :hover > .ux-person-tile {
    color: #ffffff;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.45);
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 0 0 1px rgba(255, 255, 255, 0) inset,
        0 8px 30px rgba(0, 0, 0, 0.5),
        0 0 20px color-mix(in srgb, var(--_tile) 0%, transparent);
}

html:not([data-theme="light"]) .ux-person-tile-sm:hover,
html:not([data-theme="light"]) :hover > .ux-person-tile-sm {
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 0 0 1px rgba(255, 255, 255, 0) inset,
        0 4px 12px rgba(0, 0, 0, 0.45),
        0 0 10px color-mix(in srgb, var(--_tile) 0%, transparent);
}

[data-theme="light"] .ux-person-tile {
    color: #ffffff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 4px 16px rgba(0, 0, 0, 0.12);
}

[data-theme="light"] .ux-person-tile:hover,
[data-theme="light"] :hover > .ux-person-tile {
    color: #ffffff;
    box-shadow:
        0 0 0 2px var(--person-ring, transparent),
        0 8px 24px rgba(0, 0, 0, 0.16);
}

/* Anneau de traits au clic. Le calque est cree par UX.installClickSpark.
   Il couvre le viewport sans intercepter le pointeur. */
.ux-click-spark {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 2147483400;
    display: block;
}

@media print {
    .ux-click-spark { display: none !important; }
}
