/*
 * Styles propres à l'ERP.
 *
 * Tabler couvre l'essentiel : on n'ajoute ici que ce qu'il ne fournit pas,
 * en s'appuyant sur ses variables CSS (--tblr-*) plutôt que sur des valeurs
 * en dur. Voir https://tabler.io/docs
 */

/*
 * Tableau de saisie des lignes de devis.
 *
 * Ni `.table` ni `.row` de Tabler ne conviennent : il faut des colonnes de
 * largeur fixe qui restent alignées alors que chaque ligne contient des champs
 * de formulaire, un bloc de détail repliable et une poignée de déplacement.
 *
 * Les colonnes sont volontairement serrées : la sidebar consomme déjà 15rem,
 * et une grille trop large basculerait en mode empilé sur un écran d'ordinateur
 * portable — c'est-à-dire presque toujours.
 */
.quote-lines {
    --quote-grid: 1.25rem minmax(9rem, 1fr) 4.5rem 5.5rem 6rem 4.5rem 5rem 6rem 4rem;
    --quote-gap: 0.375rem;
}

/*
 * Type et intitulé sur une même ligne.
 *
 * Le type est un code court : lui laisser toute la largeur de la cellule
 * repoussait l'intitulé en dessous et doublait la hauteur de chaque ligne.
 */
.quote-line-title {
    display: flex;
    gap: var(--quote-gap);
    align-items: center;
}

.quote-line-category {
    flex: 0 0 7rem;
}

.quote-line-title > .form-control {
    flex: 1 1 auto;
    min-width: 0;
}

/*
 * Un titre, un sous-total ou un commentaire n'a pas de type : sa place est
 * retirée plutôt que masquée, sinon l'intitulé partirait en retrait de 7rem.
 * Les colonnes chiffrées, elles, gardent leur place pour rester alignées.
 */
.quote-line:not([data-kind="service"]) .quote-line-category {
    display: none;
}

.quote-line {
    display: grid;
    grid-template-columns: var(--quote-grid);
    gap: var(--quote-gap);
    align-items: start;
    border-bottom: 1px solid var(--tblr-border-color);
    padding: 0.5rem 0;
}

/*
 * Une cellule de grille vaut `min-width: auto` par défaut : elle refuse de
 * descendre sous la largeur minimale de son contenu, et un élément large — la
 * barre d'outils de l'éditeur — pousse alors toute la ligne hors du cadre.
 */
.quote-line > * {
    min-width: 0;
}

.quote-line:last-child {
    border-bottom: 0;
}

.quote-line-handle {
    cursor: grab;
    color: var(--tblr-secondary);
    padding-top: 0.5rem;
    text-align: center;
}

.quote-line-handle:active {
    cursor: grabbing;
}

.quote-line-total {
    text-align: right;
    padding-top: 0.5rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Deux rangées de deux boutons : la colonne reste étroite. */
.quote-line-actions {
    display: grid;
    grid-template-columns: repeat(2, 1.75rem);
    gap: 0.125rem;
    justify-content: end;
}

/* Le détail est replié par défaut : un devis de dix lignes reste lisible. */
.quote-line-detail > summary {
    cursor: pointer;
    list-style: none;
    padding: 0.25rem 0;
}

.quote-line-detail > summary::-webkit-details-marker {
    display: none;
}

.quote-line-detail > summary::before {
    content: "\ea5f"; /* ti-chevron-right */
    font-family: "tabler-icons", sans-serif;
    margin-right: 0.25rem;
    display: inline-block;
    transition: transform 0.15s ease;
}

.quote-line-detail[open] > summary::before {
    transform: rotate(90deg);
}

/* Section secondaire repliée — Tabler ne style pas <details>, qui n'affiche
   même pas un curseur de clic sur son résumé. */
.details-toggle > summary {
    cursor: pointer;
}

/* En-tête de colonnes, calé sur la même grille que les lignes. */
.quote-lines-header {
    display: grid;
    grid-template-columns: var(--quote-grid);
    gap: var(--quote-gap);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--tblr-secondary);
    padding-bottom: 0.5rem;
    border-bottom: 2px solid var(--tblr-border-color);
}

.quote-lines-header > .text-end {
    text-align: right;
}

/* Champs compacts : la grille ne tient qu'à ce prix. */
.quote-line .form-control,
.quote-line .form-select {
    padding: 0.25rem 0.4rem;
    font-size: 0.8125rem;
}

.quote-line textarea.form-control {
    font-size: 0.8125rem;
}

/*
 * Une ligne de titre, de sous-total ou de commentaire n'a ni prix ni TVA :
 * ses colonnes chiffrées disparaissent, mais gardent leur place pour ne pas
 * décaler les lignes voisines.
 */
.quote-line [data-only="service"].invisible {
    visibility: hidden;
}

/* Les lignes de structure se distinguent au premier coup d'œil. */
.quote-line[data-kind="section"] {
    background: var(--tblr-bg-surface-secondary);
}

.quote-line[data-kind="section"] .form-control {
    font-weight: 600;
    text-transform: uppercase;
}

.quote-line[data-kind="comment"] .form-control {
    font-style: italic;
}

.quote-line[data-kind="subtotal"] {
    background: var(--tblr-bg-surface-tertiary, var(--tblr-bg-surface-secondary));
}

/*
 * Repli en dessous de la tablette seulement. Au-dessus, la grille tient : c'est
 * précisément ce qu'on veut, la saisie en ligne étant la raison d'être de cet écran.
 */
@media (max-width: 767.98px) {
    .quote-lines-header {
        display: none;
    }

    .quote-line {
        grid-template-columns: 1.25rem minmax(0, 1fr);
    }

    .quote-line > :not(.quote-line-handle):not(.quote-line-label) {
        grid-column: 2;
    }

    .quote-line-actions {
        justify-content: start;
    }
}

/* Le récapitulatif suit le défilement : sur un devis long, les totaux restent
   sous les yeux pendant la saisie. */
@media (min-width: 992px) {
    .quote-summary {
        position: sticky;
        top: 1rem;
    }
}

/*
 * Corps d'un mail relevé.
 *
 * Le texte est stocké brut, sauts de ligne compris : sans `pre-wrap` il
 * s'afficherait en un seul bloc. Tabler n'a pas d'utilitaire pour ça. La
 * césure forcée évite qu'une URL ou une signature encodée ne fasse déborder
 * la carte horizontalement.
 */
.mail-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/*
 * Mise en page d'un corps de mail conservé en texte brut.
 *
 * Le HTML posé ici est le seul du rendu, et c'est MailBodyFormatter qui l'écrit
 * après avoir échappé le texte reçu. Ce qui suit ne fait que l'habiller : une
 * signature d'entreprise aplatie tient sur trois lignes discrètes au lieu
 * d'occuper la moitié de l'écran, et le message précédent se replie.
 */
.mail-body .mail-rule {
    margin: 1rem 0;
    opacity: .35;
}

/* Les pastilles d'une signature : cinq liens de suivi sur une seule ligne. */
.mail-body .mail-links {
    display: inline-flex;
    flex-wrap: wrap;
    gap: .25rem;
}

.mail-body .mail-link {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .05rem .4rem;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    font-size: .75rem;
    color: var(--tblr-secondary);
    text-decoration: none;
    white-space: nowrap;
}

.mail-body .mail-link:hover {
    color: var(--tblr-primary);
    border-color: var(--tblr-primary);
}

/*
 * La signature reste lisible, mais cesse de concurrencer le message : c'est
 * exactement ce qu'un client de messagerie en fait.
 */
.mail-body .mail-signature {
    margin-top: 1rem;
    padding-top: .75rem;
    border-top: 1px solid var(--tblr-border-color);
    color: var(--tblr-secondary);
    font-size: .8125rem;
}

/*
 * Le message précédent est REPLIÉ, jamais retiré : sur un écran de messagerie,
 * ce qu'un correspondant a écrit doit rester atteignable d'un clic.
 */
.mail-body .mail-quote {
    margin-top: 1rem;
    color: var(--tblr-secondary);
}

.mail-body .mail-quote > summary {
    cursor: pointer;
    color: var(--tblr-primary);
    font-size: .8125rem;
    list-style: none;
}

.mail-body .mail-quote > summary::before {
    content: "\ea5f"; /* ti-chevron-right */
    font-family: "tabler-icons", sans-serif;
    margin-right: .25rem;
    display: inline-block;
}

.mail-body .mail-quote[open] > summary::before {
    transform: rotate(90deg);
}

.mail-body .mail-quote > div {
    margin-top: .5rem;
    padding-left: .75rem;
    border-left: 2px solid var(--tblr-border-color);
    font-size: .8125rem;
}

/*
 * Texte brut affiché tel qu'il a été saisi ou reçu.
 *
 * Notes de réunion, transcription : ce sont des textes que rien n'a mis en
 * forme, dont les sauts de ligne sont l'unique structure. Sans `pre-wrap` ils
 * s'affichent en un pavé. Tabler n'a pas d'utilitaire équivalent — `text-wrap`
 * ne touche que `white-space: normal`.
 */
.text-prewrap {
    white-space: pre-wrap;
}

/*
 * Éditeur de texte enrichi (Trix) dans le tableau de saisie.
 *
 * ATTENTION à la spécificité. La feuille de Trix est chargée par l'importmap
 * APRÈS celle-ci : à spécificité égale, c'est la sienne qui gagne. D'où la
 * classe `.app-trix-toolbar`, posée sur la barre d'outils par le contrôleur
 * Stimulus — elle donne le poids qu'il faut sans recourir à `!important`.
 */
trix-editor.app-trix-editor {
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-forms, var(--tblr-body-bg));
    color: var(--tblr-body-color);
    min-height: 6rem;
    padding: 0.4375rem 0.75rem;
    font-size: 0.8125rem;
}

trix-editor.app-trix-editor:focus {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--tblr-primary-rgb), 0.25);
    outline: 0;
}

/*
 * La barre doit tenir dans la colonne. Trix la règle en `flex-wrap: nowrap` avec
 * `overflow-x: auto` : dans une cellule étroite, les derniers boutons — annuler
 * et rétablir — se retrouvaient hors du cadre visible. Elle passe à la ligne.
 */
.app-trix-toolbar .trix-button-row {
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 0.25rem;
    overflow-x: visible;
}

/* Les marges de Trix sont calées en `vw` : sans rapport avec la largeur réelle
   de la colonne, elles creusaient des écarts inutiles. */
.app-trix-toolbar .trix-button-group {
    margin-bottom: 0.375rem;
    border-color: var(--tblr-border-color);
}

.app-trix-toolbar .trix-button-group:not(:first-child) {
    margin-left: 0;
}

.app-trix-toolbar .trix-button {
    border-bottom: 0;
}

/* Largeur fixe : le calcul en `vw` de Trix étire les boutons sans raison. */
.app-trix-toolbar .trix-button--icon {
    width: 2rem;
    max-width: 2rem;
    height: 1.75rem;
}

/*
 * Le souligné n'étant pas un attribut natif de Trix, sa feuille ne fournit
 * aucune icône : le bouton sortait vide. Le glyphe vient du webfont Tabler,
 * comme partout ailleurs dans l'application.
 */
.app-trix-toolbar .trix-button--icon-underline::before {
    content: "\eba2"; /* ti-underline */
    font-family: "tabler-icons", sans-serif;
    font-size: 0.875rem;
    /* Le bouton masque son libellé par un `text-indent: -9999px` qui s'hérite :
       sans cette remise à zéro, le glyphe partirait hors de l'écran. */
    text-indent: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Le contenu enrichi, à l'affichage comme dans l'éditeur. */
.trix-content ul,
.trix-content ol {
    margin: 0.25rem 0;
    padding-left: 1.25rem;
}

.trix-content p:last-child,
.trix-content div:last-child {
    margin-bottom: 0;
}

/*
 * Visionneuse publique d'un devis.
 *
 * Ces règles n'ont pas d'équivalent Tabler : il s'agit de mettre en page un
 * document paginé rendu dans des <canvas>, ce que la bibliothèque ne couvre
 * pas. Tout le reste de l'écran — barre d'outils, boutons, alertes — reste du
 * Tabler standard.
 */
.quote-viewer {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    background: var(--tblr-bg-surface-secondary);
}

.quote-viewer-scroll {
    flex: 1;
    overflow-y: auto;
    overflow-x: auto;
    padding: 1.5rem 1rem 4rem;
    /* Le défilement doit rester fluide au doigt sur mobile, où la visionneuse
       occupe tout l'écran. */
    -webkit-overflow-scrolling: touch;
}

.quote-viewer-pages {
    /* Pilotée par le contrôleur Stimulus au zoom. La largeur de base est celle
       d'une A4 lisible sur un écran d'ordinateur portable ; le zoom la multiplie.
       Le `min()` est DANS le produit : sans lui, le zoom 1 déborderait déjà sur
       un téléphone, et au-delà de 1 le débordement horizontal est justement ce
       qu'on veut — le conteneur défile. */
    --quote-viewer-zoom: 1;
    width: calc(min(100%, 52rem) * var(--quote-viewer-zoom));
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/*
 * Chaque page réserve sa place AVANT d'être rendue, grâce à `aspect-ratio`
 * posé en ligne par le contrôleur. Sans cette réservation la barre de
 * défilement grandirait au fil des rendus et la lecture sauterait.
 */
.quote-viewer-page {
    background: #fff;
    box-shadow: var(--tblr-box-shadow-card);
    border-radius: var(--tblr-border-radius);
    overflow: hidden;
}

.quote-viewer-page canvas {
    display: block;
    width: 100%;
    height: auto;
}

/* À l'impression, seul le document sort : ni barre d'outils ni bandeau. */
@media print {
    .quote-viewer-toolbar,
    .quote-viewer-footer {
        display: none !important;
    }

    .quote-viewer,
    .quote-viewer-scroll {
        height: auto;
        overflow: visible;
        padding: 0;
        background: #fff;
    }

    .quote-viewer-page {
        box-shadow: none;
        border-radius: 0;
        break-after: page;
    }
}

/*
 * Suivi de lecture : histogramme du temps passé page par page.
 *
 * Une barre de progression Tabler par page aurait fait l'affaire à
 * l'horizontale, mais on veut lire d'un coup d'œil quelle page a retenu le
 * client — d'où des colonnes côte à côte, comparables entre elles.
 */
.quote-dwell {
    display: flex;
    align-items: flex-end;
    gap: 0.25rem;
    height: 7rem;
}

.quote-dwell-bar {
    flex: 1;
    min-width: 0.75rem;
    background: var(--tblr-primary);
    border-radius: var(--tblr-border-radius) var(--tblr-border-radius) 0 0;
    /* Une page vue une seconde doit rester visible, sinon la colonne disparaît
       et on croit la page jamais atteinte. */
    min-height: 0.25rem;
    opacity: 0.85;
}

.quote-dwell-bar:hover {
    opacity: 1;
}

/*
 * Panneau « à programmer » du calendrier.
 *
 * Les tâches se glissent de ce panneau sur le calendrier pour être
 * programmées. Chaque ligne est une cible de préhension : d'où la poignée
 * visible et le curseur, seuls indices qu'un élément se saisit — rien dans
 * Tabler ne le signale.
 */
.planning-backlog {
    /* La liste ne doit pas repousser le panneau de détail hors de l'écran :
       elle défile dans sa carte plutôt que d'étirer la colonne. */
    max-height: 24rem;
    overflow-y: auto;
}

.planning-backlog-item {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.5rem;
    margin-bottom: 0.375rem;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    background: var(--tblr-bg-surface);
    cursor: grab;
}

.planning-backlog-item:last-child {
    margin-bottom: 0;
}

.planning-backlog-item:hover {
    border-color: var(--tblr-primary);
}

.planning-backlog-item:active {
    cursor: grabbing;
}

/*
 * Une cellule flex vaut `min-width: auto` : sans cette remise à zéro, un
 * intitulé long refuse de se tronquer et déborde de la colonne.
 */
.planning-backlog-body {
    flex: 1 1 auto;
    min-width: 0;
}

.planning-backlog-handle {
    color: var(--tblr-secondary);
    padding-top: 0.125rem;
}

/*
 * Le fantôme promené par FullCalendar pendant le glissé : sans transparence,
 * il masque le créneau sous lequel on vise.
 */
.fc-event-dragging {
    opacity: 0.75;
}

/*
 * Créneau déjà pointé. La couleur de fond est celle du poste, posée en ligne
 * par le contrôleur : la distinction passe donc par le contour, seul canal
 * encore libre.
 */
.fc-event-tracked {
    box-shadow: inset 0 0 0 2px var(--tblr-body-bg);
    opacity: 0.75;
}

/*
 * Lecteur de rejeu d'une visite.
 *
 * L'iframe est rendue aux dimensions de la fenêtre du client puis réduite par
 * `transform: scale()`. Le curseur vit DANS le même repère : il suit donc
 * l'échelle sans qu'on ait à convertir ses coordonnées.
 */
.quote-replay-stage {
    position: relative;
    overflow: hidden;
    background: var(--tblr-bg-surface-secondary);
    border-radius: var(--tblr-border-radius);
}

.quote-replay-scaler {
    position: relative;
    transform-origin: top left;
}

.quote-replay-scaler iframe {
    display: block;
    border: 0;
    /* Le rejeu se regarde, il ne se manipule pas : un clic dans l'iframe
       ferait défiler la visionneuse et désynchroniserait tout le reste. */
    pointer-events: none;
}

/*
 * Le curseur est un dessin, pas un pointeur : aucune API ne permet de déplacer
 * le vrai. `translate` plutôt que `top`/`left` pour rester sur le compositeur —
 * il bouge jusqu'à vingt fois par seconde.
 */
.quote-replay-cursor {
    position: absolute;
    top: 0;
    left: 0;
    width: 14px;
    height: 14px;
    margin: -7px 0 0 -7px;
    border-radius: 50%;
    background: var(--tblr-primary);
    box-shadow: 0 0 0 2px #fff, 0 1px 4px rgb(0 0 0 / 40%);
    pointer-events: none;
    transition: transform 60ms linear;
}

/* Onde au clic. L'animation est portée par un pseudo-élément pour ne pas
   entrer en conflit avec le `transform` qui positionne le curseur. */
.quote-replay-cursor::after {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 2px solid var(--tblr-primary);
    opacity: 0;
}

.quote-replay-cursor.quote-replay-clicked::after {
    animation: quote-replay-ripple 500ms ease-out;
}

@keyframes quote-replay-ripple {
    from { transform: scale(1); opacity: 0.9; }
    to { transform: scale(3.5); opacity: 0; }
}

/* Onglet passé en arrière-plan : la scène s'éteint, comme pour le lecteur. */
.quote-replay-stage.quote-replay-away::after {
    content: "Onglet en arrière-plan";
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgb(0 0 0 / 55%);
    color: #fff;
    font-size: 0.875rem;
}

.quote-replay-loading {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Barre de lecture : les repères se posent SOUS le curseur natif du range. */
.quote-replay-track {
    position: relative;
}

.quote-replay-marks {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 4px;
    margin-top: -2px;
    pointer-events: none;
}

.quote-replay-mark {
    position: absolute;
    top: -3px;
    width: 2px;
    height: 10px;
    background: var(--tblr-primary);
    opacity: 0.65;
}

/* Intervalle non enregistré : montré, jamais comblé. */
.quote-replay-gap {
    position: absolute;
    top: 0;
    height: 4px;
    background: repeating-linear-gradient(
        45deg,
        var(--tblr-border-color) 0 4px,
        transparent 4px 8px
    );
}

/*
 * Une surface qui s'annonce comme cible de dépôt.
 *
 * Deux usages, un seul signal, délibérément : le panneau « à programmer » du
 * planning pendant qu'on y ramène un créneau, et la colonne du tableau personnel
 * pendant qu'on y fait glisser une carte. Même geste, même signal — écrire une
 * seconde ombre pour le second ferait diverger deux apparences qui disent la
 * même chose.
 *
 * Rien dans une grille de calendrier ni dans une colonne de kanban ne laisse
 * deviner qu'un dépôt fera autre chose qu'annuler le geste.
 */
.planning-backlog-target,
.mytask-drop.is-over {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--tblr-primary-rgb), 0.15);
}

/*
 * Les colonnes du tableau personnel.
 *
 * La grille de Tabler pose les colonnes ; il lui manque deux choses qu'aucune de
 * ses classes ne donne. Une colonne vide n'a aucune hauteur, donc aucune surface
 * où lâcher une carte — d'où le plancher. Et une colonne de trente cartes
 * étirerait la page jusqu'à pousser les quatre autres hors de vue : elle défile
 * dans sa carte, comme le panneau « à programmer ».
 */
.mytask-column {
    min-height: 5rem;
    max-height: calc(100vh - 22rem);
    overflow-y: auto;
}

/*
 * Sur écran étroit, les colonnes s'empilent : cinq boîtes à défilement imbriquées
 * dans une page qui défile déjà rendraient le tableau impraticable. Le
 * glissé-déposé HTML5 ne reçoit de toute façon aucun évènement au doigt — sur
 * téléphone, le tableau se pilote par le menu de chaque carte.
 */
@media (max-width: 47.98em) {
    .mytask-column {
        max-height: none;
        overflow-y: visible;
    }

    /* Trois colonnes restantes (rond, tâche, menu) : le plancher de 12 rem
       forçait un défilement latéral qui sortait le menu ⋮ — la seule commande
       au doigt — de l'écran. */
    .mytask-list-title {
        min-width: 0;
    }

    /* Les raccourcis tiennent sur UNE ligne qui défile au doigt : repliés, ils
       coûtaient deux rangées avant la première tâche. */
    .mytask-shortcuts {
        flex-wrap: nowrap;
        overflow-x: auto;
        padding-bottom: 0.25rem;
    }

    .mytask-shortcuts .btn {
        flex-shrink: 0;
    }
}

/*
 * Au doigt, trois ajustements que Tabler ne fait pas. Les boutons-icônes
 * remontent à 44 px — le ⋮ et le rond « Terminer » sont LES commandes d'une
 * carte au doigt, et 28 px font clore une tâche en visant son menu. Les champs
 * passent à 16 px : en dessous, Safari iOS zoome la page à chaque focus et ne
 * la rend pas. La poignée de glisser disparaît : le glissé-déposé HTML5 ne
 * reçoit aucun évènement tactile, elle n'était qu'un leurre qui concurrençait
 * le menu.
 */
@media (pointer: coarse) {
    .mytask-screen .btn-icon.btn-sm {
        min-width: 2.75rem;
        min-height: 2.75rem;
    }

    .mytask-screen .form-control,
    .mytask-screen .form-select {
        font-size: 1rem;
    }

    .mytask-screen .mytask-handle {
        display: none;
    }
}

/*
 * Seule la poignée se saisit (elle seule est `draggable`) : c'est elle qui porte
 * le curseur. Sur toute la carte, il promettrait un geste que le reste de la
 * carte ne fait pas.
 */
.mytask-handle:active {
    cursor: grabbing;
}

/*
 * La poignée est le SEUL endroit d'où l'on peut saisir une carte (voir
 * #onDragStart) : elle doit se voir comme une commande, pas comme une décoration.
 * D'où une surface cliquable réelle, qui s'allume au survol — sans cela, rien ne
 * distingue « glisser ici » de « cliquer sur l'intitulé pour modifier ».
 */
.mytask-handle {
    cursor: grab;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    margin: -0.25rem 0 0 -0.25rem;
    border-radius: var(--tblr-border-radius);
    transition: background-color 0.15s;
}

.mytask-card:hover .mytask-handle {
    background: var(--tblr-bg-surface-secondary);
    color: var(--tblr-body-color);
}

/*
 * L'intitulé d'une carte du kanban : trois lignes au plus. Un intitulé de mail
 * repris par le récap fait volontiers deux phrases, et une carte qui s'allonge
 * pousse les autres hors de vue. Le texte entier est dans le panneau.
 */
.mytask-card-title {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/*
 * La vue liste. L'intitulé prend toute la place restante et se tronque — une
 * cellule de tableau ne se tronque qu'à largeur nulle déclarée, d'où le
 * `max-width: 0`. Le projet est borné pour ne pas pousser l'échéance hors de
 * l'écran — la pastille et deux lignes, client puis projet, tiennent dans 15rem.
 * Les lignes de groupe (« En retard », « Aujourd'hui »…) reprennent le
 * fond des en-têtes de Tabler.
 */
.mytask-list-title {
    width: 100%;
    max-width: 0;
    min-width: 12rem;
}

.mytask-list-project {
    width: 15rem;
    max-width: 15rem;
}

.mytask-list .mytask-group > th {
    background: var(--tblr-bg-surface-tertiary);
    font-size: var(--tblr-font-size-h5);
    text-transform: none;
    letter-spacing: normal;
}

.mytask-time {
    min-width: 6.5rem;
}

/*
 * Le rond qui termine une tâche : un cercle vide, qui se coche au survol. Le
 * webfont n'a pas d'état « survolé » ; on emprunte le glyphe de `ti-circle-check`
 * plutôt que de poser deux icônes et d'en masquer une.
 */
.mytask-check:hover .ti-circle::before,
.mytask-check:focus-visible .ti-circle::before {
    content: "\ea67";
}

/*
 * Les listes déroulantes de la barre de /mes-taches. Tom Select remplace le
 * <select> par une enveloppe à 100 % de son parent : sans largeur posée sur la
 * colonne, `col-sm-auto` s'étale et chaque filtre passe à la ligne.
 */
@media (min-width: 36em) {
    .mytask-filter {
        width: 12rem;
    }
}

/* Le panneau latéral porte un formulaire entier : la largeur par défaut
   (400 px) serre les champs côte à côte. Bornée à l'écran : à 34rem fixes, un
   téléphone de 390 px laissait 150 px de formulaire hors champ, inatteignables
   — le panneau est en position fixe, rien ne défile de côté. */
.mytask-panel {
    --tblr-offcanvas-width: min(34rem, 100vw);
}

/*
 * La teinte de chaque colonne du kanban, et du pense-bête. Pas `.bg-*-lt` : ces
 * utilitaires colorent aussi le TEXTE, et chaque carte de la colonne virerait à
 * l'azur. Les variables `--tblr-*-lt` ont leur pendant sombre dans Tabler, les
 * deux thèmes se tiennent donc sans rien ajouter.
 */
.mytask-lane {
    --tblr-card-bg: var(--tblr-bg-surface-secondary);
}

.mytask-lane-in_progress { --tblr-card-bg: var(--tblr-azure-lt); }
.mytask-lane-blocked { --tblr-card-bg: var(--tblr-orange-lt); }
.mytask-lane-done { --tblr-card-bg: var(--tblr-green-lt); }
.mytask-notes { --tblr-card-bg: var(--tblr-pink-lt); }

/* Les cartes et les lignes posées dans une colonne teintée restent blanches. */
.mytask-lane .mytask-card {
    --tblr-card-bg: var(--tblr-bg-surface);
}

/* Les colonnes closes, dans la marge du kanban : une liste courte, qui défile
   plutôt que de pousser le pense-bête sous la ligne de flottaison. */
.mytask-column-closed {
    min-height: 3rem;
    max-height: 16rem;
}

/* Les icônes d'information d'une carte : sobres, alignées sur leur chiffre. */
.mytask-meta > * {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    line-height: 1;
}

/*
 * Zone de dépôt de l'espace client.
 *
 * Tabler n'a pas de composant de glissé-déposé : il offre bien un
 * `<input type="file">` habillé, mais rien qui présente une cible de dépôt. Ces
 * quelques lignes s'en tiennent aux variables du thème, et le survol reprend
 * l'ombre portée déjà employée par le panneau du planning — même geste, même
 * signal.
 */
.space-dropzone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2.5rem 1rem;
    text-align: center;
    cursor: pointer;
    color: var(--tblr-secondary);
    border: 2px dashed var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    transition: border-color 0.15s, background-color 0.15s;
}

.space-dropzone:hover,
.space-dropzone.is-over {
    border-color: var(--tblr-primary);
    background-color: rgba(var(--tblr-primary-rgb), 0.04);
}

.space-dropzone .ti {
    font-size: 2rem;
    color: var(--tblr-primary);
}

/*
 * Glissé-déposé dans l'espace client.
 *
 * Deux états, et rien de plus : ce qu'on traîne s'efface, ce qui l'accepte
 * s'éclaire. Le trait de la cible reprend l'ombre portée déjà employée par le
 * panneau du planning — même geste, même signal.
 */
.space-dragging {
    opacity: 0.4;
}

.space-drop-over > td,
li.space-drop-over {
    background-color: rgba(var(--tblr-primary-rgb), 0.08);
    box-shadow: inset 0 0 0 2px var(--tblr-primary);
}

/* Une ligne déplaçable annonce qu'elle l'est, sans attendre qu'on essaie. */
tr[draggable="true"] {
    cursor: grab;
}

/*
 * Assistant de projet et de client.
 *
 * Tabler fournit les bulles (`.chat-bubble`, `.chat-bubble-me`) mais pas le fil
 * qui les contient : un conteneur de conversation n'existe pas dans la
 * bibliothèque. On n'ajoute donc que ce qui manque — la hauteur du fil, et
 * l'alignement des deux voix.
 */

/*
 * Le fil défile pour lui-même, plutôt que d'allonger la page.
 *
 * C'est le champ de saisie qu'il s'agit de garder sous les yeux : une
 * conversation de dix échanges pousserait sinon le formulaire hors de l'écran,
 * et poser la question suivante demanderait de remonter.
 */
.assistant-thread {
    max-height: 60vh;
    overflow-y: auto;
}

/*
 * Une bulle ne prend pas toute la largeur : c'est ce décalage, et lui seul, qui
 * distingue la question de la réponse au premier coup d'œil. La couleur ne
 * suffirait pas — `.chat-bubble-me` est une teinte claire, invisible en
 * diagonale sur un écran de portable.
 */
.assistant-bubble {
    max-width: 85%;
}

.assistant-bubble-me {
    align-self: flex-end;
}

/* Les documents cités appartiennent à la réponse qui précède, pas au fil. */
.assistant-sources {
    max-width: 85%;
    margin-top: -0.5rem;
}

/*
 * Le Markdown d'une réponse : le dernier paragraphe d'une bulle ne doit pas
 * porter la marge de fin qui, dans un document, sépare deux blocs.
 */
.assistant-bubble .markdown > :last-child {
    margin-bottom: 0;
}

/* ==========================================================================
   Logo d'entreprise
   ========================================================================== */

/*
 * Tabler pose l'image d'un avatar en `background: … center/cover` : un logo
 * carré y survit, un logotype horizontal y perd ses extrémités, et c'est
 * justement ce qui rend une marque reconnaissable. D'où une vraie balise
 * `<img>` — que `object-fit: contain` inscrit ENTIÈRE dans la pastille.
 *
 * Le fond doit être reposé : `theme.css` donne à `.avatar` un dégradé corail,
 * fait pour détacher des initiales blanches. Il transparaîtrait sous les
 * parties translucides d'un PNG, et un logo sombre y deviendrait illisible.
 */
.company-logo {
    padding: 0.125rem;
    background-image: none;
    background-color: var(--tblr-bg-surface);
    object-fit: contain;
}

/* ==========================================================================
   Aperçu de la signature de mail
   ========================================================================== */

/*
 * La signature est du HTML de mail : tableaux, images, styles en ligne. On la
 * montre telle qu'elle partira, dans une boîte qui la contient — une image de
 * 600 px de large ne doit pas déborder de la colonne de droite du composeur.
 */
.mail-signature-preview,
.mail-autoreply-preview {
    overflow-x: auto;
    font-size: 0.875rem;
}

.mail-signature-preview img {
    max-width: 100%;
    height: auto;
}

/* ==========================================================================
   Messagerie : le client mail à trois volets
   ========================================================================== */

/*
 * Dossiers, liste, lecture — trois colonnes qui remplissent la hauteur de la
 * fenêtre, chacune défilant pour elle-même. C'est ce qui distingue un client
 * mail d'une page : on ne fait pas défiler la page, on fait défiler la liste
 * ou le message. Sous la largeur `lg`, les colonnes se superposent et le
 * gabarit n'en montre qu'une (`d-none d-lg-…`) : la hauteur est alors libre.
 */
@media (min-width: 992px) {
    .mail-client {
        height: calc(100vh - 3rem);
        overflow: hidden;
    }

    .mail-client > .row {
        height: 100%;
    }

    .mail-client-nav,
    .mail-client-list,
    .mail-client-reading {
        height: 100%;
        overflow-y: auto;
    }
}

/*
 * La ligne d'un mail : deux lignes de texte et une rangée de pastilles. La
 * ligne ouverte est marquée par un filet à gauche dans la teinte de la brique
 * plutôt que par le fond plein de `.active`, qui rendrait les pastilles
 * illisibles.
 */
.mail-row {
    border-left: 3px solid transparent;
}

/*
 * `min-w-0` n'existe pas dans Tabler. Sans lui, un enfant flex garde la
 * largeur de son contenu, `text-truncate` n'a rien à tronquer, et un objet
 * long fait défiler toute la colonne horizontalement — vu sur la liste dès
 * le premier vrai mail.
 */
.mail-client .min-w-0 {
    min-width: 0;
}

.mail-client-list,
.mail-client-reading {
    overflow-x: hidden;
}

.mail-row.active {
    background-color: var(--tblr-active-bg, var(--tblr-bg-surface-secondary));
    border-left-color: var(--tblr-primary);
    color: inherit;
}

.mail-row-badges:empty {
    display: none;
}

/* Non lu : l'expéditeur et l'objet en gras, comme partout ailleurs. */
.mail-row-unread .fw-medium,
.mail-row-unread .stretched-link {
    font-weight: 700;
}

/* Le bouton « écarter » d'une ligne passe au-dessus du lien qui la couvre. */
.mail-row-action {
    position: relative;
    z-index: 2;
}

/* La case d'une ligne : alignée sur l'avatar, sans marge de formulaire. */
.mail-row-check {
    padding-left: 0;
    margin-top: 0.35rem;
}

.mail-row-check .form-check-input {
    margin-left: 0;
}

/* Les panneaux de rattachement : repliés par défaut sur un mail déjà classé. */
.mail-attach > summary {
    cursor: pointer;
    list-style: none;
}

.mail-attach > summary::-webkit-details-marker {
    display: none;
}

.mail-attach > summary::before {
    content: '▸';
    display: inline-block;
    width: 1rem;
    color: var(--tblr-secondary);
}

.mail-attach[open] > summary::before {
    content: '▾';
}

/*
 * Le composeur, façon client mail : « À », « Cc », « Objet » sur une ligne
 * chacun, l'étiquette courte à gauche, le champ sans bordure à sa suite —
 * la mise en page de Gmail, d'Apple Mail, d'Outlook. Les champs Tabler
 * ordinaires, avec leur cadre et leur étiquette au-dessus, feraient un
 * formulaire administratif, pas un mail.
 */
.mail-compose-row {
    display: flex;
    align-items: center;
    padding: 0 1rem;
    border-bottom: 1px solid var(--tblr-border-color-translucent);
}

.mail-compose-row:last-of-type {
    border-bottom: 0;
}

.mail-compose-label {
    flex: 0 0 3.5rem;
    margin: 0;
    color: var(--tblr-secondary);
    font-size: 0.875rem;
}

.mail-compose-row .form-control-flush {
    flex: 1 1 auto;
    padding-left: 0;
    padding-right: 0;
}

.mail-compose .invalid-feedback {
    display: block;
    padding: 0 1rem 0.5rem;
}

/* La signature à venir, en gris sous l'éditeur : on la voit, on ne la retape pas. */
.mail-compose-signature {
    opacity: 0.6;
}

.mail-compose trix-editor.app-trix-editor {
    min-height: 12rem;
}

/*
 * Le calendrier des absences (/absences).
 *
 * Une grille de mois rendue en Twig — pas de FullCalendar ici, réservé au
 * planning. Chaque absence est une pastille teintée par sa nature ; la teinte
 * est passée par une variable CSS posée sur la pastille (`--chip`), qui pointe
 * une couleur Tabler, si bien que le thème sombre suit sans rien redire.
 */
.absence-calendar {
    table-layout: fixed;
}

.absence-calendar th {
    background: var(--tblr-bg-surface-secondary);
    font-weight: 600;
}

.absence-day {
    height: 6.5rem;
    padding: 0.35rem 0.4rem;
    vertical-align: top;
}

.absence-day-weekend {
    background: var(--tblr-bg-surface-secondary);
}

.absence-day-outside .absence-day-number {
    opacity: 0.35;
}

/* Le jour courant : un liseré dans la teinte de la brique, pas un fond, pour
   que les pastilles gardent leur contraste. */
.absence-day-today {
    box-shadow: inset 0 0 0 2px var(--tblr-cyan);
}

.absence-day-number {
    display: inline-block;
    min-width: 1.5rem;
    margin-bottom: 0.25rem;
    color: var(--tblr-body-color);
    font-weight: 600;
    text-decoration: none;
}

.absence-day-number:hover {
    color: var(--tblr-primary);
}

.absence-day-chips {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.absence-chip {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 1px 0.35rem 1px 2px;
    border: 1px solid transparent;
    border-radius: var(--tblr-border-radius);
    background: color-mix(in oklab, var(--chip, var(--tblr-primary)) 18%, var(--tblr-bg-surface));
    color: color-mix(in oklab, var(--chip, var(--tblr-primary)) 70%, var(--tblr-body-color));
    font-size: 0.75rem;
    line-height: 1.25rem;
    text-decoration: none;
    overflow: hidden;
    white-space: nowrap;
}

.absence-chip:hover {
    background: color-mix(in oklab, var(--chip, var(--tblr-primary)) 30%, var(--tblr-bg-surface));
    color: inherit;
}

/* Une absence seulement demandée : le même ton, en pointillé. */
.absence-chip-requested,
.absence-legend-requested {
    border-style: dashed;
    border-color: color-mix(in oklab, var(--chip, var(--tblr-secondary)) 60%, transparent);
    background: transparent;
}

.absence-chip-avatar {
    flex: 0 0 auto;
    background: color-mix(in oklab, var(--chip, var(--tblr-primary)) 35%, var(--tblr-bg-surface));
    color: inherit;
    font-size: 0.6rem;
}

.absence-chip-name {
    overflow: hidden;
    text-overflow: ellipsis;
}

.absence-chip-half {
    margin-left: auto;
    opacity: 0.7;
    font-size: 0.65rem;
}

/* Sur téléphone, la grille se lit à sept colonnes serrées : seule l'initiale
   tient. Le nom reste dans le titre de la pastille. */
@media (max-width: 767.98px) {
    .absence-day {
        height: 4.5rem;
        padding: 0.2rem;
    }

    .absence-chip-name,
    .absence-chip-half {
        display: none;
    }

    .absence-chip {
        padding: 1px 2px;
    }
}

/* ==========================================================================
   Téléphone
   ==========================================================================
   Le widget flottant de `_partials/phone.html.twig`. Tabler n'a pas de
   composant « bouton flottant + panneau » : seule la position est à nous, le
   panneau est une `.card` ordinaire, le clavier une grille de `.btn`. */
.phone-widget {
    position: fixed;
    right: 1rem;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    z-index: 1035; /* sous les modales (1055), au-dessus du contenu */
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

.phone-widget-toggle {
    position: relative;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    font-size: 1.375rem;
    box-shadow: var(--tblr-box-shadow);
}

.phone-widget-dot {
    position: absolute;
    top: 0.25rem;
    right: 0.25rem;
    box-shadow: 0 0 0 2px var(--tblr-bg-surface);
}

/* Un appel entrant se voit même widget replié : le bouton tremble. */
.phone-widget-toggle.is-ringing {
    animation: phone-ring 0.9s ease-in-out infinite;
}

@keyframes phone-ring {
    0%, 100% { transform: rotate(0); }
    20% { transform: rotate(-12deg); }
    40% { transform: rotate(10deg); }
    60% { transform: rotate(-8deg); }
    80% { transform: rotate(6deg); }
}

.phone-widget-panel {
    width: min(20rem, calc(100vw - 2rem));
    /* Jamais plus haut que l'écran : le bouton « Réduire » est dans l'en-tête,
       et un panneau qui déborde par le haut le rend inatteignable. Le corps
       défile, l'en-tête reste en vue. */
    max-height: calc(100vh - 6.5rem - env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
}

.phone-widget-panel > .card-body {
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.phone-keypad {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.375rem;
}

.phone-keypad .btn {
    font-size: 1.125rem;
    font-variant-numeric: tabular-nums;
}

/* Collègues et récents défilent chacun dans leur cadre : le clavier et le
   bouton « Appeler » restent en place quelle que soit la longueur des listes. */
.phone-colleagues {
    max-height: 11rem;
    overflow-y: auto;
}

/*
 * Un collègue dont le poste n'est pas enregistré : sa ligne s'efface, et le
 * contrôleur `phone` la range sous les autres. L'effacement porte sur la LIGNE
 * ENTIÈRE — pastille, avatar, nom, numéro de poste, bouton d'appel —, ce
 * qu'aucun utilitaire Tabler ne fait d'un seul mot : `text-secondary`
 * n'atteindrait ni l'avatar ni le badge, qui portent leurs propres couleurs.
 *
 * Effacé, jamais désactivé : le plan de sonnerie peut faire sonner le mobile
 * personnel d'un collègue hors ligne, et le transfert annoncé sait attendre
 * qu'il se connecte. La ligne reste donc cliquable ; elle dit seulement qu'il
 * n'y a personne devant l'écran.
 *
 * L'opacité se relève au survol : on lit la ligne qu'on vise, sans avoir à
 * renoncer à l'effacement du reste.
 */
.phone-colleague-offline {
    opacity: 0.45;
}

.phone-colleague-offline:hover,
.phone-colleague-offline:focus-within {
    opacity: 0.75;
}

@media print {
    .phone-widget {
        display: none;
    }
}

/* ==========================================================================
   Recrutement — l'espace candidats
   ==========================================================================
   La page carrières publique a sa propre feuille, assets/styles/careers.css,
   chargée par son seul gabarit : elle n'a rien à faire ici. */

/* Côté agence : l'avatar d'un candidat prend la teinte de son métier. */
.candidate-avatar {
    background-color: color-mix(in srgb, var(--tone, var(--tblr-primary)) 16%, transparent);
    color: color-mix(in oklab, var(--tone, var(--tblr-primary)) 72%, var(--app-tone-ink-base));
    font-weight: 600;
}

/* ==========================================================================
   Tom Select — les listes déroulantes
   ==========================================================================
   Tom Select remplace l'affichage de chaque <select> (contrôleur `tom-select`).
   Sa feuille Bootstrap 5 lit les variables --bs-*, que Tabler nomme --tblr-* :
   sans ce relais, la liste resterait blanche en thème sombre. On lui passe
   donc celles de Tabler, et le reste se règle par elles.

   Le <select> d'origine garde `.form-select`, recopié sur l'enveloppe
   `.ts-wrapper` : c'est elle qui porte la bordure, le fond et le chevron de
   Tabler. Le `.ts-control` intérieur ne reprend que les marges du texte. */
.ts-wrapper,
.ts-dropdown {
    --bs-body-bg: var(--tblr-bg-forms);
    --bs-body-color: var(--tblr-body-color);
    --bs-border-color: var(--tblr-border-color);
    --bs-border-color-translucent: var(--tblr-border-color-translucent);
    --bs-border-radius: var(--tblr-border-radius);
    --bs-border-radius-sm: var(--tblr-border-radius-sm);
    --bs-border-radius-lg: var(--tblr-border-radius-lg);
    --bs-border-width: var(--tblr-border-width);
    --bs-secondary-bg: var(--tblr-bg-surface-secondary);
    --bs-secondary-color: var(--tblr-secondary);
    --bs-tertiary-bg: rgba(var(--tblr-primary-rgb), 0.08);
    --bs-form-invalid-color: var(--tblr-form-invalid-color);
    --bs-form-valid-color: var(--tblr-form-valid-color);
}

.ts-wrapper.form-select .ts-control {
    padding: 0.5625rem 3rem 0.5625rem 1rem;
    line-height: 1.25rem;
}

.ts-wrapper.form-select-sm .ts-control {
    padding: 0.3125rem 2.25rem 0.3125rem 0.5rem;
    font-size: 0.75rem;
}

/* Un choix multiple n'a pas de chevron, comme le <select multiple> de Tabler. */
.ts-wrapper.form-select.multi {
    background-image: none;
}

.ts-wrapper.form-select.multi .ts-control {
    padding-right: 1rem;
}

.ts-wrapper.disabled {
    background-color: var(--tblr-bg-surface-secondary);
}

/* Le halo de focus de theme.css, posé sur l'enveloppe qui porte la bordure —
   et non le bleu de Bootstrap sur le contrôle intérieur. */
.ts-wrapper.form-select.focus {
    border-color: var(--tblr-primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--tblr-primary-rgb), 0.16);
}

.ts-wrapper .ts-control,
.ts-wrapper.focus .ts-control {
    box-shadow: none;
}

.ts-dropdown,
.ts-control,
.ts-control input {
    color: var(--tblr-body-color);
}

.ts-control input::placeholder {
    color: var(--tblr-secondary);
}

.ts-dropdown {
    background: var(--tblr-bg-surface);
    border-color: var(--tblr-border-color);
    border-radius: var(--tblr-border-radius);
    box-shadow: var(--tblr-shadow-dropdown);
    /* Une colonne étroite (unité, TVA d'une ligne de devis) ne doit pas
       tronquer les intitulés de sa liste. */
    min-width: 100%;
    width: max-content;
    max-width: min(30rem, calc(100vw - 2rem));
}

.ts-dropdown .option {
    padding: 0.5rem 0.75rem;
}

.ts-dropdown [data-selectable] .highlight {
    background: rgba(var(--tblr-primary-rgb), 0.16);
}

.ts-dropdown .selected {
    font-weight: 600;
}

/* Les valeurs d'un choix multiple : des badges discrets, lisibles dans les
   deux thèmes. */
.ts-wrapper.multi .ts-control > div {
    background: var(--tblr-bg-surface-secondary);
    border: var(--tblr-border-width) solid var(--tblr-border-color);
    color: var(--tblr-body-color);
}

.ts-wrapper.multi .ts-control > div.active {
    background: var(--tblr-primary);
    border-color: var(--tblr-primary);
    color: var(--tblr-primary-fg);
}

/* Dans un groupe (sélecteur d'entreprise), le <select> masqué reste le premier
   enfant : Bootstrap tiendrait l'enveloppe pour un élément du milieu, et lui
   retirerait ses coins gauches. */
.input-group > .tomselected:first-child + .ts-wrapper {
    margin-left: 0;
    border-top-left-radius: var(--tblr-border-radius);
    border-bottom-left-radius: var(--tblr-border-radius);
}

/* Filtres en `w-auto` : sans plancher, l'enveloppe se réduirait à la largeur
   de son chevron. */
.ts-wrapper.w-auto {
    min-width: 10rem;
}

/* Les champs compacts d'une ligne de devis restent compacts. */
.quote-line .ts-wrapper.form-select .ts-control {
    padding: 0.25rem 1.75rem 0.25rem 0.4rem;
    font-size: 0.8125rem;
}

.quote-line .ts-wrapper.form-select {
    min-height: 0;
    background-position: right 0.4rem center;
}

@media (prefers-reduced-motion: reduce) {
    .ts-control {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Aide au remplissage — l'effacement d'une ligne validée
   --------------------------------------------------------------------------
   Au clic, la ligne (ou la carte vidée) s'efface AVANT la réponse du serveur :
   c'est ce qui rend l'écran rapide à la main, on passe à la suivante sans
   attendre. Tabler n'a pas d'état « en train de partir » ; la ligne reste
   dans le DOM jusqu'à ce que la carte recalculée la remplace, d'où un simple
   repli visuel plutôt qu'un retrait. */
/* Plafond de hauteur sur les LIGNES seulement : c'est lui qui s'anime vers 0.
   Une carte dépliée dépasse toute valeur fixe, elle ne fait que s'estomper. */
[data-controller="enrichment"] .list-group-item {
    max-height: 20rem;
    transition: opacity .15s ease, max-height .2s ease, padding .2s ease;
}

[data-controller="enrichment"] [data-enrichment-target="card"] {
    transition: opacity .2s ease;
}

[data-controller="enrichment"] [data-enrichment-target="card"].enrichment-leaving {
    max-height: none;
}

/* La classe s'ajoute à .list-group-item : deux classes l'emportent sur son
   padding sans `!important`. */
[data-controller="enrichment"] .enrichment-leaving {
    opacity: 0;
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    overflow: hidden;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    [data-controller="enrichment"] .list-group-item,
    [data-controller="enrichment"] [data-enrichment-target="card"] {
        transition: none;
    }
}

/* Menu utilisateur : le choix du thème. On masque l'entrée du thème EN COURS,
   et elle seule. `tabler-theme.min.js` retire l'attribut pour le thème clair
   (sa valeur par défaut) : le clair, c'est donc l'absence d'attribut. */
:root:not([data-bs-theme]) .theme-choice-light,
:root[data-bs-theme="light"] .theme-choice-light,
:root[data-bs-theme="dark"] .theme-choice-dark,
:root[data-bs-theme="section4"] .theme-choice-section4 {
    display: none;
}
