/* Langage visuel commun de TSIM — tout écran l'utilise ; une couleur ne s'écrit qu'ici.
   Cotes en px (converties des rem d'origine, pensés pour une base de 16 px) : le thème pose
   `html { font-size: 13px }`, qui rapetissait tout d'un cinquième par rapport aux maquettes.
   Jetons repris des maquettes validées le 2026-10-02. Dérivés de Metronic quand une variable
   existe, pour suivre le thème sombre ; les teintes d'état n'ont pas d'équivalent Metronic, elles
   sont donc redéclarées sous [data-bs-theme="dark"]. */
:root {
    --tsim-surface: var(--bs-body-bg, #ffffff);
    --tsim-page: var(--bs-gray-100, #f5f8fa);
    --tsim-border: var(--bs-gray-300, #e4e6ef);
    --tsim-text: var(--bs-gray-900, #181c32);
    --tsim-muted: var(--bs-gray-700, #5e6278);
    --tsim-primary: #0b5fd1;
    --tsim-primary-hover: #084aa3;
    --tsim-primary-soft: #e9f3ff;
    /* Teinte à peine perceptible de la ligne « par défaut » (maquette Main). */
    --tsim-primary-faint: #fbfcff;
    --tsim-chip-bg: #f1f6ff;
    --tsim-ok: #0f7a3d;
    --tsim-ok-soft: #e8fff3;
    --tsim-warn: #7a5a00;
    --tsim-warn-soft: #fff8dd;
    --tsim-ko: #b0103a;
    --tsim-ko-soft: #ffeef3;
    /* Texte d'un refus sur fond --tsim-ko-soft (maquette Refus). */
    --tsim-ko-text: #7a0a27;
    /* Page assombrie derrière une modale (maquette Refus). */
    --tsim-backdrop: rgba(107, 112, 128, 0.85);
    --tsim-dot-running: #17a34a;
    --tsim-dot-stopped: #a1a5b7;
    --tsim-console-background: #1e1e2d;
    --tsim-console-text: #cdd0de;
    --tsim-radius: 12px;
    /* Jetons des maquettes Secrets (2026-10-03). */
    --tsim-placeholder: #a1a5b7;
    --tsim-text-secondary: #3f4254;
    --tsim-row-selected: #f4f8ff;
    --tsim-warn-dot: #e0a800;
    --tsim-warn-border: #e8c96a;
    --tsim-dropzone-border: #c9d6ea;
    --tsim-dropzone-background: #f8fbff;
    /* Étiquette du placeholder `{{ parentDomain }}` (maquettes Secrets — mode fichier). */
    --tsim-code-placeholder-background: #fff4e5;
    --tsim-code-placeholder-text: #8a4b00;
    /* Barre flottante sombre (sélection, application d'un import). */
    --tsim-inverse-surface: #181c32;
    --tsim-inverse-text: #ffffff;
    --tsim-inverse-muted: #cdd0de;
    --tsim-inverse-border: rgba(255, 255, 255, 0.24);
    --tsim-inverse-field: rgba(255, 255, 255, 0.08);
    --tsim-shadow-raised: 0 1px 2px rgba(24, 28, 50, 0.08);
    --tsim-shadow-floating: 0 12px 32px rgba(24, 28, 50, 0.24);
    --tsim-shadow-dialog: 0 24px 48px rgba(24, 28, 50, 0.25);
    --tsim-font-sans: system-ui, -apple-system, "Segoe UI", sans-serif;
    --tsim-font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* Écran calé au pixel sur ses maquettes : les jetons de base prennent les valeurs exactes des
   maquettes au lieu de celles de Metronic, qui en diffèrent légèrement (#f9f9f9, #dbdfe9…). En
   thème clair seulement — le thème sombre garde ses dérivés Metronic, les maquettes n'en ont pas. */
:root:not([data-bs-theme="dark"]) .tsim-exact {
    --tsim-surface: #ffffff;
    --tsim-page: #f5f8fa;
    --tsim-border: #e4e6ef;
    --tsim-text: #181c32;
    --tsim-muted: #5e6278;
}

/* Le fond de page suit : les maquettes posent leurs cartes sur #f5f8fa, pas sur #fcfcfc. */
:root:not([data-bs-theme="dark"]) body:has(.tsim-exact) {
    --bs-app-bg-color: #f5f8fa;
}

/* L'en-tête est fixe (`data-kt-app-header-fixed` sur le body), mais Metronic le laisse transparent
   en thème clair : il ne lui donne un fond qu'en mode « sticky », que ce layout n'active pas. La
   page défilait donc sous le nom et le bouton Déconnexion. Fond « minimisé » du thème, défini en
   clair (#ffffff) comme en sombre (#0D0E12). */
[data-kt-app-header-fixed=true] .app-header {
    background-color: var(--bs-app-header-minimize-bg-color);
    box-shadow: var(--bs-app-header-minimize-box-shadow);
}

[data-bs-theme="dark"] {
    --tsim-primary: #6ea8fe;
    --tsim-primary-hover: #9ec5fe;
    --tsim-primary-soft: rgba(110, 168, 254, 0.14);
    --tsim-primary-faint: rgba(110, 168, 254, 0.05);
    --tsim-chip-bg: rgba(110, 168, 254, 0.1);
    --tsim-ok: #5fd68a;
    --tsim-ok-soft: rgba(95, 214, 138, 0.14);
    --tsim-warn: #f2c94c;
    --tsim-warn-soft: rgba(242, 201, 76, 0.14);
    --tsim-ko: #ff7a9c;
    --tsim-ko-soft: rgba(255, 122, 156, 0.14);
    --tsim-ko-text: #ffb3c4;
    --tsim-backdrop: rgba(0, 0, 0, 0.7);
    --tsim-placeholder: #7e8299;
    --tsim-text-secondary: #cdd0de;
    --tsim-row-selected: rgba(110, 168, 254, 0.08);
    --tsim-warn-border: rgba(242, 201, 76, 0.5);
    --tsim-dropzone-border: rgba(110, 168, 254, 0.4);
    --tsim-dropzone-background: rgba(110, 168, 254, 0.05);
    --tsim-code-placeholder-background: rgba(242, 201, 76, 0.14);
    --tsim-code-placeholder-text: #f2c94c;
    --tsim-inverse-surface: #2b2d3a;
}

.tsim-card__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 24px 28px 8px;
}

.tsim-card__title {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    color: var(--tsim-text);
}

.tsim-card__header--separated {
    padding-bottom: 20px;
    border-bottom: 1px solid var(--tsim-border);
}

.tsim-card__subtitle {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-page-header__breadcrumb {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-page-header__breadcrumb a,
.tsim-link {
    color: var(--tsim-primary);
    text-decoration: none;
}

.tsim-page-header__breadcrumb a:hover,
.tsim-link:hover {
    color: var(--tsim-primary-hover);
}

.tsim-page-header__titleline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.tsim-page-header__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.tsim-grid {
    padding: 8px 28px 24px;
}

.tsim-grid__head,
.tsim-grid__row {
    display: grid;
    gap: 0 16px;
    align-items: center;
    padding: 14px 0;
    border-bottom: 1px dashed var(--tsim-border);
}

.tsim-grid__row {
    font-size: 14px;
}

.tsim-grid__row > * {
    min-width: 0;
}

.tsim-grid__head {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tsim-muted);
}

.tsim-grid__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
}

.tsim-stack {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.tsim-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.tsim-row--default {
    background: var(--tsim-primary-faint);
}

.tsim-row--missing {
    opacity: 0.6;
}

.tsim-dot {
    display: inline-block;
    flex: none;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    background: var(--tsim-dot-stopped);
}

.tsim-dot--running {
    background: var(--tsim-dot-running);
}

.tsim-dot--stopped {
    background: var(--tsim-dot-stopped);
}

.tsim-chip {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--tsim-chip-bg);
    color: var(--tsim-primary);
    font-family: var(--bs-font-monospace, ui-monospace, monospace);
    font-size: 13px;
    text-decoration: none;
}

.tsim-chip:hover {
    color: var(--tsim-primary-hover);
}

.tsim-badge-default {
    padding: 2px 7px;
    border-radius: 6px;
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
}

.tsim-mono { font-family: var(--bs-font-monospace, ui-monospace, monospace); }
.tsim-muted { color: var(--tsim-muted); font-size: 12px; }
.tsim-warn-text { color: var(--tsim-warn); }

/* Encadré d'information ; --ok pour une réussite, --warn et --ko pour les avertissements et les refus. */
.tsim-callout {
    padding: 14px 18px;
    border-radius: 8px;
    border: 1px solid var(--tsim-primary);
    background: var(--tsim-primary-soft);
    color: var(--tsim-text);
}

.tsim-callout--ok {
    border-color: var(--tsim-ok);
    background: var(--tsim-ok-soft);
}

.tsim-callout--warn {
    border-color: var(--tsim-warn);
    background: var(--tsim-warn-soft);
}

.tsim-callout--ko {
    border-color: var(--tsim-ko);
    background: var(--tsim-ko-soft);
}

/* Motif d'un refus : texte du serveur, en clair ; une liste de fichiers, un par ligne. */
.tsim-refusal {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px 16px;
    border-radius: 10px;
    background: var(--tsim-ko-soft);
    color: var(--tsim-ko-text);
    overflow-wrap: anywhere;
}

.tsim-refusal__text {
    margin: 0;
    white-space: pre-line;
}

.tsim-refusal__files {
    margin: 0;
    padding: 0;
    list-style: none;
    font-family: var(--bs-font-monospace, ui-monospace, monospace);
    font-size: 13px;
}

/* Étapes d'une opération : pastille ronde de 26 px + libellé. */
.tsim-steps {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tsim-steps > li {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 14px;
}

.tsim-step-icon {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    font-size: 12px;
    font-weight: 700;
    background: var(--tsim-page);
    color: var(--tsim-muted);
}

.tsim-step-icon--done { background: var(--tsim-ok-soft); color: var(--tsim-ok); }
.tsim-step-icon--running { background: var(--tsim-primary-soft); color: var(--tsim-primary); }
.tsim-step-icon--pending { background: var(--tsim-page); color: var(--tsim-muted); }
.tsim-step-icon--failed { background: var(--tsim-ko-soft); color: var(--tsim-ko); }

.tsim-console {
    margin: 0;
    padding: 16px;
    border-radius: 8px;
    background: var(--tsim-console-background);
    color: var(--tsim-console-text);
    font-family: var(--bs-font-monospace, ui-monospace, monospace);
    font-size: 12px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 352px;
    overflow-y: auto;
}

/* Bouton bascule : cible tactile de 44 px au moins ; l'état actif se lit dans aria-pressed. */
.tsim-toggle {
    min-height: 44px;
    min-width: 44px;
    padding: 0 16px;
    border: 1px solid var(--tsim-border);
    border-radius: 8px;
    background: var(--tsim-surface);
    color: var(--tsim-text);
    font-weight: 600;
    cursor: pointer;
}

.tsim-toggle[aria-pressed="true"] {
    border-color: var(--tsim-primary);
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

/* Coche décorative : l'état est déjà dit par aria-pressed, la coche n'entre pas dans le nom. */
.tsim-toggle[aria-pressed="true"]::before {
    content: "✓ ";
    content: "✓ " / "";
}

.tsim-toggle:disabled {
    cursor: not-allowed;
    opacity: 0.65;
}

.tsim-toggle:focus-visible,
.tsim-callout:focus-visible {
    outline: 2px solid var(--tsim-primary);
    outline-offset: 2px;
}

/* Corps de carte en colonne ; titre de section porté par .tsim-card__title. */
.tsim-card__body {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 20px 24px;
}

/* Formulaire en sections : libellé à gauche (160 px), commande à droite. */
.tsim-fields {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr);
    gap: 12px 16px;
    align-items: center;
    font-size: 14px;
}

.tsim-fields__label {
    color: var(--tsim-muted);
}

.tsim-fields__control {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

/* Ligne pleine largeur dans une grille de champs : un avertissement qui vaut pour la ligne au-dessus. */
.tsim-fields__wide {
    grid-column: 1 / -1;
}

/* Cible tactile de 44 px pour les commandes de formulaire et les boutons d'action. */
.tsim-control {
    min-height: 44px;
}

/* Liste des étapes prévues (plan) : numérotée, aérée. */
.tsim-plan {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding-left: 20px;
    font-size: 14px;
    color: var(--tsim-text);
}

@media (max-width: 991px) {
    .tsim-grid__head { display: none; }
    .tsim-grid__row { grid-template-columns: 1fr; gap: 8px; }
    .tsim-grid__actions { justify-content: flex-start; }
    .tsim-fields { grid-template-columns: 1fr; gap: 6px; }
    .tsim-card__header,
    .tsim-grid { padding-left: 16px; padding-right: 16px; }
}


/* ============================================================================================
   SOCLE DES ÉCRANS — composants au pixel des maquettes validées (Secrets, 2026-10-03), repris par
   tous les écrans (plan : docs/superpowers/plans/2026-10-03-harmonisation-graphique.md).

   Cotes en px, jamais en rem : le thème pose `html { font-size: 13px }`, qui décalerait tout ce
   qui serait exprimé en rem. Un écran pose `.tsim-screen` sur sa racine, et `.tsim-exact` pour
   que les jetons de base prennent les valeurs exactes des maquettes.
   ============================================================================================ */


/* --------------------------------------------------------------------------------------------
   Socle
   -------------------------------------------------------------------------------------------- */

.tsim-screen {
    display: flex;
    flex-direction: column;
    gap: 20px;
    color: var(--tsim-text);
    font-family: var(--tsim-font-sans);
    font-size: 16px;
    line-height: normal;
}

.tsim-screen a:not(.tsim-button) {
    color: var(--tsim-primary);
}

.tsim-screen a:not(.tsim-button):hover {
    color: var(--tsim-primary-hover);
}

.tsim-checkbox {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--tsim-primary);
    cursor: pointer;
}

/* --------------------------------------------------------------------------------------------
   En-tête de page
   -------------------------------------------------------------------------------------------- */

.tsim-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
}

.tsim-page-header__text {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tsim-page-header__breadcrumb,
.tsim-page-header__subtitle {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-page-header__breadcrumb a {
    text-decoration: none;
}

.tsim-page-header__title {
    margin: 0;
    font-size: 24px;
    font-weight: 700;
    color: var(--tsim-text);
}

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

.tsim-button {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: 36px;
    padding: 0 12px;
    border: 0;
    border-radius: 8px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    line-height: normal;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.tsim-button--page {
    height: 40px;
    padding: 0 16px;
    font-size: 14px;
}

.tsim-button--large {
    height: 44px;
    padding: 0 18px;
    font-size: 14px;
}

.tsim-button--row {
    padding: 0 14px;
}

.tsim-button--small {
    height: 34px;
    padding: 0 10px;
    font-size: 12px;
}

.tsim-button--soft {
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

.tsim-button--soft:hover {
    color: var(--tsim-primary-hover);
}

.tsim-button--outline {
    gap: 6px;
    border: 1px solid var(--tsim-border);
    background: var(--tsim-surface);
    color: var(--tsim-text);
}

.tsim-button--outline.tsim-button--large,
.tsim-button--outline.tsim-button--page {
    padding: 0 16px;
}

.tsim-button--quiet {
    background: var(--tsim-page);
    color: var(--tsim-text);
}

.tsim-button--primary {
    background: var(--tsim-primary);
    color: #ffffff;
    font-weight: 700;
}

.tsim-button--primary:hover {
    background: var(--tsim-primary-hover);
    color: #ffffff;
}

/* Sur la barre sombre : bouton plein blanc, et bouton au trait translucide. */
.tsim-button--inverse {
    height: 40px;
    padding: 0 18px;
    background: var(--tsim-inverse-text);
    color: var(--tsim-primary);
    font-size: 14px;
    font-weight: 700;
}

.tsim-button--inverse-outline {
    height: 40px;
    padding: 0 14px;
    border: 1px solid var(--tsim-inverse-border);
    background: transparent;
    color: var(--tsim-inverse-text);
}

/* Au trait de la couleur primaire : l'action secondaire d'une ligne (« Gérer »). */
.tsim-button--outline-primary {
    border: 1px solid var(--tsim-primary);
    background: transparent;
    color: var(--tsim-primary);
}

.tsim-button--outline-primary:hover {
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

/* Geste destructeur : teinte de refus, jamais pleine — la confirmation porte le poids. */
.tsim-button--danger-soft {
    background: var(--tsim-ko-soft);
    color: var(--tsim-ko);
}

.tsim-button--danger-soft:hover {
    color: var(--tsim-ko-text);
}

.tsim-button:disabled {
    cursor: not-allowed;
    opacity: 0.65;
}

/* Bouton carré à icône seule : son nom accessible est porté par `aria-label`. */
.tsim-icon-button {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--tsim-border);
    border-radius: 8px;
    background: var(--tsim-surface);
    color: var(--tsim-muted);
    cursor: pointer;
}

.tsim-icon-button--primary {
    border-color: transparent;
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

.tsim-icon-button--danger {
    border-color: transparent;
    background: var(--tsim-ko-soft);
    color: var(--tsim-ko);
}

.tsim-icon-button:hover {
    color: var(--tsim-text);
}

/* --------------------------------------------------------------------------------------------
   Pastilles
   -------------------------------------------------------------------------------------------- */

.tsim-pill {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    line-height: normal;
    white-space: nowrap;
}

.tsim-pill--compact {
    padding: 3px 8px;
}

.tsim-pill--ok { background: var(--tsim-ok-soft); color: var(--tsim-ok); }
.tsim-pill--warn { background: var(--tsim-warn-soft); color: var(--tsim-warn); }
.tsim-pill--ko { background: var(--tsim-ko-soft); color: var(--tsim-ko); }
.tsim-pill--info { background: var(--tsim-primary-soft); color: var(--tsim-primary); }
.tsim-pill--muted { background: var(--tsim-page); color: var(--tsim-muted); }

.tsim-pill--outline {
    border: 1px solid var(--tsim-border);
    background: var(--tsim-surface);
    color: var(--tsim-muted);
}

/* --------------------------------------------------------------------------------------------
   Tuiles de statut — décompte et filtre à la fois
   -------------------------------------------------------------------------------------------- */

.tsim-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
}

.tsim-tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-height: 44px;
    padding: 14px 18px;
    border: 1px solid var(--tsim-border);
    border-radius: 12px;
    background: var(--tsim-surface);
    font-family: inherit;
    line-height: normal;
    text-align: left;
    cursor: pointer;
}

.tsim-tile[aria-pressed="true"] {
    border-color: var(--tsim-primary);
    background: var(--tsim-primary-soft);
    box-shadow: inset 0 0 0 1px var(--tsim-primary);
}

.tsim-tile__label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--tsim-muted);
}

.tsim-tile__dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--tsim-placeholder);
}

.tsim-tile__dot--all { background: var(--tsim-primary); }
.tsim-tile__dot--ok { background: var(--tsim-dot-running); }
.tsim-tile__dot--warn { background: var(--tsim-warn-dot); }
.tsim-tile__dot--ko { background: var(--tsim-ko); }
.tsim-tile__dot--muted { background: var(--tsim-placeholder); }

.tsim-tile__count {
    font-size: 26px;
    font-weight: 700;
    color: var(--tsim-text);
}

.tsim-card {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--tsim-border);
    border-radius: 12px;
    background: var(--tsim-surface);
}

.tsim-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 20px 28px;
    border-bottom: 1px solid var(--tsim-border);
}

.tsim-toolbar__spacer,
.tsim-floating-bar__spacer {
    flex: 1 1 auto;
}

.tsim-toolbar__count {
    font-size: 13px;
    color: var(--tsim-muted);
    white-space: nowrap;
}

.tsim-search {
    position: relative;
    display: flex;
    flex: 0 1 380px;
    align-items: center;
    min-width: 220px;
    margin: 0;
}

.tsim-search__icon {
    position: absolute;
    left: 12px;
    display: flex;
    color: var(--tsim-muted);
    pointer-events: none;
}

.tsim-search__field,
.tsim-input {
    box-sizing: border-box;
    border: 1px solid var(--tsim-border);
    border-radius: 8px;
    background: var(--tsim-surface);
    color: var(--tsim-text);
    font-family: inherit;
    font-size: 14px;
}

.tsim-search__field {
    width: 100%;
    height: 40px;
    padding: 0 12px 0 36px;
}

.tsim-input {
    height: 44px;
    padding: 0 12px;
}

.tsim-input--mono {
    font-family: var(--tsim-font-mono);
}

.tsim-search__field:focus,
.tsim-input:focus {
    border-color: var(--tsim-primary);
    outline: none;
    box-shadow: 0 0 0 3px var(--tsim-primary-soft);
}

.tsim-field-label {
    margin: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--tsim-muted);
}

/* Commande segmentée : une option retenue, annoncée par `aria-pressed`. */
.tsim-segmented {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--tsim-border);
    border-radius: 10px;
    background: var(--tsim-page);
}

.tsim-segmented__option {
    height: 34px;
    padding: 0 14px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--tsim-muted);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.tsim-segmented__option[aria-pressed="true"] {
    background: var(--tsim-surface);
    color: var(--tsim-primary);
    box-shadow: var(--tsim-shadow-raised);
}

/* --------------------------------------------------------------------------------------------
   Tableau de l'inventaire
   -------------------------------------------------------------------------------------------- */

/*
 * UNE définition de pistes pour l'en-tête et les lignes : l'en-tête vit hors des `<details>` (replier
 * un groupe ne doit pas emporter la légende), donc en-tête et lignes ne sont jamais enfants d'une
 * même grille. Le bandeau de groupe garde la même première piste et le même retrait : sa case
 * tombe sur celle de ses lignes.
 *
 * Le nombre de pistes suit le nombre de cellules de `_inventory_row.html.twig` : une piste
 * manquante ne se voit pas comme une erreur, la cellule surnuméraire part sur une rangée implicite.
 */
.tsim-table {
    padding: 4px 28px 20px;
}

/* Les pistes sont celles de l'écran : il les pose par --tsim-table-columns sur son tableau. */
.tsim-table-grid {
    display: grid;
    grid-template-columns: var(--tsim-table-columns, minmax(0, 1fr));
    gap: 0 16px;
    align-items: center;
    padding: 12px;
}

.tsim-table__head {
    font-size: 12px;
    font-weight: 700;
    color: var(--tsim-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.tsim-cell-check {
    display: flex;
    justify-content: center;
}

.tsim-cell-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    text-align: right;
}

.tsim-group {
    margin-top: 8px;
    border: 1px solid var(--tsim-border);
    border-radius: 10px;
    overflow: hidden;
}

.tsim-group__band {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr) auto;
    gap: 0 16px;
    align-items: center;
    padding: 10px 12px;
    background: var(--tsim-page);
    list-style: none;
    cursor: pointer;
}

.tsim-group__band::-webkit-details-marker {
    display: none;
}

.tsim-group__heading {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    height: 36px;
    color: var(--tsim-text);
}

.tsim-group__name {
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
}

.tsim-group__path {
    overflow: hidden;
    font-family: var(--tsim-font-mono);
    font-size: 12px;
    color: var(--tsim-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.tsim-group__tally {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.tsim-group__more {
    margin-left: 6px;
}

/* --------------------------------------------------------------------------------------------
   Menus « … » (`popover` natif, placé par `tsim-menu.js`)
   -------------------------------------------------------------------------------------------- */

.tsim-menu {
    position: fixed;
    inset: auto;
    flex-direction: column;
    min-width: 240px;
    margin: 0;
    padding: 6px;
    border: 1px solid var(--tsim-border);
    border-radius: 10px;
    background: var(--tsim-surface);
    box-shadow: var(--tsim-shadow-floating);
    font-family: var(--tsim-font-sans);
}

.tsim-menu:popover-open {
    display: flex;
}

.tsim-menu__item {
    display: flex;
    align-items: center;
    height: 40px;
    padding: 0 12px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--tsim-text);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
}

.tsim-menu__item:hover {
    background: var(--tsim-page);
}

/* --------------------------------------------------------------------------------------------
   Barre flottante sombre — sélection pour l'export, application d'un import
   -------------------------------------------------------------------------------------------- */

.tsim-floating-bar {
    position: sticky;
    bottom: 16px;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 16px;
    padding: 14px 20px 14px 28px;
    border-radius: 12px;
    background: var(--tsim-inverse-surface);
    color: var(--tsim-inverse-text);
    box-shadow: var(--tsim-shadow-floating);
}

.tsim-floating-bar[hidden] {
    display: none;
}

.tsim-floating-bar__title {
    font-size: 15px;
    font-weight: 700;
    white-space: nowrap;
}

.tsim-floating-bar__detail,
.tsim-floating-bar__label {
    margin: 0;
    font-size: 13px;
    color: var(--tsim-inverse-muted);
    white-space: nowrap;
}

.tsim-floating-bar__input {
    width: 240px;
    height: 40px;
    box-sizing: border-box;
    padding: 0 12px;
    border: 1px solid var(--tsim-inverse-border);
    border-radius: 8px;
    background: var(--tsim-inverse-field);
    color: var(--tsim-inverse-text);
    font-family: inherit;
    font-size: 14px;
}

.tsim-floating-bar__input:focus {
    border-color: var(--tsim-inverse-text);
    outline: none;
}

/* --------------------------------------------------------------------------------------------
   Fenêtres — export, modification
   -------------------------------------------------------------------------------------------- */

.tsim-dialog {
    padding: 0;
    border: 0;
    border-radius: 14px;
    background: var(--tsim-surface);
    color: var(--tsim-text);
    box-shadow: var(--tsim-shadow-dialog);
    font-family: var(--tsim-font-sans);
    font-size: 16px;
    line-height: normal;
}

/* Largeur par défaut d'une fenêtre ; un écran la change par son propre modificateur, posé dans
   sa feuille — chargée après celle-ci, elle l'emporte à spécificité égale. */
.tsim-dialog {
    width: min(640px, calc(100vw - 32px));
}

.tsim-dialog::backdrop {
    background: var(--tsim-backdrop);
}

.tsim-dialog[open] {
    display: flex;
    flex-direction: column;
}

.tsim-dialog__content {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    min-height: 0;
}

.tsim-dialog__header {
    display: flex;
    flex: none;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    padding: 22px 24px 18px 28px;
    border-bottom: 1px solid var(--tsim-border);
}

.tsim-dialog__heading {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.tsim-dialog__title {
    margin: 0;
    font-size: 18px;
    font-weight: 700;
    color: var(--tsim-text);
}

.tsim-dialog__subtitle {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-dialog__close {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: var(--tsim-page);
    color: var(--tsim-muted);
    cursor: pointer;
}

.tsim-dialog__close:hover {
    color: var(--tsim-text);
}

.tsim-dialog__body {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 22px 28px;
}

.tsim-dialog__footer {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 16px 28px 22px;
    border-top: 1px solid var(--tsim-border);
}

/* --------------------------------------------------------------------------------------------
   Import d'un lot
   -------------------------------------------------------------------------------------------- */

.tsim-stepper {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 0;
    padding: 0;
    font-size: 14px;
    list-style: none;
}

.tsim-stepper__step {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--tsim-muted);
}

.tsim-stepper__marker {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    box-sizing: border-box;
    border: 1px solid var(--tsim-border);
    border-radius: 50%;
    background: var(--tsim-surface);
    font-size: 13px;
}

.tsim-stepper__step--current {
    color: var(--tsim-text);
    font-weight: 700;
}

.tsim-stepper__step--current .tsim-stepper__marker {
    border: 0;
    background: var(--tsim-primary);
    color: #ffffff;
}

.tsim-stepper__step--done {
    color: var(--tsim-ok);
    font-weight: 600;
}

.tsim-stepper__step--done .tsim-stepper__marker {
    border: 0;
    background: var(--tsim-ok-soft);
}

.tsim-stepper__connector {
    width: 48px;
    height: 1px;
    background: var(--tsim-border);
}

.tsim-stepper__connector--done {
    background: var(--tsim-ok);
}

/* --------------------------------------------------------------------------------------------
   Petits écrans : une colonne, l'en-tête de tableau s'efface.
   -------------------------------------------------------------------------------------------- */

@media (max-width: 991px) {

    .tsim-cell-actions {
        justify-content: flex-start;
    }

    .tsim-group__band {
        grid-template-columns: 40px minmax(0, 1fr);
    }

    .tsim-group__tally {
        grid-column: 2;
        flex-wrap: wrap;
        justify-content: flex-start;
    }

    .tsim-group__heading {
        flex-wrap: wrap;
        height: auto;
    }

    .tsim-floating-bar__input {
        width: 100%;
    }
}
.tsim-screen code {
    font-family: var(--tsim-font-mono);
}

.tsim-button:focus-visible,
.tsim-icon-button:focus-visible,
.tsim-dialog__close:focus-visible,
.tsim-tile:focus-visible,
.tsim-segmented__option:focus-visible,
.tsim-menu__item:focus-visible,
.tsim-group__band:focus-visible {
    outline: 2px solid var(--tsim-primary);
    outline-offset: 2px;
}

.tsim-group__chevron {
    display: flex;
    color: var(--tsim-muted);
    transition: transform 0.15s;
}

.tsim-group[open] > summary .tsim-group__chevron {
    transform: rotate(90deg);
}

/* Un groupe écarté par un filtre porte `hidden` : ceinture face au thème. */
.tsim-group[hidden] {
    display: none;
}

@media (max-width: 991px) {
    .tsim-table,
    .tsim-toolbar {
        padding-right: 16px;
        padding-left: 16px;
    }

    .tsim-table__head {
        display: none;
    }
}

/* Écran de plus grand souffle (maquettes Environnements : 24 px entre les blocs). */
.tsim-screen--spacious {
    gap: 24px;
}

/*
 * Champs du thème posés dans un écran du socle : même cote que `.tsim-input`, pour qu'un
 * formulaire existant prenne le langage commun sans réécrire chaque champ.
 */
.tsim-screen .form-control,
.tsim-screen .form-select {
    min-height: 44px;
    border: 1px solid var(--tsim-border);
    border-radius: 8px;
    background-color: var(--tsim-surface);
    color: var(--tsim-text);
    font-family: inherit;
    font-size: 14px;
}

.tsim-screen .form-control-sm,
.tsim-screen .form-select-sm {
    min-height: 36px;
    font-size: 13px;
}

.tsim-screen .form-control:focus,
.tsim-screen .form-select:focus {
    border-color: var(--tsim-primary);
    box-shadow: 0 0 0 3px var(--tsim-primary-soft);
}

.tsim-screen .form-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--tsim-muted);
}

/* Séparation de sections dans une carte : le même pointillé que les lignes des tableaux. */
.tsim-separator {
    margin: 8px 0;
    border: 0;
    border-top: 1px dashed var(--tsim-border);
    opacity: 1;
}

/* Faits d'un objet : libellé à gauche (140 px), valeur à droite — comme la modale des secrets. */
.tsim-facts {
    display: grid;
    grid-template-columns: 140px minmax(0, 1fr);
    gap: 14px 16px;
    align-items: center;
    font-size: 14px;
}

.tsim-facts__label {
    color: var(--tsim-muted);
}

.tsim-facts__value {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    min-width: 0;
    color: var(--tsim-text);
}

/* Tableau de données simple (mesures, listes plates) : en-tête des tableaux du socle, lignes au
   pointillé. */
.tsim-data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

.tsim-data-table th {
    padding: 12px;
    font-size: 12px;
    font-weight: 700;
    color: var(--tsim-muted);
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.tsim-data-table td {
    padding: 12px;
    border-top: 1px dashed var(--tsim-border);
    color: var(--tsim-text);
}

.tsim-data-table .tsim-data-table__number {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.tsim-data-table__strong {
    font-weight: 700;
}

/* Étapes d'une opération suivie en direct : une ligne par étape, son issue en pastille. */
.tsim-progress-list {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tsim-progress-list:empty::before {
    content: "En attente des premières étapes…";
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-progress-list__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    padding: 12px 0;
    border-top: 1px dashed var(--tsim-border);
    font-size: 14px;
}

.tsim-progress-list__item:first-child {
    border-top: 0;
}

.tsim-progress-list__name {
    flex: 1 1 auto;
    font-weight: 700;
}

.tsim-progress-list__message {
    flex: 1 0 100%;
    font-size: 12px;
    color: var(--tsim-muted);
}

/* Raccourci vers un écran : carte cliquable, icône dans un carré teinté, titre et description. */
.tsim-shortcuts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
}

.tsim-shortcut {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 22px;
    border: 1px solid var(--tsim-border);
    border-radius: 12px;
    background: var(--tsim-surface);
    color: var(--tsim-text);
    text-decoration: none;
}

.tsim-shortcut:hover {
    border-color: var(--tsim-primary);
    color: var(--tsim-text);
}

.tsim-shortcut:focus-visible {
    outline: 2px solid var(--tsim-primary);
    outline-offset: 2px;
}

.tsim-shortcut__icon {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

.tsim-shortcut__text {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tsim-shortcut__title {
    font-size: 16px;
    font-weight: 700;
}

.tsim-shortcut__description {
    font-size: 13px;
    color: var(--tsim-muted);
}

/* Bouton de copie qui vient de copier : retour vert bref, posé par le script de la page. */
.tsim-icon-button--copied {
    border-color: transparent;
    background: var(--tsim-ok-soft);
    color: var(--tsim-ok);
}

/* Message d'un filtre qui ne garde aucune ligne (`tsim-filter.js`). */
.tsim-filter-empty {
    padding: 20px 12px;
    border-top: 1px dashed var(--tsim-border);
    font-size: 14px;
    color: var(--tsim-muted);
    text-align: center;
}

.tsim-filter-empty[hidden] {
    display: none;
}

/* Bouton d'accord : teinte de réussite, jamais pleine. */
.tsim-button--ok-soft {
    background: var(--tsim-ok-soft);
    color: var(--tsim-ok);
}

.tsim-button--ok-soft:hover {
    color: var(--tsim-ok);
}

/* Formulaire d'un seul bouton posé dans une rangée d'actions. */
.tsim-inline-form {
    display: inline-flex;
    margin: 0;
}

/* Écran-porte (connexion, attente d'accès) : une carte centrée, une icône, un texte, un geste. */
.tsim-gate {
    display: flex;
    flex-direction: column;
    gap: 18px;
    box-sizing: border-box;
    width: min(460px, 100%);
    margin: 40px auto 0;
    padding: 36px;
    border: 1px solid var(--tsim-border);
    border-radius: 14px;
    background: var(--tsim-surface);
}

.tsim-gate__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 14px;
    background: var(--tsim-primary-soft);
    color: var(--tsim-primary);
}

.tsim-gate__icon--warn {
    background: var(--tsim-warn-soft);
    color: var(--tsim-warn);
}

.tsim-gate__icon--ko {
    background: var(--tsim-ko-soft);
    color: var(--tsim-ko);
}

.tsim-gate__heading {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.tsim-gate__title {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    color: var(--tsim-text);
}

.tsim-gate__subtitle {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-gate__text {
    margin: 0;
    font-size: 14px;
    line-height: 1.5;
    color: var(--tsim-muted);
}

.tsim-gate__action {
    width: 100%;
}

/* Libellé suivi de son « ? » d'aide : l'aide reste HORS du <label for=…> (sinon le lecteur d'écran
   l'ajoute au nom du champ), et la paire occupe une seule cellule de grille. */
.tsim-label-with-hint {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* ============================================================================================
   COMPOSANTS REMONTÉS DES ZONES (2026-10-03) — écrits en double par cinq écrans pendant que ce
   fichier était fermé (containers, projects, configuration-admin, bdd-local, maintenance…), et
   consolidés ici à cote constante. Les feuilles d'écran ne gardent que leur mise en page : pistes
   de grilles, largeurs, colonnes.
   ============================================================================================ */

/* Un attribut `hidden` doit toujours gagner : lignes, barres et encadrés déclarent un `display`
   (grille, flex) qui, à spécificité égale ou supérieure, le rendrait sans effet — or c'est lui que
   pose `tsim-filter.js` pour écarter une ligne. */
.tsim-screen [hidden] {
    display: none;
}

/* Texte coupé par « … » sur une ligne ; le texte entier reste au `title`. */
.tsim-ellipsis {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Note de 13 px en retrait : sous un champ, à côté d'un fait, dans une cellule. */
.tsim-note {
    font-size: 13px;
    color: var(--tsim-muted);
}

/* --------------------------------------------------------------------------------------------
   Commande segmentée : options qui ne sont pas des boutons
   -------------------------------------------------------------------------------------------- */

/* Des LIENS (volets, sections, écrans d'administration) : l'option retenue se dit par
   `aria-current` (pages distinctes) ou par `aria-selected` / `.active` (onglets Bootstrap, qui les
   tient à jour au clic), jamais par `aria-pressed`, réservé aux boutons. `.tsim-screen a:not(.tsim-button)`
   colore tout lien en primaire : la spécificité est égalée ici, et l'ordre départage. */
.tsim-screen a.tsim-segmented__option,
.tsim-screen a.tsim-segmented__option:hover {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--tsim-muted);
    text-decoration: none;
}

.tsim-screen a.tsim-segmented__option[aria-current="page"],
.tsim-screen a.tsim-segmented__option[aria-selected="true"],
.tsim-screen a.tsim-segmented__option.active {
    background: var(--tsim-surface);
    color: var(--tsim-primary);
    box-shadow: var(--tsim-shadow-raised);
}

/* Des BOUTONS RADIO (hériter / remplacer, portée d'un import) : chaque option est l'étiquette d'un
   VRAI radio, masqué mais focalisable et annoncé ; l'option retenue se peint par `:has(:checked)`.
   Une règle par sélecteur : une liste qui contient un `:has()` incompris est rejetée en entier. */
.tsim-segmented__option--radio {
    position: relative;
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}

.tsim-segmented__radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.tsim-segmented__option--radio:has(:checked) {
    background: var(--tsim-surface);
    color: var(--tsim-primary);
    box-shadow: var(--tsim-shadow-raised);
}

.tsim-segmented__option--radio:has(:focus-visible) {
    outline: 2px solid var(--tsim-primary);
    outline-offset: 2px;
}

/* Tuile de décompte pure : pas de geste, donc pas de curseur de bouton. */
.tsim-tile--static {
    cursor: default;
}

/* --------------------------------------------------------------------------------------------
   Encadrés à la cote des maquettes (`.callout`) : 14 px, coins de 10 px, liseré d'avertissement
   doux. La règle de base `.tsim-callout` garde l'ancienne cote (8 px, texte de l'écran) des écrans
   qui n'ont pas été recalés sur ces maquettes ; passer un encadré en flex casserait un texte
   courant, d'où deux modificateurs : en ligne (icône + corps), ou empilé.
   -------------------------------------------------------------------------------------------- */

.tsim-callout--row,
.tsim-callout--stack {
    display: flex;
    gap: 12px;
    border-radius: 10px;
    font-size: 14px;
}

.tsim-callout--stack {
    flex-direction: column;
    gap: 8px;
}

.tsim-callout--row.tsim-callout--warn,
.tsim-callout--stack.tsim-callout--warn {
    border-color: var(--tsim-warn-border);
}

.tsim-callout__body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

.tsim-callout__note {
    font-size: 13px;
    color: var(--tsim-muted);
}

.tsim-callout__title {
    margin: 0 0 8px;
    font-size: 15px;
    font-weight: 700;
}

.tsim-callout__text,
.tsim-callout__list {
    margin: 0 0 8px;
}

.tsim-callout__list {
    padding-left: 20px;
}

/* Le dernier bloc d'un encadré ne porte pas de marge basse : c'est l'encadré qui respire. */
.tsim-callout__title:last-child,
.tsim-callout__text:last-child,
.tsim-callout__list:last-child {
    margin-bottom: 0;
}

/* --------------------------------------------------------------------------------------------
   Carte à en-tête de section (maquettes `.ch` / `.cb`) : 20 px 28 px, filet sous l'en-tête. La
   base `.tsim-card__header` (24 px en haut, 8 px en bas) reste celle des écrans Environnements.
   -------------------------------------------------------------------------------------------- */

.tsim-card__header--section {
    gap: 12px 16px;
    padding: 20px 28px;
    border-bottom: 1px solid var(--tsim-border);
}

.tsim-card__heading {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

/* Titre suivi de ce qui le qualifie (slug, pastille) sur la même ligne. */
.tsim-card__titleline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.tsim-card__body--section {
    padding: 20px 28px;
}

/* --------------------------------------------------------------------------------------------
   Faits à libellé de 160 px (maquettes `.facts`), et libellé calé en haut d'une valeur haute
   -------------------------------------------------------------------------------------------- */

.tsim-facts--wide {
    grid-template-columns: 160px minmax(0, 1fr);
}

/* Valeurs de hauteurs inégales : le libellé reste calé sur la première ligne du champ (44 px), une
   liste ne l'entraîne pas au milieu. */
.tsim-facts--top {
    align-items: start;
}

.tsim-facts--top > .tsim-facts__label {
    display: flex;
    align-items: center;
    min-height: 44px;
}

/* Champ natif à la cote de la barre d'outils (40 px), pas celle d'un champ de formulaire (44 px).
   Spécificité (0,2,0) pour l'emporter sur `.tsim-screen .form-select` comme sur `.tsim-input`. */
.tsim-screen .tsim-input--toolbar {
    height: 40px;
    min-height: 40px;
}

/* --------------------------------------------------------------------------------------------
   Ligne de tableau en div : filet pointillé, 14 px, et `hidden` qui gagne sur la grille
   -------------------------------------------------------------------------------------------- */

.tsim-table__row {
    border-top: 1px dashed var(--tsim-border);
    font-size: 14px;
}

.tsim-table__row[hidden] {
    display: none;
}

/* En-tête de colonne triable : un bouton qui reprend l'écriture de la légende, sans cadre… */
.tsim-table__sort {
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-align: left;
    text-transform: inherit;
    cursor: pointer;
}

.tsim-table__sort:hover {
    color: var(--tsim-text);
}

/* …ou un `th` à `aria-sort`, dont la flèche suit l'état. */
.tsim-sortable {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}

.tsim-sort-indicator::after {
    content: "\2195"; /* ↕ neutre */
    margin-left: 6px;
    opacity: 0.4;
}

.tsim-sortable[aria-sort="ascending"] .tsim-sort-indicator::after {
    content: "\2191"; /* ↑ */
    opacity: 1;
}

.tsim-sortable[aria-sort="descending"] .tsim-sort-indicator::after {
    content: "\2193"; /* ↓ */
    opacity: 1;
}

/* --------------------------------------------------------------------------------------------
   Zone de dépôt d'un fichier
   -------------------------------------------------------------------------------------------- */

.tsim-dropzone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 140px;
    margin: 0;
    padding: 20px;
    border: 2px dashed var(--tsim-dropzone-border);
    border-radius: 12px;
    background: var(--tsim-dropzone-background);
    text-align: center;
    cursor: pointer;
}

/* Le champ couvre toute la zone, transparent : un fichier glissé dessus est déposé par le
   navigateur lui-même, et la validation `required` garde une cible focalisable. */
.tsim-dropzone__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.tsim-dropzone:focus-within {
    border-color: var(--tsim-primary);
}

.tsim-dropzone__icon {
    display: flex;
    color: var(--tsim-primary);
}

.tsim-dropzone__title {
    font-size: 15px;
    font-weight: 700;
    overflow-wrap: anywhere;
}

.tsim-dropzone__browse {
    color: var(--tsim-primary);
    text-decoration: underline;
}

.tsim-dropzone__hint {
    font-size: 12px;
    color: var(--tsim-muted);
}

/* --------------------------------------------------------------------------------------------
   Groupe dépliable d'un aperçu (import de secrets, de versions, de définitions) : compléments au
   `tsim-group` de l'inventaire
   -------------------------------------------------------------------------------------------- */

/* Premier groupe collé à ce qui le précède ; les suivants gardent leurs 8 px. */
.tsim-group--flush {
    margin-top: 0;
}

.tsim-group--flush + .tsim-group--flush {
    margin-top: 8px;
}

/* Bandeau en ligne plutôt qu'en grille : titre, pastille, et le reste poussé à droite par le
   `__spacer`. Déclaré après `.tsim-group__band`, qu'il remplace à spécificité égale. */
.tsim-group__band--row {
    display: flex;
    gap: 10px;
    padding: 12px;
    font-size: 15px;
    font-weight: 700;
}

.tsim-group__band--compact {
    font-size: 14px;
}

/* Bandeau sans hauteur imposée : celle de son contenu, pas les 36 px d'une rangée de boutons. */
.tsim-group__heading--auto {
    height: auto;
}

.tsim-group__label {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.tsim-group__spacer {
    flex: 1 1 auto;
}

.tsim-group__hint {
    overflow: hidden;
    font-size: 13px;
    color: var(--tsim-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.tsim-group__count {
    font-size: 13px;
    font-weight: 400;
    color: var(--tsim-muted);
    white-space: nowrap;
}

.tsim-group__empty {
    display: block;
    padding: 10px 12px;
    border-top: 1px dashed var(--tsim-border);
    font-size: 13px;
    color: var(--tsim-muted);
}

/* Mise en garde en tête d'un groupe : elle précède les lignes qu'elle concerne. */
.tsim-group__notice {
    padding: 12px;
    border-top: 1px dashed var(--tsim-border);
}

.tsim-group__footer {
    padding: 0 12px 16px;
}

/* Ligne d'aperçu : une case, l'entrée, et son effet qui suit la case SANS script — cochée, ce qui
   sera écrit ; décochée, ce qui restera. Une règle par sélecteur à cause du `:has()`. */
.tsim-preview-row {
    min-height: 28px;
    margin: 0;
    padding: 10px 12px;
}

label.tsim-preview-row {
    cursor: pointer;
}

.tsim-preview-row__entry {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.tsim-preview-row__line {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

.tsim-preview-row__key {
    font-family: var(--tsim-font-mono);
    font-size: 13px;
    font-weight: 700;
    white-space: nowrap;
}

.tsim-preview-row__path {
    overflow: hidden;
    font-family: var(--tsim-font-mono);
    font-size: 12px;
    color: var(--tsim-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.tsim-preview-row__kind {
    overflow: hidden;
    font-size: 12px;
    color: var(--tsim-muted);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.tsim-preview-row__if-checked {
    display: none;
}

.tsim-preview-row:has(.tsim-checkbox:checked) .tsim-preview-row__if-unchecked {
    display: none;
}

.tsim-preview-row:has(.tsim-checkbox:checked) .tsim-preview-row__if-checked {
    display: inline-block;
}

/* --------------------------------------------------------------------------------------------
   Menu « … » : item lien, geste destructeur, formulaire porteur, formulaire dans le popover
   -------------------------------------------------------------------------------------------- */

/* `.tsim-screen a:not(.tsim-button)` colore tout lien en primaire : la spécificité est égalée ici
   pour qu'un lien de menu se lise comme un bouton de menu. */
.tsim-screen a.tsim-menu__item,
.tsim-screen a.tsim-menu__item:hover {
    color: var(--tsim-text);
    text-decoration: none;
}

.tsim-menu__item.tsim-menu__item--danger,
.tsim-screen a.tsim-menu__item.tsim-menu__item--danger {
    color: var(--tsim-ko);
}

/* Le formulaire d'un geste n'existe que pour porter sa soumission et son jeton : il ne compte pas
   dans la disposition du menu, dont l'élément reste le bouton. */
.tsim-menu__form {
    display: contents;
}

.tsim-menu__form .tsim-menu__item {
    width: 100%;
}

/* Un formulaire entier dans le popover (champ + bouton), calé sous son déclencheur. */
.tsim-menu--form {
    gap: 10px;
    padding: 14px;
}

.tsim-menu__note {
    padding: 6px 12px 8px;
}

/* --------------------------------------------------------------------------------------------
   Lignes répétables (variables, labels, volumes, alias) : `configuration-form.js` en ajoute et en
   retire, avec le même balisage que Twig.
   -------------------------------------------------------------------------------------------- */

.tsim-repeat-block {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
}

.tsim-repeat {
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
}

.tsim-repeat__row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.tsim-repeat__row > .tsim-repeat__input {
    flex: 1 1 0;
    min-width: 0;
}

/* La clé a une largeur fixe : les valeurs commencent toutes au même endroit. */
.tsim-repeat__row > .tsim-repeat__input--key {
    flex: 0 0 260px;
}

/* --------------------------------------------------------------------------------------------
   Cartes de choix radio : un choix par carte, son effet et son dessin dessous
   -------------------------------------------------------------------------------------------- */

.tsim-choice-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px;
    width: 100%;
}

.tsim-choice-card {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    padding: 14px 16px;
    border: 1px solid var(--tsim-border);
    border-radius: 10px;
    background: var(--tsim-surface);
}

.tsim-choice-card--selected {
    border-color: var(--tsim-primary);
    background: var(--tsim-primary-soft);
}

.tsim-choice-card__choice {
    display: flex;
    gap: 12px;
    margin: 0;
    cursor: pointer;
}

.tsim-choice-card__choice input {
    flex: none;
    margin-top: 2px;
    accent-color: var(--tsim-primary);
}

.tsim-choice-card__title {
    font-size: 14px;
    font-weight: 700;
}

/* --------------------------------------------------------------------------------------------
   Petits écrans : les faits en une colonne, la clé des lignes répétables en proportion.
   -------------------------------------------------------------------------------------------- */

@media (max-width: 991px) {
    .tsim-facts--wide {
        grid-template-columns: minmax(0, 1fr);
        gap: 6px;
    }

    .tsim-facts--top > .tsim-facts__label {
        min-height: 0;
    }

    .tsim-repeat__row > .tsim-repeat__input--key {
        flex-basis: 40%;
    }
}

/* Compteur d'attention d'un onglet de volets : orange, et absent à zéro (_workspace_tabs). */
.workspace-tabs__count--attention {
    padding: 1px 7px;
    border-radius: 6px;
    background: var(--tsim-warn-soft);
    color: var(--tsim-warn);
    font-weight: 700;
}

/*
 * Les <code> d'un écran du socle. Le thème pose sur `code:not([class*=language-])` un rose, un fond
 * gris, une bordure et une marge de 0,5rem de chaque côté — plus prioritaire qu'une simple classe :
 * un chemin cité dans une phrase s'écartait du texte et une pastille `tsim-chip` en `<code>` restait
 * rose. Un code en ligne sans classe devient un texte mono discret ; un code à classe perd les
 * marges et bordures du thème et garde le dessin de sa classe.
 */
.tsim-screen code:not([class]) {
    margin: 0;
    padding: 1px 5px;
    border: 0;
    border-radius: 4px;
    box-shadow: none;
    background: var(--tsim-page);
    color: var(--tsim-text);
    font-family: var(--tsim-font-mono);
    font-size: 0.92em;
    font-weight: inherit;
    line-height: inherit;
}

.tsim-screen code[class] {
    margin: 0;
    border: 0;
    box-shadow: none;
    font-family: var(--tsim-font-mono);
    font-weight: inherit;
    line-height: inherit;
}

.tsim-screen code.tsim-chip {
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--tsim-chip-bg);
    color: var(--tsim-primary);
    font-size: 13px;
    overflow-wrap: anywhere;
}

.tsim-screen code.tsim-mono {
    padding: 0;
    background: transparent;
    color: inherit;
    font-size: inherit;
}

/*
 * Éditeur de code léger (`tsim-code-editor.js`) : gouttière de numéros de ligne, puis un
 * `<textarea>` transparent posé exactement sur la copie colorée de son texte. Les deux couches
 * partagent police, taille, interligne, marges et absence de retour à la ligne : un écart d'un
 * pixel et le curseur ne tombe plus sur la lettre qu'on voit. Sans script (`--ready` absent), le
 * champ s'affiche comme un champ ordinaire et la copie colorée reste masquée.
 */
.tsim-code-editor {
    --tsim-code-line: 20px;
    --tsim-code-padding: 12px;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    width: 100%;
    min-height: calc(var(--tsim-code-line) * 8 + var(--tsim-code-padding) * 2);
    overflow: hidden;
    border: 1px solid var(--tsim-border);
    border-radius: 8px;
    background: var(--tsim-surface);
    font-family: var(--tsim-font-mono);
    font-size: 13px;
    line-height: var(--tsim-code-line);
}

.tsim-code-editor:focus-within {
    border-color: var(--tsim-primary);
    box-shadow: 0 0 0 3px var(--tsim-primary-soft);
}

.tsim-code-editor__gutter {
    display: none;
    min-width: 36px;
    padding: var(--tsim-code-padding) 10px;
    overflow: hidden;
    border-right: 1px solid var(--tsim-border);
    background: var(--tsim-page);
    color: var(--tsim-placeholder);
    text-align: right;
    white-space: pre;
    user-select: none;
}

.tsim-code-editor__area {
    position: relative;
    grid-column: 1 / -1;
    min-width: 0;
}

.tsim-code-editor__highlight,
.tsim-code-editor__input {
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    min-height: inherit;
    margin: 0;
    padding: var(--tsim-code-padding);
    border: 0;
    font: inherit;
    letter-spacing: 0;
    white-space: pre;
    tab-size: 2;
    overflow: auto;
}

/*
 * Le cadre de la copie retranche la place des barres de défilement du champ, mesurée par le
 * script : les deux couches ont alors la même zone visible, donc la même course de défilement.
 * Largeur et hauteur en `auto`, sans quoi le `100 %` partagé l'emporterait sur `right`/`bottom`.
 */
.tsim-code-editor__highlight {
    display: none;
    position: absolute;
    inset: 0 var(--tsim-code-editor-scrollbar-width, 0px) var(--tsim-code-editor-scrollbar-height, 0px) 0;
    width: auto;
    height: auto;
    background: transparent;
    color: var(--tsim-text);
    pointer-events: none;
}

/*
 * Le `<code>` de la copie PORTE UNE CLASSE, et son sélecteur compte deux classes : sans ça, c'est
 * `.tsim-screen code:not([class])` (0,2,1) qui gagnait sur `.tsim-code-editor__highlight code`
 * (0,1,1) et posait sur la copie 5 px de remplissage, une police à 0,92 em et un fond gris — la
 * copie dérivait du champ dès la première lettre, et le curseur ne tombait plus sur celle qu'on voit.
 */
.tsim-code-editor__highlight .tsim-code-editor__code {
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    background: transparent;
    color: inherit;
    font: inherit;
}

.tsim-code-editor__input {
    position: relative;
    display: block;
    min-height: calc(var(--tsim-code-line) * 8 + var(--tsim-code-padding) * 2);
    resize: vertical;
    outline: none;
    background: transparent;
    color: var(--tsim-text);
}

/* Script prêt : gouttière visible, texte du champ transparent, la couleur vient de la copie. */
.tsim-code-editor--ready .tsim-code-editor__gutter {
    display: block;
}

.tsim-code-editor--ready .tsim-code-editor__area {
    grid-column: 2;
}

.tsim-code-editor--ready .tsim-code-editor__highlight {
    display: block;
    overflow: hidden;
}

.tsim-code-editor--ready .tsim-code-editor__input {
    color: transparent;
    caret-color: var(--tsim-text);
}

/*
 * Le champ est peint PAR-DESSUS la copie colorée : une sélection opaque — `--tsim-primary-soft`
 * l'est en thème clair — recouvrait le texte d'une bande pleine. Translucide, elle le teinte.
 */
.tsim-code-editor--ready .tsim-code-editor__input::selection {
    background: color-mix(in srgb, var(--tsim-primary) 22%, transparent);
    color: transparent;
}

.tsim-code-editor__input::placeholder {
    color: var(--tsim-placeholder);
}

.tsim-code-editor__token--marker { color: var(--tsim-muted); }
.tsim-code-editor__token--value { color: var(--tsim-primary); font-weight: 600; }
.tsim-code-editor__token--comment { color: var(--tsim-ok); font-style: italic; }

/* Langages `dotenv` et `php-define` (mode fichier des secrets). Aucun jeton n'a de marge ni de
   remplissage : la copie colorée doit garder la largeur exacte du texte du champ. */
.tsim-code-editor__token--key { color: var(--tsim-primary); font-weight: 600; }
.tsim-code-editor__token--punctuation { color: var(--tsim-placeholder); }
.tsim-code-editor__token--string { color: var(--tsim-ok); }
.tsim-code-editor__token--number { color: var(--tsim-warn); }
.tsim-code-editor__token--keyword { color: var(--tsim-text-secondary); font-weight: 600; }

.tsim-code-editor__token--placeholder {
    border-radius: 4px;
    background: var(--tsim-code-placeholder-background);
    color: var(--tsim-code-placeholder-text);
}

/* Après la fin de la ligne : seule décoration autorisée à avoir de la marge. */
.tsim-code-editor__tag {
    margin-left: 12px;
    padding: 1px 8px;
    border-radius: 6px;
    background: var(--tsim-page);
    color: var(--tsim-muted);
    font-family: var(--tsim-font-sans);
    font-size: 11px;
    font-style: normal;
    font-weight: 600;
    /* Autre police, autre taille : sans ça la ligne dépasserait 20px et la copie dériverait du champ. */
    line-height: 1;
    vertical-align: top;
}

/* Numéros de la gouttière : une marque à gauche pour la marge de diff, un fond pour une erreur. */
.tsim-code-editor__line-number {
    display: inline-block;
    width: 100%;
}

.tsim-code-editor__line-number--added {
    box-shadow: inset 3px 0 0 var(--tsim-ok);
    color: var(--tsim-ok);
}

.tsim-code-editor__line-number--modified {
    box-shadow: inset 3px 0 0 var(--tsim-primary);
    color: var(--tsim-primary);
}

.tsim-code-editor__line-number--error {
    box-shadow: inset 3px 0 0 var(--tsim-ko);
    background: var(--tsim-ko-soft);
    color: var(--tsim-ko);
}

.tsim-code-editor__token--invalid {
    color: var(--tsim-ko);
    text-decoration: underline wavy var(--tsim-ko);
    text-underline-offset: 3px;
}
