/* ==========================================================================
   Stackly — Composants
   Le vocabulaire commun des 82 pages. Ecrit contre tokens.css uniquement :
   aucune valeur en dur. Direction « Crenolia » : cartes blanches sur fond
   gris, encre presque noire, la couleur de l'outil pour son action principale.
   Le vocabulaire de la refonte des outils (.ui-page-head, .ui-worklist...)
   est documente a la fin de cette feuille.
   Charge apres shell.css.
   ========================================================================== */

/* ---------- Garde generale --------------------------------------------------
   L'attribut `hidden` doit toujours masquer. Sa regle native n'a aucune
   specificite : la moindre classe portant un `display` la bat, et l'element
   reste visible alors que le gabarit le declare masque. Chaque feuille de
   module reecrivait la garde dans son coin ; elle est posee une fois ici.
   ------------------------------------------------------------------------- */

[hidden] { display: none !important; }

/* ---------- Boutons -------------------------------------------------------- */

.ui-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /*  Maquettes V2 : 44 px, texte 15 px en 500, rayon 10 px. 16 px de marge
      interieure, 18 px pour le bouton plein (primaire, accent). */
  height: var(--control-lg);
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-button);
  font-family: var(--font-ui);
  font-size: 15px;
  font-weight: var(--weight-medium);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease),
              border-color var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease),
              filter var(--duration-fast) var(--ease);
}

.ui-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ui-btn i { font-size: 14px; }

/*  Primaire : l'action principale de l'ecran, une seule. Dans un outil elle
    prend la couleur de l'outil (--accent-solid, texte blanc a 4,5:1 minimum) ;
    hors outil — tableau de bord, profil, offres — elle reste a l'encre. */
.ui-btn--primary   { background: var(--accent-solid); color: var(--ink-on-dark); border-width: 0; padding: 0 18px; }
.ui-btn--primary:hover { filter: brightness(0.92); color: var(--ink-on-dark); }
body[data-module="none"] .ui-btn--primary { background: var(--ink); }
body[data-module="none"] .ui-btn--primary:hover { background: #2B2E36; filter: none; }

.ui-btn--secondary { background: var(--surface); color: var(--ink); border-color: var(--border-strong); }
.ui-btn--secondary:hover { background: var(--surface-sunken); color: var(--ink); }

/* Accent : la teinte du module courant, meme hors outil (bleu neutre). */
.ui-btn--accent    { background: var(--accent-solid); color: var(--ink-on-dark); border-width: 0; padding: 0 18px; }
.ui-btn--accent:hover { filter: brightness(0.92); color: var(--ink-on-dark); }

.ui-btn--tinted    { background: var(--accent-tint); color: var(--accent-ink); }
.ui-btn--tinted:hover { background: var(--accent-tint); filter: brightness(0.97); }

.ui-btn--ghost     { background: none; color: var(--accent-ink); padding: 0 var(--space-2); }
.ui-btn--ghost:hover { color: var(--ink); }

.ui-btn--danger    { background: var(--danger); color: var(--ink-on-dark); }
.ui-btn--danger:hover { filter: brightness(0.92); color: var(--ink-on-dark); }

.ui-btn--danger-outline { background: var(--surface); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.ui-btn--danger-outline:hover { background: var(--danger-tint); color: var(--danger); }

/*  Bouton de ligne (« Encaisser », « Relancer ») : 36 px, 14 px en 500. */
.ui-btn--sm { height: var(--control-sm); padding: 0 14px; font-size: 14px; }
.ui-btn--lg { height: var(--control-lg); padding: 0 18px; font-size: 15px; }

.ui-btn--icon { width: var(--control-lg); padding: 0; }
.ui-btn--icon.ui-btn--sm { width: var(--control-sm); }

.ui-btn[disabled],
.ui-btn--disabled {
  background: var(--surface-sunken);
  border-color: var(--border);
  color: var(--ink-disabled);
  cursor: not-allowed;
  pointer-events: none;
}

.ui-btn--block { width: 100%; }

/* Cible tactile : 44 px plancher sur mobile. Sans exception. */
@media (max-width: 992px) {
  .ui-btn { height: var(--touch-target); }
  .ui-btn--sm { height: 38px; }
  .ui-btn--icon { width: var(--touch-target); }
}

/* ---------- Champs --------------------------------------------------------- */

.ui-field { display: block; }

.ui-field-label {
  display: block;
  font-size: 14px;
  font-weight: var(--weight-medium);
  color: var(--ink);
  margin-bottom: 6px;
}

.ui-field-required { color: var(--danger); margin-left: 2px; }

.ui-field-control,
.ui-input,
.ui-select,
.ui-textarea {
  display: block;
  width: 100%;
  min-height: var(--field-height);
  padding: 0 13px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-field);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: calc(var(--field-height) - 2px);
  transition: border-color var(--duration-fast) var(--ease),
              box-shadow var(--duration-fast) var(--ease);
}

.ui-textarea { line-height: var(--lh-normal); padding: 11px 13px; min-height: 86px; resize: vertical; }

.ui-input::placeholder,
.ui-textarea::placeholder { color: var(--ink-muted); opacity: 0.8; }

.ui-input:focus,
.ui-select:focus,
.ui-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring-field);
}

.ui-select {
  appearance: none;
  padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235F6573' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}

.ui-field-hint {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin-top: 6px;
}

.ui-field-error {
  display: flex;
  /*  En tete, pas au milieu : un motif sur deux lignes gardait son icone
      flottant a mi-hauteur, loin du debut de la phrase. */
  align-items: flex-start;
  gap: 6px;
  font-size: var(--text-sm);
  color: var(--danger);
  margin-top: 6px;
}

.ui-field--invalid .ui-input,
.ui-field--invalid .ui-select,
.ui-field--invalid .ui-textarea {
  border-color: var(--danger);
  box-shadow: inset 0 0 0 1px var(--danger);
}

/* Montants, quantites, references : alignes et tabulaires. */
.ui-input--numeric { text-align: right; font-variant-numeric: tabular-nums; }

/*  Lecture seule (rôle de l'équipe) : `<fieldset class="ui-lecture-seule"
    disabled>` autour des champs d'un formulaire fige tout ce qu'il contient,
    sans créer de boîte (la mise en page reste celle du formulaire). Le
    gabarit ne le pose que si peut_ecrire(outil) répond non. Les champs se
    lisent comme des valeurs : texte à l'encre, fond grisé, pas de curseur
    de saisie. */
.ui-lecture-seule { display: contents; }
.ui-lecture-seule .ui-input,
.ui-lecture-seule .ui-select,
.ui-lecture-seule .ui-textarea {
  background-color: var(--surface-sunken);
  color: var(--ink);
  -webkit-text-fill-color: var(--ink);
  opacity: 1;
  cursor: default;
}
.ui-lecture-seule .ui-select { background-image: none; }
.ui-lecture-seule .ui-textarea { resize: none; }
.ui-lecture-seule .ui-switch,
.ui-lecture-seule label { cursor: default; }

/* Interrupteur */
.ui-switch { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; }
.ui-switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.ui-switch-track {
  width: 40px; height: 23px;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
  position: relative;
  flex-shrink: 0;
  transition: background var(--duration-fast) var(--ease);
}

.ui-switch-track::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--surface);
  transition: transform var(--duration-fast) var(--ease);
}

.ui-switch input:checked + .ui-switch-track { background: var(--accent); }
.ui-switch input:checked + .ui-switch-track::after { transform: translateX(17px); }
.ui-switch input:focus-visible + .ui-switch-track { box-shadow: var(--focus-ring); }

/* ---------- Statuts --------------------------------------------------------
   La couleur ne porte jamais l'information seule : chaque pastille a un mot
   et une icone.
   -------------------------------------------------------------------------- */

.ui-status {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  gap: 7px;
  max-width: 100%;
  height: 24px;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
}

.ui-status i { font-size: 12px; }

.ui-status--neutral { background: var(--surface-sunken); color: var(--ink-secondary); }
.ui-status--muted   { background: var(--surface-sunken); color: var(--ink-muted); }
.ui-status--success { background: var(--success-tint); color: var(--success); }
.ui-status--warning { background: var(--warning-tint); color: var(--warning-ink); }
.ui-status--danger  { background: var(--danger-tint);  color: var(--danger); }
.ui-status--info    { background: var(--info-tint);    color: var(--info-ink); }
.ui-status--accent  { background: var(--accent-tint);  color: var(--accent-ink); }

/*  Marque de forme, a la place de l'icone (maquettes V2) : la forme double
    la couleur, lisible par un daltonien et en impression.
    <span class="ui-status ui-status--success"><span class="ui-status-mark" aria-hidden="true"></span>Relance auto</span>
    plein (defaut) : carre plein      — en cours, accepte
    --tirets       : carre en tirets  — en pause, consulte
    --losange      : losange plein    — litige, bloquant
    --anneau       : rond evide       — manuel, en attente
    --point        : rond plein pale  — clos, refuse
    La marque prend la couleur du texte ; --accent la passe a la teinte vive
    de l'outil. */
.ui-status-mark {
  display: inline-block;
  flex-shrink: 0;
  box-sizing: border-box;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: currentColor;
}

.ui-status-mark--tirets  { background: transparent; border: 1.5px dashed currentColor; }
.ui-status-mark--losange { border-radius: 0; transform: rotate(45deg); }
.ui-status-mark--anneau  { border-radius: 50%; background: transparent; border: 1.5px solid var(--ink-muted); }
.ui-status-mark--point   { border-radius: 50%; background: var(--ink-faint); }
.ui-status-mark--accent  { background: var(--accent); }

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

.ui-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.ui-card--flush { padding: 0; overflow: hidden; }
.ui-card--padded { padding: var(--space-5) var(--space-5); }

.ui-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}

.ui-card-title {
  font-family: var(--font-display);
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  color: var(--ink);
  margin: 0;
}

.ui-card-subtitle {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin: 2px 0 0;
}

.ui-card-body { padding: var(--space-5); }

.ui-card-foot {
  padding: var(--space-4) var(--space-5);
  background: var(--surface-muted);
  border-top: 1px solid var(--border-subtle);
}

/* Carte statistique : une metrique, une seule. */
.ui-stat { padding: var(--space-4) 18px; }

.ui-stat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* Teintes d'icone de carte statistique. Vocabulaire ferme : le gabarit passe
   un mot-cle, jamais une couleur, pour qu'aucun style en ligne ne subsiste. */
.ui-stat-icon--accent    { color: var(--accent); }
.ui-stat-icon--muted     { color: var(--ink-muted); }
.ui-stat-icon--documents { color: var(--mod-documents); }
.ui-stat-icon--stock     { color: var(--mod-stock); }
.ui-stat-icon--finance   { color: var(--mod-finance); }
.ui-stat-icon--crm       { color: var(--mod-crm); }
.ui-stat-icon--planning  { color: var(--mod-planning); }
.ui-stat-icon--expenses  { color: var(--mod-expenses); }
.ui-stat-icon--assistant { color: var(--mod-assistant); }
.ui-stat-icon--success   { color: var(--success); }
.ui-stat-icon--warning   { color: var(--warning); }
.ui-stat-icon--danger    { color: var(--danger); }

.ui-stat-label {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
}

.ui-stat-value {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin-top: 10px;
  color: var(--ink);
}

.ui-stat-value--sm { font-size: var(--text-title-1); }
.ui-stat-foot { font-size: var(--text-sm); color: var(--ink-muted); margin-top: 6px; }

.ui-stat-delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.ui-stat-delta--up   { color: var(--success); }
.ui-stat-delta--down { color: var(--danger); }

/*  Une tuile en alerte reste une carte blanche : seuls le chiffre et sa
    legende prennent la couleur de l'etat. Le gris porte, la couleur signale. */
.ui-stat--warning .ui-stat-value,
.ui-stat--warning .ui-stat-foot { color: var(--warning-ink); }

.ui-stat--danger .ui-stat-value,
.ui-stat--danger .ui-stat-foot { color: var(--danger-ink); }

/* ---------- Tableau ---------------------------------------------------------
   Une seule action visible par ligne : le menu. Pas trois pastilles rondes.
   -------------------------------------------------------------------------- */

.ui-table { width: 100%; border-collapse: collapse; }

.ui-table thead th,
.ui-table-head {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
  text-align: left;
  height: 40px;
  padding: 0 var(--space-4);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

.ui-table tbody td {
  padding: var(--space-2) var(--space-4);
  height: var(--row-height);
  font-size: 14px;
  color: var(--ink);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}

.ui-table tbody tr:last-child td { border-bottom: none; }
.ui-table tbody tr:hover td { background: var(--surface-muted); }

.ui-table .is-numeric { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ui-table .is-strong  { font-weight: var(--weight-semibold); }
.ui-table .is-muted   { color: var(--ink-secondary); }

/* Le liseré ne marque que la premiere cellule : pose sur chacune, il
   dessinait un trait vertical entre toutes les colonnes. */
.ui-table tr.is-selected td { background: var(--accent-tint-2); }
.ui-table tr.is-selected td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.ui-table tr.is-flagged td  { background: color-mix(in srgb, var(--warning-tint) 60%, var(--surface)); }
.ui-table tr.is-flagged td:first-child { box-shadow: inset 3px 0 0 var(--mod-expenses); }

.ui-table-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.ui-table-count { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }

.ui-row-menu {
  width: 30px; height: 30px;
  border: none;
  background: none;
  color: var(--ink-muted);
  border-radius: var(--radius-field);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ui-row-menu:hover { background: var(--surface-sunken); color: var(--ink); }
.ui-row-menu:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Sur mobile un tableau devient une liste de cartes. Jamais un defilement lateral. */
@media (max-width: 768px) {
  /*  LA CARTE QUI CONTIENT DES CARTES SE DISSOUT.
   *
   *  Chaque ligne devient ici une carte blanche, bordee, au rayon de 14 px.
   *  Elle restait pourtant enfermee dans une `.ui-card` blanche, bordee, au
   *  rayon de 14 px : un cadre dans un cadre identique. Les lignes cessaient
   *  alors de se lire comme des objets separes — elles flottaient dans un
   *  contenant de la meme couleur, sans qu'on sache ou l'un finit et l'autre
   *  commence.
   *
   *  Le cadre exterieur s'efface donc, et les lignes se posent directement sur
   *  le fond de la page. L'en-tete de la carte, lui, reste : il nomme la liste.
   *
   *  L'ancienne feuille faisait deja cela pour `.table-mobile-cards` ; la
   *  regle n'avait pas suivi le nouveau vocabulaire.  */
  .ui-card:has(.ui-table--stack) {
    background: transparent;
    border-color: transparent;
    box-shadow: none;
  }

  .ui-card:has(.ui-table--stack) > .ui-card-head {
    padding-left: 0;
    padding-right: 0;
    border-bottom: none;
  }

  /*  EN MODE CARTE, CE N'EST PLUS UN TABLEAU.
   *
   *  Les lignes passaient bien en `block`, mais la table elle-meme restait en
   *  `display: table` : elle continuait donc a calculer une largeur
   *  intrinseque a partir de ses cellules, et depassait son conteneur — 489 px
   *  dans une colonne de 316 sur la page Stock. Le contenu etait rogne sans
   *  qu'aucune barre de defilement ne le signale.  */
  .ui-table--stack {
    display: block;
    width: 100%;
    min-width: 0;
    background: transparent;
  }

  .ui-table--stack tbody { display: block; width: 100%; background: transparent; }

  .ui-table--stack thead { display: none; }
  .ui-table--stack tbody tr {
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    background: var(--surface);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
    /*  Le fond de l'application est a quatre points du blanc : sans un leger
        relief, une pile de cartes blanches sur un fond presque blanc se lit
        comme une liste plate, et les lignes ne se detachent plus les unes des
        autres. La bordure seule n'y suffit pas.  */
    box-shadow: var(--shadow-1);
  }
  .ui-table--stack tbody td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    height: auto;
    padding: 6px 0;
    border-bottom: none;
    /*  Une valeur saisie par un client peut etre longue et sans espace — une
        reference, une unite fantaisiste. Sans ces deux lignes elle poussait la
        carte au-dela de l'ecran et rognait le reste en silence.  */
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /*  Ligne signalee ou choisie : en carte, c'est la carte qui se teinte,
      pas chaque cellule (qui dessinait un pave dans la carte). */
  .ui-table--stack tbody tr.is-flagged { background: color-mix(in srgb, var(--warning-tint) 60%, var(--surface)); }
  .ui-table--stack tbody tr.is-selected { background: var(--accent-tint-2); }
  .ui-table--stack tbody tr.is-flagged td,
  .ui-table--stack tbody tr.is-selected td { background: transparent; box-shadow: none; }

  /*  Le libelle, lui, ne se coupe pas : c'est le repere de lecture. */
  .ui-table--stack tbody td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--ink-muted);
  }
}

/* ---------- Onglets de filtre ------------------------------------------------
   Des liens, pas des boutons : le filtre passe par l'adresse, une vue filtree
   se partage et survit au bouton Precedent. Le soulignement de la navigation
   interne du CRM, avec un compteur par onglet.

   <nav class="ui-tabs" aria-label="…">
     <a class="ui-tab is-current" aria-current="page" href="?statut=a-traiter">
       A traiter <span class="ui-tab-count">3</span></a>
   </nav>
   ---------------------------------------------------------------------------- */

.ui-tabs {
  display: flex;
  gap: var(--space-1);
  overflow-x: auto;
  scrollbar-width: none;
}
.ui-tabs::-webkit-scrollbar { display: none; }

.ui-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--control-md);
  padding: 0 var(--space-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--ink-secondary);
  font-size: 14px;
  font-weight: var(--weight-medium);
  text-decoration: none;
  white-space: nowrap;
}
.ui-tab:hover { color: var(--ink); }
.ui-tab:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-chip); }
.ui-tab.is-current { color: var(--ink); border-bottom-color: var(--ink); font-weight: var(--weight-semibold); }

.ui-tab-count { font-size: var(--text-sm); color: var(--ink-muted); font-variant-numeric: tabular-nums; }

/* La barre qui porte les onglets dans une carte : filet du bas, action a droite. */
.ui-tabs-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 0 var(--space-5);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

@media (max-width: 768px) {
  .ui-tabs-bar { padding: 0; align-items: stretch; }
  .ui-tabs-bar > .ui-btn { margin: var(--space-3) 0; }
}

/* ---------- Pagination ------------------------------------------------------- */

.ui-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  background: var(--surface-muted);
  border-top: 1px solid var(--border);
}

.ui-pagination-range { font-size: var(--text-sm); color: var(--ink-secondary); font-variant-numeric: tabular-nums; }
.ui-pagination-pages { display: flex; align-items: center; gap: 5px; }

.ui-page {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 8px;
  border-radius: var(--radius-field);
  border: 1px solid transparent;
  background: none;
  color: var(--ink-secondary);
  font-size: 13.5px;
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

.ui-page:hover { background: var(--surface-sunken); color: var(--ink); }
.ui-page:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.ui-page.is-current { background: var(--ink); color: var(--ink-on-dark); font-weight: var(--weight-semibold); }
.ui-page--arrow { border-color: var(--border-strong); background: var(--surface); }
.ui-page--arrow.is-disabled { color: var(--ink-disabled); border-color: var(--border); pointer-events: none; }

/* ---------- Etat vide --------------------------------------------------------
   Un etat vide dit toujours quoi faire. « Aucune donnee » seul est interdit.
   ---------------------------------------------------------------------------- */

.ui-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--space-10) var(--space-6);
  text-align: center;
}

.ui-empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--surface-sunken);
  color: var(--ink-muted);
  font-size: 20px;
}

.ui-empty-title {
  margin: var(--space-4) 0 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
}

.ui-empty-text {
  max-width: 46ch;
  margin: 6px auto 0;
  color: var(--ink-muted);
  font-size: 14px;
  line-height: var(--lh-normal);
}

.ui-empty .ui-btn { margin-top: var(--space-5); }

/* Actions de l'etat vide : une principale, parfois une secondaire. */
.ui-empty-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
}

.ui-empty-actions .ui-btn { margin-top: 0; }

/* ---------- Encarts ----------------------------------------------------------- */

.ui-note {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  color: var(--ink-secondary);
}

.ui-note i { font-size: 17px; flex-shrink: 0; margin-top: 1px; }

/*  Un lien dans un encart prend la couleur de l'encart, souligne : sans
    cette regle il sortait dans le bleu brut du navigateur. */
.ui-note a {
  color: inherit;
  font-weight: var(--weight-semibold);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.ui-note a:hover { color: var(--ink); }
.ui-note a:focus-visible { outline: none; border-radius: 2px; box-shadow: var(--focus-ring); }
.ui-note-title { font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink); margin-bottom: 3px; }

.ui-note--warning { border-color: color-mix(in srgb, var(--warning) 25%, transparent); background: var(--warning-tint); color: var(--warning-ink); }
.ui-note--warning i, .ui-note--warning .ui-note-title { color: var(--warning-ink); }

.ui-note--danger { border-color: color-mix(in srgb, var(--danger) 25%, transparent); background: var(--danger-tint); color: var(--danger-ink); }
.ui-note--danger i, .ui-note--danger .ui-note-title { color: var(--danger-ink); }

.ui-note--success { border-color: color-mix(in srgb, var(--success) 25%, transparent); background: var(--success-tint); color: var(--success-ink); }
.ui-note--success i, .ui-note--success .ui-note-title { color: var(--success-ink); }

.ui-note--accent { border-color: var(--accent-tint); background: var(--accent-tint-2); color: var(--accent-ink); }
.ui-note--accent i, .ui-note--accent .ui-note-title { color: var(--accent-ink); }

/* ---------- Grilles utilitaires ------------------------------------------------ */

.ui-grid { display: grid; gap: var(--space-4); }
.ui-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ui-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ui-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ui-grid--5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }

@media (max-width: 1200px) {
  .ui-grid--4, .ui-grid--5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
  .ui-grid--2, .ui-grid--3, .ui-grid--4, .ui-grid--5 { grid-template-columns: minmax(0, 1fr); }
}

.ui-stack { display: flex; flex-direction: column; gap: var(--space-4); }
.ui-row   { display: flex; align-items: center; gap: var(--space-2); }
.ui-row--between { justify-content: space-between; }
.ui-spacer { flex-grow: 1; }

/* ---------- Modale ------------------------------------------------------------
   Utilisee par la fiche client rapide du chassis. Les styles etaient inline
   dans base.html.twig avant la refonte.
   ---------------------------------------------------------------------------- */

/* Centree verticalement. Elle s'ouvrait a 32px du haut, ce qui la posait haut
   sur un grand ecran, loin du regard et loin du bouton qui l'a ouverte. */
.ui-modal {
  position: fixed;
  inset: 0;
  z-index: 1050;
  overflow-y: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6) 0;
}

/*  Le voile et le dialogue sont deux enfants de .ui-modal, qui porte
    `position: fixed` et `z-index: 1050` : elle ouvre donc son propre contexte
    d'empilement, et seul l'ordre RELATIF de ses deux enfants compte ici.

    Le voile portait `z-index: 1040` et le dialogue `z-index: auto`, c'est-a-dire
    zero. Le voile passait donc PAR-DESSUS le dialogue : il le grisait, et
    surtout il interceptait tous les clics. Comme le voile a pour role de
    fermer, cliquer sur « Resilier maintenant », sur un menu deroulant ou dans
    un champ refermait la modale au lieu d'agir. Les cinq modales du profil et
    de la facturation etaient inutilisables a la souris ; seul le clavier, qui
    ne depend pas du test de survol, continuait de fonctionner.

    0 et 1 suffisent, et disent l'intention sans nombre magique.  */
.ui-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: var(--overlay);
  cursor: pointer;
}

.ui-modal-dialog {
  position: relative;
  z-index: 1;
  max-width: 800px;
  /* `margin: auto` plutot que `align-items: center` seul : quand le dialogue
     depasse la hauteur de l'ecran, un centrage par align-items rogne son haut
     et le rend inatteignable au defilement. La marge automatique, elle, le
     laisse entier. */
  margin: auto;
  padding: 0 var(--gutter-page);
}

.ui-modal-content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}

.ui-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}

.ui-modal-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: var(--text-title-2);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  color: var(--ink);
  margin: 0;
}

.ui-modal-title i { font-size: 20px; color: var(--accent); }

.ui-modal-close {
  width: var(--control-sm);
  height: var(--control-sm);
  border: none;
  background: none;
  color: var(--ink-muted);
  font-size: 22px;
  line-height: 1;
  border-radius: var(--radius-field);
  cursor: pointer;
}

.ui-modal-close:hover { background: var(--surface-sunken); color: var(--ink); }
.ui-modal-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.ui-modal-body {
  padding: var(--space-5);
  max-height: calc(100vh - 250px);
  overflow-y: auto;
}

.ui-modal-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-muted);
  border-top: 1px solid var(--border-subtle);
}

@media (max-width: 992px) {
  .ui-modal-close { width: var(--touch-target); height: var(--touch-target); }
}

/* ---------- Fenetres de message (flash) ---------------------------------------
   Une action qui aboutit doit le dire. Ces fenetres etaient decrites a deux
   endroits qui se contredisaient : 230 lignes dans shell-legacy.css, en
   couleurs brutes et degrades, puis 48 lignes dans shell.css qui en
   redefinissaient la moitie. Tout est ici, sur les jetons.
   ---------------------------------------------------------------------------- */

/*  EN BAS, AU CENTRE.

    Les messages sortaient en haut a droite, la ou chaque ecran de
    l'application pose ses boutons d'action : ils recouvraient « Nouveau
    document », « Exporter », « Ajouter un produit »... c'est-a-dire ce sur
    quoi on venait de cliquer et ce sur quoi on allait cliquer ensuite. Le bas
    du centre n'est occupe par rien et se lit sans quitter des yeux le contenu.

    `bottom` tient compte de `safe-area-inset-bottom` : sur un telephone, la
    barre de geste mangeait le message. */
#flashMessagesContainer {
  position: fixed;
  bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  left: 50%;
  transform: translateX(-50%);
  /*  Au-dessus des modales, pour de bon. La valeur etait 1080 sous un
      commentaire qui annoncait le contraire : les modales de l'application
      montent a 1200, et deux fonds de modale jusqu'a 9999. Un message qui
      confirme une suppression ne doit pas passer derriere la fenetre qui l'a
      declenchee. */
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  width: min(420px, calc(100vw - var(--space-5) * 2));
  pointer-events: none;   /* la page reste cliquable autour des fenetres */
}

.flash-toast {
  pointer-events: auto;
  position: relative;
  width: 100%;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  overflow: hidden;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-3);
  color: var(--ink);
  animation: flashEntree 0.28s var(--ease);
}

.flash-toast.removing {
  animation: flashSortie 0.28s var(--ease) forwards;
}

@keyframes flashEntree {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes flashSortie {
  to { opacity: 0; transform: translateY(14px); }
}

.flash-toast-icon { flex-shrink: 0; margin-top: 1px; }
.flash-toast-icon svg { display: block; width: 18px; height: 18px; }

.flash-toast-content {
  flex: 1;
  min-width: 0;
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--ink-secondary);
  /* Un message peut citer un nom de fichier ou de client sans espace. */
  overflow-wrap: anywhere;
}

/* La couleur ne porte que l'icone et le filet : le texte reste a l'encre,
   lisible quel que soit le type. */
.flash-toast-success .flash-toast-icon { color: var(--success); }
.flash-toast-error   .flash-toast-icon,
.flash-toast-danger  .flash-toast-icon { color: var(--danger); }
.flash-toast-warning .flash-toast-icon { color: var(--warning-ink); }
.flash-toast-info    .flash-toast-icon { color: var(--info); }

/*  L'action d'un message (« Annuler » apres une action rapide) : un lien
    bouton, a l'accent, avant la croix. */
.flash-toast-action {
  flex-shrink: 0;
  /*  Centre sur la premiere ligne du message (20 px), comme la croix. */
  height: var(--control-sm);
  margin: -8px 0;
  padding: 0 var(--space-2);
  border: none;
  border-radius: var(--radius-field);
  background: none;
  color: var(--accent-ink);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
}

.flash-toast-action:hover { background: var(--accent-tint-2); }
.flash-toast-action:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.flash-toast-close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--control-sm);
  height: var(--control-sm);
  margin: -4px -4px 0 0;
  padding: 0;
  border: none;
  border-radius: var(--radius-field);
  background: none;
  color: var(--ink-muted);
  cursor: pointer;
}

.flash-toast-close:hover { background: var(--surface-sunken); color: var(--ink); }
.flash-toast-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.flash-toast-close svg { display: block; width: 16px; height: 16px; }

/* Le filet de progression dit combien de temps il reste avant disparition.
   Il prend la couleur de l'icone, donc du type de message. */
.flash-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: currentColor;
  opacity: 0.28;
  transition: width 12s linear;
}

.flash-toast-success .flash-progress { color: var(--success); }
.flash-toast-error   .flash-progress,
.flash-toast-danger  .flash-progress { color: var(--danger); }
.flash-toast-warning .flash-progress { color: var(--warning-ink); }
.flash-toast-info    .flash-progress { color: var(--info); }

/* Sur telephone, la fenetre prend la largeur, gouttieres comprises. */
@media (max-width: 600px) {
  #flashMessagesContainer {
    left: var(--gutter-page);
    right: var(--gutter-page);
    top: calc(var(--space-4) + env(safe-area-inset-top, 0px));
    bottom: auto;
    width: auto;
    /*  Le centrage par translation n'a plus lieu d'etre : il decalait le
        conteneur d'une demi-largeur hors de l'ecran, a gauche. */
    transform: none;
  }
}

/* Une disparition qui glisse n'apporte rien a qui demande moins de mouvement,
   et le filet de progression cesse d'etre une animation pour devenir un
   simple reste de temps. */
@media (prefers-reduced-motion: reduce) {
  .flash-toast,
  .flash-toast.removing { animation: none; }
  .flash-progress { transition: none; }
}

/* ---------- Modale d'alerte et de confirmation (.cm-*) -----------------------
   C'est la modale que shell.js construit pour customAlert() et customConfirm(),
   donc celle qui s'affiche a chaque action destructrice de l'application. Elle
   vivait dans shell-legacy.css, en couleurs brutes — #ef4444, #f59e0b,
   #10b981, #111827, #6b7280, #f3f4f6 — et sur var(--primary), qui vaut
   l'ancien violet #6022C4. Reecrite ici sur les jetons, dans le meme
   vocabulaire que .ui-modal ci-dessus.

   Les noms de classes sont conserves : shell.js les construit, et 94 appels
   dans l'application en dependent.
   ---------------------------------------------------------------------------- */

/* shell.js bascule cette classe pour ouvrir et fermer. Elle doit l'emporter
   sur le `display: flex` de .cm-overlay, d'ou le !important — meme raison que
   la garde [hidden] plus haut dans cette feuille. */
.cm-hidden { display: none !important; }

.cm-overlay {
  position: fixed;
  inset: 0;
  /*  Devant toute modale applicative : c'est le dernier ecran avant un geste
      irreversible. A 1060, il passait derriere les modales de l'inventaire
      (1200) et le bouton de confirmation devenait incliquable. */
  z-index: var(--z-confirm);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: var(--overlay);
  animation: cmFadeIn 0.15s var(--ease);
}

.cm-box {
  width: 100%;
  max-width: 420px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card-lg);
  box-shadow: var(--shadow-3);
  animation: cmSlideIn 0.2s var(--ease);
}

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

@keyframes cmSlideIn {
  from { opacity: 0; transform: translateY(-12px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0)     scale(1); }
}

/* La reduction de mouvement est respectee : l'apparition reste instantanee. */
@media (prefers-reduced-motion: reduce) {
  .cm-overlay,
  .cm-box { animation: none; }
}

/* Le filet de couleur en tete, qui dit la nature du message avant la lecture. */
.cm-stripe { height: 4px; width: 100%; }

.cm-stripe--danger  { background: var(--danger); }
.cm-stripe--warning { background: var(--warning); }
.cm-stripe--error   { background: var(--danger); }
.cm-stripe--success { background: var(--success); }
.cm-stripe--info    { background: var(--info); }

.cm-icon-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  margin: var(--space-5) auto 0;
  border-radius: var(--radius-pill);
  font-size: 20px;
}

.cm-icon-wrap--danger  { background: var(--danger-tint);  color: var(--danger-ink); }
.cm-icon-wrap--warning { background: var(--warning-tint); color: var(--warning-ink); }
.cm-icon-wrap--error   { background: var(--danger-tint);  color: var(--danger-ink); }
.cm-icon-wrap--success { background: var(--success-tint); color: var(--success-ink); }
.cm-icon-wrap--info    { background: var(--info-tint);    color: var(--info-ink); }

.cm-title {
  margin: var(--space-3) var(--space-5) 0;
  font-family: var(--font-display);
  font-size: var(--text-title-2);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  line-height: var(--lh-snug);
  color: var(--ink);
  text-align: center;
}

.cm-message {
  margin: var(--space-2) var(--space-5) 0;
  font-size: var(--text-body);
  line-height: var(--lh-normal);
  color: var(--ink-secondary);
  text-align: center;
}

.cm-footer {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-muted);
  border-top: 1px solid var(--border-subtle);
}

/* Sur un telephone, les deux actions prennent la largeur et se superposent :
   viser un bouton de 90px au pouce, en bas d'ecran, est une source d'erreur
   sur une action destructrice. */
@media (max-width: 480px) {
  .cm-footer { flex-direction: column-reverse; }
  .cm-footer .ui-btn { width: 100%; }
}

/* ==========================================================================
   Assistant a etapes (import d'un fichier)
   Le chassis partage par les assistants d'import — stock, CRM, et les
   suivants. Rien ici ne connait le module : la teinte vient de --accent,
   remappe par <body data-module>. Le nombre d'etapes, leurs libelles et la
   liste des options ne sont pas decrits ici : le gabarit en decide.
   Aucun selecteur d'element nu : cette feuille est chargee par toutes les
   pages.
   ========================================================================== */

/* ---------- Fleche de retour dans la barre du haut --------------------------
   Un carre contour, pas la pastille teintee par defaut du chassis.
   ---------------------------------------------------------------------------- */

.topbar-icon:has(.ui-wizard-back) { background: none; }

.ui-wizard-back {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-button);
  background: var(--surface);
  color: var(--ink);
  font-size: 17px;
  text-decoration: none;
}

.ui-wizard-back:hover { background: var(--surface-sunken); border-color: var(--ink); color: var(--ink); }
.ui-wizard-back:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* ---------- Indicateur d'etapes ----------------------------------------------
   Bandeau pleine largeur sous la barre du haut : il deborde les gouttieres
   de .content-wrapper. Deux etapes ou cinq, la regle ne compte pas.
   ---------------------------------------------------------------------------- */

.ui-wizard-steps {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-3) 0;
  margin: calc(-1 * var(--space-6)) calc(-1 * var(--space-8)) var(--space-6);
  padding: var(--space-5) var(--space-8);
  background: var(--canvas);
  border-bottom: 1px solid var(--border);
}

.ui-wizard-step {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}

.ui-wizard-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border: 1.5px solid var(--border-dashed);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-faint);
  font-size: 13.5px;
  font-weight: var(--weight-bold);
  line-height: 1;
}

.ui-wizard-badge i { font-size: 15px; }

.ui-wizard-step.is-done .ui-wizard-badge,
.ui-wizard-step.is-current .ui-wizard-badge {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--surface);
}

.ui-wizard-text { display: flex; flex-direction: column; min-width: 0; }

.ui-wizard-name {
  font-size: 14px;
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
}

.ui-wizard-step.is-done .ui-wizard-name,
.ui-wizard-step.is-current .ui-wizard-name { color: var(--ink); }

.ui-wizard-note {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.ui-wizard-step.is-current .ui-wizard-note {
  color: var(--accent-ink);
  font-weight: var(--weight-medium);
}

.ui-wizard-line {
  flex: 0 1 90px;
  min-width: var(--space-6);
  height: 2px;
  margin: 0 var(--space-5);
  background: var(--border);
}

.ui-wizard-line.is-done { background: var(--accent); }

/* ---------- Gabarits de page de l'assistant ----------------------------------- */

/* Premiere etape : deux cartes cote a cote, puis la barre d'actions. */
.ui-wizard-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.ui-wizard-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: var(--space-5);
}

/* Etapes suivantes : le travail a gauche, la decision a droite. */
.ui-wizard-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  align-items: start;
  gap: var(--space-5);
}

.ui-wizard-side {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.ui-wizard-side .ui-card--padded { padding: var(--space-5) 22px; }

/* En-tete de carte de l'assistant : un peu plus dense que .ui-card-head,
   et un filet franc plutot que le separateur de lignes. */
.ui-wizard-head {
  align-items: center;
  padding: 17px var(--space-5);
  border-bottom-color: var(--border);
}

.ui-wizard-head .ui-card-subtitle { font-size: 12.5px; }

/* ---------- Barres d'actions ---------------------------------------------------
   `--end` ferme un formulaire pleine largeur, `--split` ferme une colonne
   laterale : deux boutons de meme largeur.
   ---------------------------------------------------------------------------- */

.ui-wizard-actions { display: flex; gap: var(--space-3); }
.ui-wizard-actions--end { justify-content: flex-end; }
.ui-wizard-actions--split .ui-btn { flex: 1 1 0; min-width: 0; }

/* ---------- Mention de bas de panneau ------------------------------------------
   Icone + texte, sans cadre : ce n'est pas un encart .ui-note.
   ---------------------------------------------------------------------------- */

.ui-wizard-hint {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 0;
  font-size: 12.5px;
  line-height: var(--lh-normal);
  color: var(--ink-secondary);
}

.ui-wizard-hint i {
  flex-shrink: 0;
  margin-top: 2px;
  font-size: 15px;
  color: var(--ink-muted);
}

/* ---------- Zone de depot de fichier -------------------------------------------- */

.ui-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 190px;
  padding: var(--space-8) var(--space-5);
  border: 1.5px dashed var(--border-dashed);
  border-radius: var(--radius-card);
  background: var(--surface-muted);
  cursor: pointer;
  text-align: center;
  transition: border-color var(--duration-fast) var(--ease),
              background var(--duration-fast) var(--ease);
}

.ui-dropzone:hover,
.ui-dropzone:focus-visible,
.ui-dropzone.is-over {
  outline: none;
  border-color: var(--accent);
  background: var(--accent-tint-2);
}

.ui-dropzone-icon {
  font-size: 30px;
  color: var(--accent);
}

.ui-dropzone-title {
  font-family: var(--font-display);
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  color: var(--ink);
  margin: var(--space-2) 0 0;
}

.ui-dropzone-sub {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin: 0;
}

/* Le champ natif reste dans le flux pour l'accessibilite, sans etre visible. */
.ui-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.ui-file-selected {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--touch-target);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--success);
  border-radius: var(--radius-card);
  background: var(--success-tint);
  color: var(--success-ink);
}

.ui-file-selected i { font-size: 17px; }

.ui-file-name {
  flex: 1;
  min-width: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Marche a suivre, numerotee ------------------------------------------
   « Comment ca marche » : autant d'items que le gabarit en pose.
   ---------------------------------------------------------------------------- */

.ui-steplist {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ui-steplist-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.ui-steplist-num {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-pill);
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

.ui-steplist-title {
  font-size: 14px;
  font-weight: var(--weight-semibold);
  color: var(--ink);
  margin: 3px 0 2px;
}

.ui-steplist-sub {
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  color: var(--ink-secondary);
  margin: 0;
}

/* ---------- Grille de correspondance des colonnes --------------------------------
   Quatre colonnes : source, fleche, champ cible, etat. Les champs cibles sont
   ceux du module ; la grille ne les connait pas.
   ---------------------------------------------------------------------------- */

.ui-map-card { align-self: start; }
.ui-map-count { flex-shrink: 0; }

.ui-map-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--control-sm) minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-4);
  min-height: var(--row-height);
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--border-subtle);
}

.ui-map-row:last-child { border-bottom: none; }

.ui-map-labels {
  min-height: 0;
  padding-top: 10px;
  padding-bottom: 10px;
  background: var(--surface-sunken);
  border-bottom-color: var(--border);
}

.ui-map-label {
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
}

.ui-map-source { min-width: 0; }

.ui-map-name {
  margin: 0;
  font-size: 14px;
  font-weight: var(--weight-medium);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Valeurs d'exemple sous l'en-tete : on reconnait sa colonne a son contenu,
   pas a son titre. */
.ui-map-sample {
  margin: 0;
  font-size: 12.5px;
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ui-map-arrow {
  justify-self: center;
  font-size: 17px;
  color: var(--ink-disabled);
}

.ui-map-target { min-width: 0; }

.ui-map-select {
  height: var(--control-md);
  min-height: var(--control-md);
  line-height: calc(var(--control-md) - 2px);
  font-size: 14px;
}

.ui-map-state { justify-self: start; }

/* Colonne a confirmer : fond ambre discret et filet vertical.
   Le lisere passe par une ombre interne : pas de decalage de 0,5 px. */
.ui-map-row.is-todo {
  background: var(--mod-expenses-tint-2);
  box-shadow: inset 2px 0 0 var(--warning);
}

.ui-map-row.is-todo .ui-map-arrow { color: var(--warning-ink); }

.ui-map-row.is-todo .ui-map-select {
  border-color: var(--warning);
  box-shadow: inset 0 0 0 1px var(--warning);
}

/* Colonne ignoree. */
.ui-map-row.is-off .ui-map-name,
.ui-map-row.is-off .ui-map-sample { color: var(--ink-faint); }

.ui-map-row.is-off .ui-map-arrow { color: var(--border-strong); }

.ui-map-row.is-off .ui-map-select {
  border-style: dashed;
  border-color: var(--border-dashed);
  background-color: transparent;
  color: var(--ink-faint);
}

/* ---------- Liste de choix exclusifs ---------------------------------------------
   Politique de doublon, cle de rapprochement, type de contact : une carte,
   plusieurs options radio dessinees. Le chassis ne connait aucune option en
   particulier ; les variantes propres a un module restent dans sa feuille.
   ---------------------------------------------------------------------------- */

.ui-choice-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: var(--space-4) 0 0;
  padding: 0;
  border: 0;
}

.ui-choice-option {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: var(--space-3) 13px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-button);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease),
              background var(--duration-fast) var(--ease);
}

.ui-choice-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.ui-choice-mark {
  flex-shrink: 0;
  width: 19px;
  height: 19px;
  margin-top: 1px;
  border: 1.5px solid var(--border-dashed);
  border-radius: 50%;
  background: var(--surface);
}

.ui-choice-text { display: flex; flex-direction: column; min-width: 0; }

.ui-choice-title {
  font-size: 14px;
  font-weight: var(--weight-semibold);
  color: var(--ink);
}

.ui-choice-desc {
  margin-top: 2px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--ink-secondary);
}

.ui-choice-option:hover { border-color: var(--ink-muted); }

.ui-choice-option:has(input:checked) {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
  background: var(--accent-tint-2);
}

.ui-choice-option:has(input:checked) .ui-choice-mark {
  border-color: var(--accent);
  border-width: 5px;
}

.ui-choice-option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Carte a choix : le sous-titre porte la question, il respire un peu plus
   que le sous-titre de carte par defaut. */
.ui-choice-card .ui-card-subtitle {
  font-size: 12.5px;
  line-height: 1.45;
  margin-top: var(--space-1);
}

/* ---------- Panneau « Ce qui va se passer » ---------------------------------------
   L'effet annonce sur les donnees, avant toute ecriture.
   ---------------------------------------------------------------------------- */

.ui-plan-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
}

.ui-plan-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.ui-plan-term {
  font-size: 13.5px;
  font-weight: var(--weight-regular);
  color: var(--ink-secondary);
}

.ui-plan-value {
  margin: 0;
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  color: var(--ink);
}

.ui-plan-value--success { color: var(--success); }
.ui-plan-value--warning { color: var(--warning-ink); }

.ui-plan-row--total {
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-subtle);
}

.ui-plan-row--total .ui-plan-term {
  font-weight: var(--weight-semibold);
  color: var(--ink);
}

.ui-plan-note {
  margin: var(--space-3) 0 0;
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--ink-muted);
}

/* ---------- Tableau large : seul le tableau defile, jamais la page --------------- */

.ui-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ---------- Adaptations ------------------------------------------------------------ */

@media (max-width: 1200px) {
  .ui-wizard-layout { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 992px) {
  .ui-wizard-split { grid-template-columns: minmax(0, 1fr); }
  .ui-wizard-back { width: var(--touch-target); height: var(--touch-target); }
  .ui-wizard-steps {
    margin: calc(-1 * var(--space-5)) calc(-1 * var(--gutter-page)) var(--space-5);
    padding: var(--space-4) var(--gutter-page);
  }
  .ui-wizard-line { flex: 0 1 var(--space-8); margin: 0 var(--space-3); }
}

@media (max-width: 768px) {
  .ui-wizard-steps {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }
  .ui-wizard-step { width: 100%; }
  .ui-wizard-line {
    flex: none;
    width: 2px;
    height: var(--space-4);
    min-width: 0;
    margin: 0 0 0 14px;
  }
  .ui-wizard-actions { flex-direction: column-reverse; }
  .ui-wizard-actions--end .ui-btn { width: 100%; }
  .ui-map-row {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2);
    padding: var(--space-4) var(--space-4);
  }
  .ui-map-labels { display: none; }
  .ui-map-arrow { display: none; }
  .ui-map-select { min-height: var(--touch-target); line-height: calc(var(--touch-target) - 2px); }
  .ui-map-name,
  .ui-map-sample { white-space: normal; }
  /* Cible tactile : chaque choix reste cliquable au doigt. */
  .ui-choice-option { min-height: var(--touch-target); }
}

/* ==========================================================================
   VOCABULAIRE DE LA REFONTE DES OUTILS
   Direction « Crenolia ». Partage par les sept outils : chacun compose ses
   ecrans avec ces briques, et ne garde dans sa feuille de module que ce qui
   lui est propre. Tout est ecrit contre les jetons ; la couleur de l'outil
   arrive par --accent / --accent-solid, posees par <body data-module>.

   Ecran type d'un outil (vue « Liste ») :

   <header class="ui-page-head">
     <div class="ui-page-head-main">
       <h1 class="ui-page-head-title">Paiements</h1>
       <nav class="ui-viewnav" aria-label="Vues de l'outil">
         <a class="ui-viewnav-item" href="…" aria-current="page">Liste</a>
         <a class="ui-viewnav-item" href="…">Statistiques</a>
       </nav>
     </div>
     <div class="ui-page-head-actions">
       <a class="ui-btn ui-btn--secondary" href="…">Export pour le comptable</a>
       <a class="ui-btn ui-btn--primary" href="…">Enregistrer un paiement</a>
     </div>
   </header>

   <nav class="ui-filtertabs" aria-label="Files de travail">
     <a class="ui-filtertab ui-filtertab--danger" href="?file=retard" aria-current="true">
       <span class="ui-filtertab-label">En retard</span>
       <span class="ui-filtertab-figures">
         <span class="ui-filtertab-amount">17 574 €</span>
         <span class="ui-filtertab-count">6 factures</span>
       </span>
     </a>
     …
   </nav>

   <div class="ui-split">
     <section class="ui-worklist" aria-label="Factures en retard">
       <div class="ui-worklist-bar">
         <label class="ui-worklist-search">
           <i class="bi bi-search" aria-hidden="true"></i>
           <span class="visually-hidden">Rechercher</span>
           <input type="search" placeholder="Client, numéro…">
         </label>
         <div class="ui-worklist-filters"><select class="ui-select ui-select--sm">…</select></div>
         <span class="ui-worklist-count">6 factures</span>
       </div>
       <div class="ui-worklist-scroll">
         <table class="ui-table">
           <thead><tr><th scope="col">Client</th><th scope="col" class="is-numeric">Reste dû</th><th scope="col"><span class="visually-hidden">Actions</span></th></tr></thead>
           <tbody><tr>
             <td data-label="Client">Meyer Conseil <span class="ui-ref">FA-2026-023</span></td>
             <td data-label="Reste dû" class="is-numeric">4 428,00 €</td>
             <td class="is-actions"><div class="ui-row-actions">
               <button class="ui-btn ui-btn--sm ui-btn--secondary" type="button">Relancer</button>
             </div></td>
           </tr></tbody>
         </table>
       </div>
     </section>
     <aside class="ui-sidepanel" aria-labelledby="detail-titre" hidden>…</aside>
   </div>

   Vue « Statistiques » : la meme .ui-page-head (aria-current sur l'autre
   onglet), puis une grille .ui-kpis de .ui-kpi, puis des .ui-chart-card.

   Regles : une seule .ui-btn--primary par ecran ; la .ui-page-head est le
   premier element de la page (sur telephone elle se cale a cote du bouton de
   menu) ; un etat ne passe jamais par la couleur seule (mot + couleur).
   ========================================================================== */

/* ---------- Tete de page : titre, vues, actions ----------------------------
   Remplace l'en-tete du chassis ({% block page_title %}) pour les outils
   repris : ne pas declarer les deux.
   ---------------------------------------------------------------------------- */

.ui-page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--stack-gap);
}

/*  Titre et vues alignes sur la ligne de base, comme la maquette. */
.ui-page-head-main {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  min-width: 0;
}

.ui-page-head-title {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--text-title-1);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  line-height: 1.2;
}

/* Phrase d'aide facultative, sous le titre : une ligne, pas un paragraphe. */
.ui-page-head-sub {
  flex-basis: 100%;
  margin: calc(-1 * var(--space-1)) 0 0;
  color: var(--ink-muted);
  font-size: 14px;
}

.ui-page-head-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* ---------- Vues de l'outil (Liste / Statistiques) -------------------------- */

.ui-viewnav {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.ui-viewnav::-webkit-scrollbar { display: none; }

/*  Au telephone, les vues passent a la ligne : en defilement, la derniere
    (« Statistiques », « Temps passé ») etait coupee sans rien qui le dise,
    et la rangee elargissait la page de Devis et factures (415 px pour 390). */
@media (max-width: 640px) {
  .ui-viewnav {
    display: flex;
    flex-wrap: wrap;
    overflow-x: visible;
  }
}

.ui-viewnav-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  /* Maquette : 6 px 10 px autour d'un texte de 14 px, soit 30 px. */
  height: 30px;
  padding: 0 10px;
  border-radius: 8px;
  color: var(--ink-muted);
  font-size: 14px;
  font-weight: var(--weight-regular);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease),
              color var(--duration-fast) var(--ease);
}

.ui-viewnav-item:hover { background: rgba(22, 24, 29, 0.045); color: var(--ink); }
.ui-viewnav-item:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.ui-viewnav-item[aria-current="page"],
.ui-viewnav-item.is-current {
  background: var(--surface);
  box-shadow: var(--shadow-1);
  color: var(--ink);
  font-weight: var(--weight-medium);
}

/*  L'onglet courant passe en graisse moyenne, donc s'elargit de quelques
    pixels : ses voisins glissaient a chaque changement de vue. Avec
    `data-libelle` (le libelle repete), chaque onglet reserve des le depart
    la largeur de sa version courante : un fantome invisible, de hauteur
    nulle, sous le texte. */
.ui-viewnav-item[data-libelle] { flex-direction: column; justify-content: center; gap: 0; }

.ui-viewnav-item[data-libelle]::after {
  content: attr(data-libelle);
  height: 0;
  overflow: hidden;
  visibility: hidden;
  font-weight: var(--weight-medium);
  pointer-events: none;
  user-select: none;
}

/* ---------- Onglets-filtres de la liste de travail -------------------------
   Un lien par file, avec son montant et son nombre. Des liens et non des
   boutons : la file passe par l'adresse, elle se partage et survit au retour.
   L'element courant porte aria-current="true" (ou .is-current).
   `--danger`, `--warning`, `--success` colorent le montant ; le libelle dit
   toujours l'etat en toutes lettres.
   `.ui-filtertabs--compact` : une rangee de pastilles « En retard 6 · 17 574 € ».
   ---------------------------------------------------------------------------- */

.ui-filtertabs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--stack-gap);
}

.ui-filtertab {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  min-width: 0;
  padding: 14px var(--space-4);
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  transition: border-color var(--duration-fast) var(--ease),
              box-shadow var(--duration-fast) var(--ease);
}

.ui-filtertab:hover { border-color: var(--border-strong); color: var(--ink); }
.ui-filtertab:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Le liseré de 1,5 px passe par une ombre interne : aucun saut de mise en page. */
.ui-filtertab[aria-current="true"],
.ui-filtertab[aria-current="page"],
.ui-filtertab.is-current {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 0.5px var(--accent), var(--shadow-1);
}

.ui-filtertab-label {
  max-width: 100%;
  overflow: hidden;
  color: var(--ink-secondary);
  font-size: 14px;
  font-weight: var(--weight-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ui-filtertab-figures {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px var(--space-2);
}

.ui-filtertab-amount {
  color: var(--ink);
  font-size: 22px;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1.15;
  white-space: nowrap;
}

.ui-filtertab-count {
  color: var(--ink-muted);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ui-filtertab--danger  .ui-filtertab-amount { color: var(--danger); }
.ui-filtertab--warning .ui-filtertab-amount { color: var(--warning-ink); }
.ui-filtertab--success .ui-filtertab-amount { color: var(--success); }

/* Variante compacte : une rangee de pastilles, pour les listes sans montant. */
.ui-filtertabs--compact {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.ui-filtertabs--compact .ui-filtertab {
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
  height: var(--control-md);
  padding: 0 14px;
  border-radius: var(--radius-pill);
}

.ui-filtertabs--compact .ui-filtertab-label { color: var(--ink); }
.ui-filtertabs--compact .ui-filtertab-figures { flex-wrap: nowrap; gap: 6px; }

.ui-filtertabs--compact .ui-filtertab-amount {
  font-size: 14px;
  font-weight: var(--weight-medium);
  letter-spacing: 0;
}

.ui-filtertabs--compact .ui-filtertab-amount::before {
  content: "·";
  margin-right: 6px;
  color: var(--ink-faint);
}

/* ---------- Liste de travail ------------------------------------------------
   Une carte blanche : barre de recherche et de filtres, eventuelle note,
   tableau, pagination (.ui-pagination). Le tableau est un .ui-table.
   ---------------------------------------------------------------------------- */

.ui-worklist {
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.ui-worklist-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
}

.ui-worklist-search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 240px;
  min-width: 0;
  max-width: 360px;
}

.ui-worklist-search i {
  position: absolute;
  left: 12px;
  color: var(--ink-muted);
  font-size: 15px;
  pointer-events: none;
}

.ui-worklist-search input {
  width: 100%;
  height: var(--control-md);
  padding: 0 12px 0 36px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-field);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px;
}

.ui-worklist-search input::placeholder { color: var(--ink-muted); opacity: 0.8; }

.ui-worklist-search input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring-field);
}

.ui-worklist-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* Champ de liste a la hauteur de la barre. */
.ui-select--sm {
  width: auto;
  min-height: var(--control-md);
  line-height: calc(var(--control-md) - 2px);
  font-size: 14px;
}

.ui-worklist-count {
  margin-left: auto;
  color: var(--ink-muted);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Une phrase de contexte sous la barre (« Stackly ne voit pas votre banque »). */
.ui-worklist-note {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--border);
  background: var(--surface-sunken);
  color: var(--ink-secondary);
  font-size: 14px;
}

/* Seul le tableau defile, jamais la page. */
.ui-worklist-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/*  Tableau d'une liste de travail (maquettes V2) : en-tete de 40 px en
    13 px, cellules de 15 px avec 12 px de marge, 20 px aux deux bords,
    filet --border entre les lignes. */
.ui-worklist .ui-table thead th { padding: 0 var(--space-3); }

.ui-worklist .ui-table tbody td {
  height: auto;
  padding: var(--space-3);
  font-size: 15px;
  border-bottom-color: var(--border);
}

.ui-worklist .ui-table thead th:first-child,
.ui-worklist .ui-table tbody td:first-child { padding-left: var(--space-5); }

.ui-worklist .ui-table thead th:last-child,
.ui-worklist .ui-table tbody td:last-child { padding-right: var(--space-5); }

.ui-worklist .ui-pagination { background: var(--surface); }

/* La ligne ouverte dans le panneau lateral. */
.ui-worklist .ui-table tr.is-open td { background: var(--accent-tint-2); }
.ui-worklist .ui-table tr.is-open td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

/* Reference de piece (FA-2026-023) : chiffres a chasse fixe, lisibles. */
.ui-ref {
  display: inline-block;
  color: var(--ink-secondary);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* ---------- Actions de ligne -------------------------------------------------
   Toujours visibles, comme sur les maquettes V2 : « Encaisser », « Relancer »,
   « Facturer » sont l'action principale de la ligne, pas un detail a
   decouvrir au survol. Boutons .ui-btn--sm (36 px), 6 px entre eux.
   ---------------------------------------------------------------------------- */

.ui-table td.is-actions {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}

.ui-row-actions {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
}

/* ---------- Bascule segmentee (periode, mode) -------------------------------
   <div class="ui-seg" role="group" aria-label="Période">
     <button type="button" class="ui-seg-item" aria-pressed="true">Année</button>
   </div>
   ---------------------------------------------------------------------------- */

.ui-seg {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-button);
  background: var(--surface);
}

.ui-seg-item {
  height: 32px;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-muted);
  font-family: var(--font-ui);
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}

.ui-seg-item:hover { color: var(--ink); }
.ui-seg-item:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.ui-seg-item[aria-pressed="true"],
.ui-seg-item[aria-current="page"],
.ui-seg-item.is-current {
  background: var(--surface-sunken);
  color: var(--ink);
  font-weight: var(--weight-medium);
}

/* ---------- Chiffres cles (onglet Statistiques) ------------------------------
   <div class="ui-kpis">
     <article class="ui-kpi">
       <p class="ui-kpi-label">Encaissé depuis janvier</p>
       <p class="ui-kpi-value">70 200 €</p>
       <p class="ui-kpi-foot ui-kpi-foot--up">+11 % sur 2025 à la même date</p>
     </article>
   </div>
   Un graphique miniature se pose dans .ui-kpi-row a cote de la valeur.
   ---------------------------------------------------------------------------- */

.ui-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--stack-gap);
}

.ui-kpi {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: var(--space-4) 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.ui-kpi-label {
  margin: 0;
  color: var(--ink-muted);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
}

.ui-kpi-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-2);
}

.ui-kpi-value {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--text-title-1);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.ui-kpi-value--danger  { color: var(--danger); }
.ui-kpi-value--warning { color: var(--warning-ink); }

.ui-kpi-foot {
  margin: 0;
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.ui-kpi-foot--up   { color: var(--success); }
.ui-kpi-foot--down { color: var(--danger); }

.ui-kpi-spark { flex-shrink: 0; width: 88px; height: 30px; color: var(--accent); }

/* ---------- Carte de graphique ----------------------------------------------
   <section class="ui-chart-card" aria-labelledby="g1">
     <header class="ui-chart-card-head">
       <div>
         <h2 class="ui-chart-card-title" id="g1">Facturé et encaissé en 2026</h2>
         <p class="ui-chart-card-sub">Cumulés, toutes taxes comprises</p>
       </div>
       <ul class="ui-chart-legend">
         <li class="ui-chart-legend-item"><span class="ui-chart-swatch" data-series="1"></span>Facturé</li>
       </ul>
     </header>
     <div class="ui-chart-card-body">… canvas ou svg …</div>
   </section>
   Les series suivent --data-1 a --data-5, dans cet ordre.
   ---------------------------------------------------------------------------- */

.ui-chart-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding: 18px var(--space-5);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

.ui-chart-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.ui-chart-card-title {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--text-title-3);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  line-height: 1.3;
}

.ui-chart-card-sub {
  margin: 2px 0 0;
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.ui-chart-card-body {
  position: relative;
  min-height: 220px;
}

.ui-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink-secondary);
  font-size: var(--text-sm);
}

.ui-chart-legend-item { display: inline-flex; align-items: center; gap: 6px; }

.ui-chart-swatch {
  flex-shrink: 0;
  width: 12px;
  height: 12px;
  border-radius: 3px;
  background: var(--accent);
}

.ui-chart-swatch[data-series="1"] { background: var(--data-1); }
.ui-chart-swatch[data-series="2"] { background: var(--data-2); }
.ui-chart-swatch[data-series="3"] { background: var(--data-3); }
.ui-chart-swatch[data-series="4"] { background: var(--data-4); }
.ui-chart-swatch[data-series="5"] { background: var(--data-5); }
.ui-chart-swatch[data-series="muted"] { background: var(--border-strong); }

/* ---------- Panneau lateral de detail ----------------------------------------
   <div class="ui-split">
     <section class="ui-worklist">…</section>
     <aside class="ui-sidepanel" aria-labelledby="sp-titre">
       <header class="ui-sidepanel-head">
         <div>
           <p class="ui-sidepanel-kicker">FA-2026-023 · Meyer Conseil</p>
           <h2 class="ui-sidepanel-title" id="sp-titre">Enregistrer un paiement</h2>
         </div>
         <button type="button" class="ui-sidepanel-close" aria-label="Fermer le panneau">
           <i class="bi bi-x-lg" aria-hidden="true"></i></button>
       </header>
       <div class="ui-sidepanel-body">…</div>
       <footer class="ui-sidepanel-foot">…</footer>
     </aside>
   </div>
   Au bureau il s'ouvre a droite de la liste ; sous 1200 px il devient une
   feuille qui glisse par-dessus la page. Ferme : attribut `hidden`.
   ---------------------------------------------------------------------------- */

.ui-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  align-items: start;
  gap: var(--space-4);
}

.ui-split:not(:has(> .ui-sidepanel:not([hidden]))) {
  grid-template-columns: minmax(0, 1fr);
}

.ui-sidepanel {
  position: sticky;
  top: var(--space-6);
  display: flex;
  flex-direction: column;
  min-width: 0;
  max-height: calc(100vh - var(--space-12));
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  box-shadow: var(--shadow-3);
}

.ui-sidepanel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-5) var(--space-3);
}

.ui-sidepanel-kicker {
  margin: 0 0 4px;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.ui-sidepanel-title {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--text-title-2);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--track-title);
  line-height: 1.3;
}

.ui-sidepanel-close {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--control-sm);
  height: var(--control-sm);
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: var(--surface-sunken);
  color: var(--ink-secondary);
  cursor: pointer;
}

.ui-sidepanel-close:hover { color: var(--ink); background: var(--border); }
.ui-sidepanel-close:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.ui-sidepanel-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
  padding: var(--space-2) var(--space-5) var(--space-5);
  overflow-y: auto;
}

.ui-sidepanel-foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border);
}

.ui-sidepanel-foot .ui-btn { flex: 1 1 auto; }

/* Voile de la feuille, sous 1200 px seulement. */
.ui-sidepanel-backdrop { display: none; }

@media (max-width: 1200px) {
  .ui-split { grid-template-columns: minmax(0, 1fr); }

  .ui-sidepanel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-modal);
    width: min(400px, 100%);
    max-height: none;
    border-radius: 0;
    border-width: 0 0 0 1px;
  }

  .ui-sidepanel-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: calc(var(--z-modal) - 1);
    background: var(--overlay);
  }

  .ui-sidepanel[hidden] + .ui-sidepanel-backdrop,
  .ui-sidepanel-backdrop[hidden] { display: none; }
}

/* ---------- Telephone ---------------------------------------------------------- */

@media (max-width: 992px) {
  /*  Sans en-tete de chassis, la tete de page se cale a droite du bouton de
      menu plutot que de s'empiler dessous. */
  .main-content--bare .content-wrapper:has(.ui-page-head) { padding-top: var(--space-3); }
  .main-content--bare .ui-page-head-main { padding-left: 56px; min-height: var(--touch-target); }

  .ui-viewnav-item,
  .ui-seg-item { height: var(--touch-target); }

  .ui-row-actions { opacity: 1; }
  .ui-row-actions .ui-btn { height: var(--touch-target); }

  .ui-sidepanel-close { width: var(--touch-target); height: var(--touch-target); }
}

@media (max-width: 768px) {
  .ui-page-head-title { font-size: var(--text-title-1); }

  .ui-page-head-actions { width: 100%; }
  .ui-page-head-actions .ui-btn { flex: 1 1 auto; }

  /*  Les onglets-filtres defilent lateralement, aimantes : quatre cartes ne
      tiennent pas a 390 px, et les empiler repousserait la liste hors ecran. */
  .ui-filtertabs {
    display: flex;
    margin-right: calc(-1 * var(--gutter-page));
    padding-right: var(--gutter-page);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }

  .ui-filtertabs::-webkit-scrollbar { display: none; }

  .ui-filtertabs > .ui-filtertab {
    flex: 0 0 auto;
    min-width: 160px;
    scroll-snap-align: start;
  }

  .ui-filtertabs--compact .ui-filtertab { min-width: 0; height: var(--touch-target); }

  .ui-worklist-search { flex-basis: 100%; max-width: none; }
  .ui-worklist-search input { height: var(--touch-target); }
  .ui-worklist-count { margin-left: 0; }

  /*  Liste en cartes empilees (avec .ui-table--stack sur le tableau) : la
      carte exterieure s'efface, la barre de recherche garde la sienne. */
  .ui-worklist:has(.ui-table) .ui-worklist-scroll { overflow-x: auto; }

  .ui-worklist:has(.ui-table--stack) {
    overflow: visible;
    border: 0;
    background: transparent;
  }

  .ui-worklist:has(.ui-table--stack) .ui-worklist-bar {
    margin-bottom: var(--space-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-card);
    background: var(--surface);
  }

  /*  Toutes les cellules, pas seulement la premiere et la derniere : la
      regle de la liste de travail (12 px de chaque cote) l'emportait sur
      celle des cartes et decalait la premiere ligne de chaque carte. */
  .ui-worklist .ui-table--stack tbody td,
  .ui-worklist .ui-table--stack tbody td:first-child,
  .ui-worklist .ui-table--stack tbody td:last-child { padding-left: 0; padding-right: 0; }

  .ui-worklist .ui-table--stack td.is-actions { width: auto; justify-content: flex-end; }

  .ui-worklist .ui-table--stack tbody tr.is-open { background: var(--accent-tint-2); border-color: var(--accent); }
  .ui-worklist .ui-table--stack tbody tr.is-open td,
  .ui-worklist .ui-table--stack tbody tr.is-open td:first-child { background: transparent; box-shadow: none; }

  .ui-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
  .ui-kpi { padding: 14px var(--space-4); }
  .ui-kpi-value { font-size: 22px; }

  .ui-chart-card { padding: var(--space-4); }
}

@media (max-width: 420px) {
  .ui-kpis { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
  .ui-row-actions,
  .ui-filtertab,
  .ui-viewnav-item { transition: none; }
}

/*  UN LIEN SANS CLASSE.
    Sans regle, il gardait le bleu souligne du navigateur (Agenda, bon de
    commande, fiche client, fenetre « Ajouter un ouvrage ») : l'encre de
    l'outil, soulignee au survol. :where() garde la specificite a zero, toute
    regle d'un module l'emporte. */
:where(a:not([class])) {
  color: var(--accent-ink);
  text-decoration: none;
}
:where(a:not([class])):hover { text-decoration: underline; }
:where(a:not([class])):focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 2px; }
