/* ============================================================
   TimeEcosModal — système de modale unique (socle V3)
   ------------------------------------------------------------
   Basé sur l'élément <dialog> natif. S'appuie sur les variables
   de theme.css (--surface, --text, --line, --shadow-lg…) afin de
   fonctionner automatiquement en thème clair ET sombre.
   Préfixe de classe dédié `tem-` (Time-Ecos Modal) pour éviter
   toute collision avec .modal-* (admin) et .te-modal-* (sujets).
   ============================================================ */

/* Verrouillage du défilement du fond pendant l'ouverture */
html.tem-modal-open,
html.tem-modal-open body { overflow: hidden; }

/* Le <dialog> occupe tout l'écran et centre le cadre.
   Sa zone vide (hors cadre) sert de fond cliquable. */
dialog.tem-dialog {
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  padding: 16px;
  border: 0;
  background: transparent;
  overflow: hidden;
  box-sizing: border-box;
}
dialog.tem-dialog[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}
dialog.tem-dialog::backdrop {
  background: rgba(2, 8, 23, 0.55);
  backdrop-filter: blur(2px);
}
dialog.tem-dialog.tem-nonmodal {
  position: fixed;
  inset: 0;
  /* show() ne met PAS le <dialog> dans le top layer (contrairement à showModal()) :
     sans z-index il retombe à 0 et passe SOUS tout élément positionné de la page.
     Constaté le 2026-08-16 sur l'accueil : la modale de connexion s'ouvrait derrière
     la carte « Choisir une organisation » (.index-v3-main porte z-index:1).
     Valeur choisie sous les tooltips (2147483000) et les notifications (2147483645+),
     qui doivent rester au-dessus de la modale. */
  z-index: 2147482000;
  background: rgba(2, 8, 23, 0.55);
  backdrop-filter: blur(2px);
}
/* [2026-09-27, Lot 118 — QG sur FGSM3-31 : « qiand je clique associer un autre planniong ça ouvre une fenetr
   ederriere je peux rien faire : pq »] Calque « maison » (`.modal-overlay`) RATTACHÉ à un <dialog> du socle pour
   rejoindre la couche du dessus (fenêtre ouverte depuis une modale : « Associer un planning à la session » depuis
   4.2, admin-epreuves-planning.js, Lot 14). Il doit passer au-dessus de TOUT le contenu du dialog : l'hôte de
   l'assistant (`#epreuve-create-modal`, admin.css) garde `z-index: 11000` et, élément flex du corps, il compte dans
   l'empilement du dialog ; le calque (`z-index: 1000`, admin.css) s'ouvrait dessous, visible par transparence et
   masqué par le contenu. Valeur sous les infobulles et les notifications, comme `.tem-nonmodal`. */
dialog.tem-dialog > .modal-overlay {
  z-index: 2147482500;
}

/* Cadre visible de la modale */
.tem-frame {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 560px;                 /* taille md par défaut */
  max-height: min(90vh, 760px);
  background: var(--surface, #f9fafb);
  color: var(--text, #04151f);
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius-lg, 12px);
  box-shadow: var(--shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.15));
  overflow: hidden;
  animation: tem-frame-in 0.2s ease-out;
}
dialog.tem-dialog.tem-size-sm .tem-frame { max-width: 420px; }
dialog.tem-dialog.tem-size-lg .tem-frame { max-width: 820px; }
dialog.tem-dialog.tem-size-xl .tem-frame { max-width: 1040px; }
dialog.tem-dialog.tem-size-workspace .tem-frame {
  max-width: min(1180px, calc(100vw - 32px));
  height: min(860px, calc(100vh - 32px));
}
/* [2026-08-16] 8 px de marge autour de l'assistant au lieu de 16 : 16 px de hauteur
   rendus au contenu sur les portables, sans coller aux bords. Le padding du <dialog>
   et la hauteur du cadre doivent rester cohérents, sinon le cadre déborde et se fait
   rogner par l'`overflow: hidden` du dialog. */
dialog.tem-dialog.tem-size-creation { padding: 8px; }
dialog.tem-dialog.tem-size-creation .tem-frame {
  max-width: min(1120px, calc(100vw - 16px));
  height: min(900px, calc(100vh - 16px));
}
dialog.tem-dialog.tem-size-import .tem-frame {
  max-width: min(1080px, calc(100vw - 32px));
  height: min(820px, calc(100vh - 32px));
}
dialog.tem-dialog.tem-size-station .tem-frame {
  max-width: min(1180px, calc(100vw - 32px));
  height: min(880px, calc(100vh - 32px));
}

@keyframes tem-frame-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .tem-frame { animation: none; }
}

/* En-tête (reste visible quand le corps défile) */
.tem-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 16px 18px;
  border-bottom: 1px solid var(--line, #e5e7eb);
  background: var(--surface, #f9fafb);
}
.tem-title {
  margin: 0;
  min-width: 0;
  font-size: var(--text-lg, 1.125rem);
  font-weight: 700;
  color: var(--title-card, var(--brand, #004777));
}
/* [2026-09-23, capture QG : « Réglages de la répétition » cassé un mot par ligne sous le nom de
   session] La rangée passe à la ligne : une méta trop longue pour tenir à côté du titre descend
   dessous au lieu de l'écraser, et ne dépasse jamais la largeur de l'en-tête. */
.tem-title-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.65rem;
  min-width: 0;
}
.tem-header-meta {
  display: flex;
  align-items: center;
  /* [2026-09-21, soir — capture QG : pastille « ● » sans texte, « FGSM3-1 » réduit à « FG »] La
     pastille ne se comprime pas : quand l'en-tête est chargé (préremplissage, réglages, présence,
     indicateur), c'est le titre qui passe à la ligne, pas l'identifiant de l'épreuve qui disparaît. */
  flex: 0 0 auto;
  max-width: 100%;
}
/* Exception : l'assistant d'épreuve garde son en-tête sur UNE ligne au-dessus de 640 px (maquette
   du 2026-09-22, admin.css) ; la fin de sa pastille y est rognée plutôt que renvoyée à la ligne. */
@media (min-width: 641px) {
  .tem-header:has(> #epreuve-presence-indicator) .tem-title-row { flex-wrap: nowrap; }
}
.tem-header-meta[hidden] { display: none; }
.tem-heading {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
}
.tem-subtitle {
  margin: 0;
  color: var(--muted, #6b7280);
  font-size: var(--text-sm, 0.875rem);
  line-height: 1.35;
}

/* Métadonnée compacte « promotions ciblées » utilisée par les assistants Station/Épreuve. */
.tem-promotion-meta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
.tem-promotion-meta__separator {
  width: 1px;
  height: 1.15rem;
  background: var(--line, #e5e7eb);
  flex: 0 0 auto;
}
.tem-promotion-meta__desktop {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}
.tem-promotion-meta .promo-epreuve-chip {
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tem-promotion-meta .tem-promotion-meta__mobile { display: none; }
.tem-promotion-meta__edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 999px;
  background: transparent;
  color: var(--muted, #6b7280);
  cursor: pointer;
  flex: 0 0 auto;
}
.tem-promotion-meta__edit:hover {
  border-color: var(--accent, #00afb5);
  color: var(--accent, #00afb5);
  background: color-mix(in srgb, var(--accent, #00afb5) 8%, transparent);
}
.tem-promotion-meta__edit:focus-visible {
  outline: 2px solid var(--accent, #00afb5);
  outline-offset: 2px;
}
.tem-promotion-meta__edit:disabled { opacity: 0.55; cursor: wait; }
.tem-promotion-meta__edit .lucide-icon,
.tem-promotion-meta__edit svg { width: 14px; height: 14px; }

@media (max-width: 640px) {
  .tem-title-row { gap: 0.4rem; }
  .tem-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .tem-header-meta { flex: 0 0 auto; }
  .tem-promotion-meta { gap: 0.3rem; }
  .tem-promotion-meta__separator { display: none; }
  .tem-promotion-meta__desktop { display: none; }
  .tem-promotion-meta .tem-promotion-meta__mobile { display: inline-flex; }
  .tem-promotion-meta .promo-epreuve-chip { max-width: 8rem; }
}

/* Pastille d'icône optionnelle dans l'en-tête (option `icon` du socle). */
.tem-header-lead {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-width: 0;
}
.tem-header-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  color: var(--accent, #00afb5);
  background: color-mix(in srgb, var(--accent, #00afb5) 15%, transparent);
}
.tem-header-icon .lucide-icon,
.tem-header-icon svg { width: 20px; height: 20px; }
.tem-header-icon--info {
  color: var(--info, #3b82f6);
  background: color-mix(in srgb, var(--info, #3b82f6) 15%, transparent);
}
.tem-header-icon--warning {
  color: var(--warning, #ff7700);
  background: color-mix(in srgb, var(--warning, #ff7700) 15%, transparent);
}
.tem-header-icon--danger {
  color: var(--danger, #a30000);
  background: color-mix(in srgb, var(--danger, #a30000) 15%, transparent);
}
.tem-header-icon--success {
  color: var(--success, #16a34a);
  background: color-mix(in srgb, var(--success, #16a34a) 15%, transparent);
}
.tem-close {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--radius, 6px);
  background: transparent;
  color: var(--muted, #6b7280);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  transition: var(--transition, 0.2s ease);
}
.tem-close:hover { background: rgba(180, 35, 24, 0.12); color: var(--danger, #b42318); }
.tem-close:focus-visible { outline: 2px solid var(--accent, #00afb5); outline-offset: 2px; }

/* Corps (zone défilante) */
.tem-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 18px;
  overflow-y: auto;
  line-height: var(--leading-normal, 1.5);
}
.tem-body p { margin: 0 0 0.75rem 0; }
.tem-body p:last-child { margin-bottom: 0; }

/* Pied (reste visible quand le corps défile) */
.tem-footer {
  padding: 14px 18px;
  border-top: 1px solid var(--line, #e5e7eb);
  background: var(--surface, #f9fafb);
}
.tem-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.tem-actions .btn {
  width: auto !important;
}

/* Champs de formulaire à l'intérieur d'une modale */
.tem-field { margin-bottom: 0.85rem; }
.tem-field:last-child { margin-bottom: 0; }
.tem-label {
  display: block;
  margin-bottom: 0.3rem;
  font-weight: 600;
  font-size: var(--text-sm, 0.875rem);
}
.tem-input {
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #ffffff);
  color: var(--text, #04151f);
  font: inherit;
}
.tem-input:focus-visible { outline: 2px solid var(--accent, #00afb5); outline-offset: 1px; }
.tem-help { margin-top: 0.3rem; font-size: var(--text-xs, 0.75rem); color: var(--muted, #6b7280); }
.tem-error { margin-top: 0.3rem; font-size: var(--text-xs, 0.75rem); color: var(--danger, #a30000); }

/* État « champ requis non rempli » : rendu orange aligné sur le socle
   TimeEcosPrompt (`.te-prompt__input--error`, modals.css). Un champ oublié n'est
   pas une vraie erreur : on invite à compléter en orange (--warning) plutôt que
   de dramatiser en rouge. À poser/retirer en JS via la classe `tem-input--error`,
   avec un message `tem-error--warning` sous le champ. */
.tem-input--error,
.tem-input--error:focus-visible {
  border-color: var(--warning, #FF7700);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--warning, #FF7700) 22%, transparent);
  outline: none;
}
.tem-error--warning { color: var(--warning, #FF7700); font-weight: 600; }

/* Contenus standards réutilisables dans les modales V3 */
.tem-stack {
  display: grid;
  gap: 0.85rem;
}
.tem-summary {
  padding: 0.85rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: color-mix(in srgb, var(--surface, #f9fafb) 72%, var(--accent, #00afb5) 8%);
}
.tem-summary strong { color: var(--text, #04151f); }
.tem-list {
  margin: 0;
  padding-left: 1.2rem;
}
/* Un paragraphe qui suit une liste ne doit pas coller a sa derniere puce : sans cette regle, la
   phrase de conclusion se lit comme un item de la liste (constate le 2026-08-20 sur la modale
   « Changer de type ? » des stations). Meme respiration que .tem-body p. */
.tem-body .tem-list + p { margin-top: 0.75rem; }

/* [2026-09-26, Lot 12] Prévol d'un geste : ce qui va changer, montré avant la confirmation.
   Rouge quand on perd, vert quand on gagne. Construit par `apercuGesteHtml` (scripts/apercu-geste.js). */
.tem-apercu {
  margin: 0.6rem 0 0;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 10px;
  background: var(--surface, #f9fafb);
  font-size: 0.86rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.tem-apercu--retrait {
  border-color: color-mix(in srgb, var(--danger, #A30000) 30%, #fff);
  background: color-mix(in srgb, var(--danger, #A30000) 4%, #fff);
}
.tem-apercu--ajout {
  border-color: color-mix(in srgb, var(--success, #15803d) 35%, #fff);
  background: color-mix(in srgb, var(--success, #15803d) 5%, #fff);
}
.tem-apercu__liste { margin: 0; padding-left: 1.05rem; }
.tem-apercu__liste li { margin: 0.12rem 0; }
.tem-apercu__perdu { color: var(--danger, #A30000); font-weight: 700; }
.tem-apercu__gagne { color: var(--success, #15803d); font-weight: 700; }
.tem-apercu__compteurs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.9rem;
  font-size: 0.82rem;
  font-variant-numeric: tabular-nums;
}
.tem-apercu__liste + .tem-apercu__compteurs {
  margin-top: 0.4rem;
  padding-top: 0.35rem;
  border-top: 1px dashed var(--line, #e5e7eb);
}
.tem-apercu__compteurs strong { font-weight: 800; }
.tem-apercu__fleche { color: var(--muted, #6b7280); padding: 0 0.15rem; }
.tem-apercu__alerte strong:last-child { color: var(--danger, #A30000); }
.tem-apercu__liste { max-height: 12rem; overflow-y: auto; }
/* Détail case par case (décision QG du 26/09) : tableau toujours visible, hauteur bornée, défilement
   interne ; à 320 px, seul le tableau défile en largeur, jamais la page. */
.tem-apercu__legende {
  margin: 0.45rem 0 0.2rem;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted, #6b7280);
}
.tem-apercu__tableau { max-height: 15rem; overflow: auto; background: #fff; border: 1px solid var(--line, #e5e7eb); border-radius: 6px; }
.tem-apercu__tableau table { width: 100%; border-collapse: collapse; font-size: 0.76rem; font-variant-numeric: tabular-nums; }
.tem-apercu__tableau th {
  position: sticky;
  top: 0;
  background: var(--surface, #f9fafb);
  text-align: left;
  color: var(--muted, #6b7280);
  font-weight: 700;
  padding: 0.2rem 0.35rem;
  border-bottom: 1px solid var(--line, #e5e7eb);
  white-space: nowrap;
}
.tem-apercu__tableau td { padding: 0.15rem 0.35rem; border-bottom: 1px solid var(--line, #e5e7eb); white-space: nowrap; }
.tem-apercu__sens { font-weight: 700; }
.tem-apercu__sens--retrait { color: var(--danger, #A30000); }
.tem-apercu__sens--ajout { color: var(--success, #15803d); }
.tem-apercu__conserve { margin: 0.35rem 0 0; color: var(--muted, #6b7280); font-size: 0.8rem; }
/* [2026-09-28, Lot 168] Ce qui bloque un geste, au-dessus de son prévol (la confirmation est grisée, même cause). */
.tem-apercu__blocage { margin: 0 0 0.4rem; color: var(--danger, #A30000); font-weight: 600; font-size: 0.86rem; }
/* Aperçu sans fenêtre : il s'ouvre au survol ou au focus du bouton qu'il accompagne, sous lui. */
.tem-apercu-survol { position: relative; display: inline-flex; }
.tem-apercu-survol > .tem-apercu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  width: min(330px, calc(100vw - 32px));
  margin: 0;
  box-shadow: 0 10px 25px rgba(15, 23, 42, 0.15);
}
/* Pont invisible entre le bouton et l'aperçu : le survol ne se perd pas dans l'écart. */
.tem-apercu-survol > .tem-apercu::before { content: ''; position: absolute; left: 0; right: 0; top: -8px; height: 8px; }
.tem-apercu-survol > .tem-apercu--retrait { background: color-mix(in srgb, var(--danger, #A30000) 4%, #fff); }
.tem-apercu-survol > .tem-apercu--ajout { background: color-mix(in srgb, var(--success, #15803d) 5%, #fff); }
.tem-apercu-survol > .tem-apercu--neutre { background: #fff; }
/* Aperçu au survol posé dans le body (`apercu-survol.js`) : jamais rogné par une carte ou une modale. */
.tem-apercu-flottant {
  position: fixed;
  z-index: 3000;
  width: min(330px, calc(100vw - 32px));
  pointer-events: none;
}
.tem-apercu-flottant > .tem-apercu { margin: 0; background: #fff; box-shadow: 0 10px 25px rgba(15, 23, 42, 0.15); }
.tem-apercu-survol:hover > .tem-apercu,
.tem-apercu-survol:focus-within > .tem-apercu { display: block; }

/* [2026-09-26, Lot 6] Prévol de l'affectation des PS et évaluateurs (4.3) : qui sera placé où, et
   pourquoi, règle par règle. Construit par `apercu-affectation-intervenants.js` ; maquette
   `mockups/prevol-affectation-intervenants/` (cases P1 à P13 gardées par QG). */
.tem-prevol { font-size: 0.86rem; line-height: 1.45; }
.tem-prevol__resume { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.6rem; }
.tem-prevol__tuile {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 10px;
  padding: 0.3rem 0.6rem;
  background: var(--surface, #f9fafb);
  font: inherit;
  font-size: 0.8rem;
  color: inherit;
}
.tem-prevol__tuile strong { font-size: 1.05rem; font-variant-numeric: tabular-nums; }
button.tem-prevol__tuile { cursor: pointer; }
.tem-prevol__tuile.is-active { outline: 2px solid var(--brand, #004777); outline-offset: 1px; }
.tem-prevol__tuile--ok strong { color: var(--success, #15803d); }
.tem-prevol__tuile--evite strong { color: #b45309; }
.tem-prevol__tuile--non strong { color: var(--danger, #A30000); }
.tem-prevol__filtres { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.6rem 0; }
.tem-prevol__filtres select,
.tem-prevol__filtres input { font: inherit; font-size: 0.82rem; padding: 0.3rem 0.45rem; border: 1px solid var(--line, #e5e7eb); border-radius: 6px; background: #fff; }
.tem-prevol__filtres input { flex: 1 1 140px; min-width: 0; }
.tem-prevol__zone { max-height: 26rem; overflow: auto; border: 1px solid var(--line, #e5e7eb); border-radius: 10px; background: #fff; }
.tem-prevol__table { width: 100%; border-collapse: collapse; font-size: 0.78rem; }
.tem-prevol__table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface, #f9fafb);
  text-align: left;
  color: var(--muted, #6b7280);
  font-weight: 700;
  padding: 0.3rem 0.4rem;
  border-bottom: 1px solid var(--line, #e5e7eb);
  white-space: nowrap;
}
.tem-prevol__table td { padding: 0.3rem 0.4rem; border-bottom: 1px solid var(--line, #e5e7eb); vertical-align: top; }
.tem-prevol__table tr.is-surveiller td,
.tem-prevol__carte.is-surveiller { background: #fff7ed; }
.tem-prevol__detail td { background: var(--surface, #f9fafb); }
.tem-prevol__detail ul,
.tem-prevol__carte ul,
.tem-prevol__bloc ul,
.tem-prevol__limites ul { margin: 0.2rem 0 0; padding-left: 1.05rem; }
.tem-prevol__nom { font-weight: 700; white-space: nowrap; }
.tem-prevol__poste { white-space: nowrap; font-variant-numeric: tabular-nums; }
.tem-prevol__code { font-size: 0.72rem; background: var(--gris, #f3f4f6); border-radius: 4px; padding: 0 0.25rem; }
/* [2026-09-27, lot 38 — maquette `mockups/simuler-affectation/`] Poste « S2 B3 » en première colonne, code de
   fiche dessous ; personne « NOM Prénom », adresse copiable dessous, repère « aussi en … » ; vue par personne. */
.tem-prevol__poste-cle { font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tem-prevol__poste-code { display: block; font-size: 0.68rem; color: var(--muted, #6b7280); }
.tem-prevol__email { display: block; appearance: none; background: none; border: 0; padding: 0; margin: 0; font: inherit; font-size: 0.72rem; color: var(--muted, #6b7280); text-align: left; cursor: copy; max-width: 100%; overflow-wrap: anywhere; }
.tem-prevol__email:hover { color: var(--text, #04151f); text-decoration: underline; }
.tem-prevol__email:focus-visible { outline: 2px solid var(--accent, #00AFB5); outline-offset: 2px; border-radius: 2px; }
.tem-prevol__aussi { display: block; font-size: 0.7rem; color: #1e40af; }
.tem-prevol__aussi b { font-variant-numeric: tabular-nums; }
.tem-prevol__postes { display: flex; flex-wrap: wrap; gap: 0.2rem; }
.tem-prevol__poste-puce { font-size: 0.72rem; font-weight: 800; background: var(--gris, #f3f4f6); border-radius: 6px; padding: 0 0.3rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tem-prevol__poste-puce.is-surveiller { background: #fef3c7; color: #92400e; }
.tem-prevol__carte-postes { margin-top: 0.25rem; }
.tem-prevol__carte .tem-prevol__nom { white-space: normal; overflow-wrap: anywhere; }
.tem-prevol__v {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 999px;
  font-weight: 800;
  font-size: 0.72rem;
  cursor: help;
}
.tem-prevol__v--ok { background: #ecfdf3; color: var(--success, #15803d); }
.tem-prevol__v--evite { background: #fef3c7; color: #92400e; }
.tem-prevol__v--off { background: var(--gris, #f3f4f6); color: var(--muted, #6b7280); }
.tem-prevol__v--non { background: #fef2f2; color: var(--danger, #A30000); }
.tem-prevol__pourquoi { background: none; border: 0; padding: 0; font: inherit; font-size: 0.76rem; color: var(--primary, #3b82f6); text-decoration: underline; cursor: pointer; }
.tem-prevol__legende { display: flex; flex-wrap: wrap; gap: 0.3rem 0.8rem; margin: 0.35rem 0 0; font-size: 0.74rem; color: var(--muted, #6b7280); }
.tem-prevol__legende > span { display: inline-flex; align-items: center; gap: 0.25rem; }
.tem-prevol__muet { color: var(--muted, #6b7280); font-size: 0.8rem; margin: 0.35rem 0 0; }
.tem-prevol__vide { margin: 0; padding: 0.6rem; color: var(--muted, #6b7280); }
.tem-prevol__bloc { border: 1px solid var(--line, #e5e7eb); border-radius: 10px; margin-top: 0.6rem; padding: 0 0.6rem; }
.tem-prevol__bloc summary { cursor: pointer; padding: 0.45rem 0; font-weight: 700; }
.tem-prevol__bloc > ul,
.tem-prevol__bloc > p { margin-bottom: 0.5rem; }
.tem-prevol__limites { border: 1px dashed #f59e0b; background: #fffbeb; border-radius: 10px; padding: 0.5rem 0.65rem; margin-top: 0.6rem; font-size: 0.8rem; color: #78350f; }
.tem-prevol__cartes { display: none; list-style: none; margin: 0; padding: 0; }
.tem-prevol__carte { padding: 0.45rem 0.5rem; border-bottom: 1px solid var(--line, #e5e7eb); font-size: 0.8rem; }
.tem-prevol__carte-tete { display: flex; justify-content: space-between; gap: 0.4rem; flex-wrap: wrap; }
.tem-prevol__puces { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.25rem; }
.tem-prevol__puce { font-size: 0.7rem; border-radius: 999px; padding: 0.05rem 0.4rem; background: var(--gris, #f3f4f6); }
.tem-prevol__puce--ok { background: #ecfdf3; color: var(--success, #15803d); }
.tem-prevol__puce--evite { background: #fef3c7; color: #92400e; }
.tem-prevol__puce--non { background: #fef2f2; color: var(--danger, #A30000); }
/* N-6 : en Mobile S, les lignes passent en cartes ; jamais de défilement horizontal de la page. */
@media (max-width: 640px) {
  .tem-prevol__table { display: none; }
  .tem-prevol__cartes { display: block; }
}
.tem-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
}
.tem-tile {
  padding: 0.8rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-tile-title {
  display: block;
  margin-bottom: 0.25rem;
  font-weight: 700;
}
.tem-stepper {
  display: grid;
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tem-stepper li {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: start;
}
.tem-stepper span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--brand, #004777);
  color: #fff;
  font-weight: 700;
}
.tem-station-preview {
  padding: 1rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-station-preview h3 {
  margin: 0 0 0.5rem;
  font-size: 1rem;
}
.tem-eval-grid {
  display: grid;
  gap: 0.7rem;
}
.tem-eval-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  padding: 0.75rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-score {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3rem;
  min-height: 2rem;
  border-radius: var(--radius, 6px);
  background: color-mix(in srgb, var(--accent, #00afb5) 16%, transparent);
  color: var(--brand, #004777);
  font-weight: 700;
}
/* En preset workspace, le corps s'étire (flex-column) pour que le plan occupe
   la hauteur fixe et que le pied reste collé en bas (voir .tem-body { flex }). */
dialog.tem-dialog.tem-size-workspace .tem-body {
  display: flex;
  flex-direction: column;
}
dialog.tem-dialog.tem-size-creation .tem-body {
  display: flex;
  flex-direction: column;
  padding: 0;
}
dialog.tem-dialog.tem-size-import .tem-body {
  display: flex;
  flex-direction: column;
  padding: 0;
}
.tem-creation {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
/* [2026-08-16] L'indicateur d'enregistrement est passé dans l'en-tête : la bande ne
   porte plus que la barre de progression, donc une seule colonne. Elle est entièrement
   masquée (attribut `hidden`) quand l'assistant passe `progress:false`. */
.tem-creation-top {
  display: block;
  padding: 10px 18px;
  border-bottom: 1px solid var(--line, #e5e7eb);
  background: color-mix(in srgb, var(--surface, #f9fafb) 88%, var(--accent, #00afb5) 4%);
}
.tem-creation-progress {
  display: grid;
  gap: 0.45rem;
  min-width: 0;
}
.tem-creation-progress-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
}
.tem-creation-progress-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text, #04151f);
  font-size: var(--text-sm, 0.875rem);
  font-weight: 700;
}
.tem-creation-progress-percent {
  flex: 0 0 auto;
  color: var(--brand, #004777);
  font-size: var(--text-sm, 0.875rem);
}
.tem-creation-progress-bar {
  height: 8px;
  overflow: hidden;
  border-radius: 999px;
  background: color-mix(in srgb, var(--line, #e5e7eb) 72%, var(--surface, #f9fafb) 28%);
}
.tem-creation-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: var(--accent, #00afb5);
  transition: width 0.2s ease;
}
.tem-creation-status {
  min-width: 9rem;
  margin: 0;
  justify-content: flex-end;
}
/* Même indicateur, replacé dans l'en-tête à gauche de la croix : il ne doit ni pousser
   le titre ni passer à la ligne, et s'efface tant qu'il est vide (`:empty` du socle).
   [2026-08-20] Séparé de la croix par un filet et une vraie marge : les deux étaient
   collés, au point qu'on visait l'un en croyant viser l'autre. Le filet est un
   pseudo-élément POSITIONNÉ, donc hors de la boîte : sans cela il serait peint à
   l'intérieur de la pastille teintée. `overflow: hidden` a été retiré pour la même
   raison (il découpait le filet) — l'ellipsis est portée par le texte interne. */
.tem-header-status {
  position: relative;
  flex: 0 0 auto;
  min-width: 0;
  max-width: 14rem;
  margin-right: 14px;
  white-space: nowrap;
}
.tem-header-status::after {
  content: "";
  position: absolute;
  right: -8px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 16px;
  background: var(--line, #e5e7eb);
}
/* [2026-09-19, demande QG] FENTE de largeur fixe qui porte l'indicateur d'enregistrement.
   Le défaut : la largeur du badge suivait son texte, et comme le bloc titre absorbe l'espace
   libre, tout ce qui PRÉCÈDE l'indicateur (recherche, annuler, refaire, aperçu, laboratoire,
   clavier) reculait à chaque changement d'état. Mesuré sur la modale station à 1120 px :
   138 px entre « vide » et « Enregistrement… », puis 34 px au succès, puis 50 px au repos,
   267 px d'amplitude totale avec les messages longs. QG : « c'est pénible », on clique à côté.
   La fente tient la place en permanence ; le badge garde sa largeur naturelle À L'INTÉRIEUR
   et reste collé à droite, donc aucune pastille ne change d'aspect. La règle `:empty` du
   socle reste en vigueur SUR LE BADGE : quand il n'y a rien à dire, la pastille et son filet
   disparaissent comme avant — c'est la fente, elle, qui ne disparaît jamais.
   Largeur : 42 px fixes depuis le 2026-09-25 (icône seule, bloc suivant) ; 16,5rem avant. */
.tem-header-status-slot {
  position: relative;
  flex: 0 0 42px;
  width: 42px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  min-width: 0;
}
/* Le badge ne peut pas déborder de sa fente (il passerait par-dessus les boutons voisins).
   Deux classes : il faut passer devant la copie de compatibilité `.te-save-status`
   d'admin.css, chargée APRÈS ce fichier et qui l'emporte donc à spécificité égale. */
.tem-header-status-slot > .tem-header-status {
  box-sizing: border-box;
  max-width: 100%;
}
/* [2026-09-25, maquette `indicateur-enregistrement-icone` validée par QG, place A, case 1 ;
   étendue à toutes les modales du preset le même jour] L'indicateur de l'en-tête est une ICÔNE
   SEULE de 28 px (`te-save-status--icon`, cf. form-save-status.js) : la fente ne réserve plus
   16,5rem mais 42 px FIXES (l'icône + les 14 px qui la séparent de la croix), sur tous les écrans.
   Le filet de séparation passe de la pastille à la fente. Il se montre dès l'ouverture quand la
   modale SUIT ses enregistrements (elle a donné un `statusId`, l'indicateur porte donc un `id`) :
   rien ne bouge à la première écriture. Une modale qui n'écrit jamais dans l'indicateur
   (inscription à une session, prévision, préparations) ne montre de filet que s'il parle. */
.tem-header-status-slot:is(:has(> .tem-header-status[id]), :has(> .tem-header-status:not(:empty)))::after {
  content: "";
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 16px;
  background: var(--line, #e5e7eb);
}
.tem-header-status-slot > .tem-header-status::after {
  content: none;
}
/* Le bloc titre absorbe l'espace libre : tout ce qui suit (indicateur d'enregistrement,
   barre de recherche de la modale station, croix) reste groupé à droite. Sans cela,
   deux éléments en `margin-left:auto` se partagent l'espace et l'indicateur flotte
   au milieu de l'en-tête. */
.tem-heading,
.tem-header-lead {
  flex: 1 1 auto;
}
.tem-creation-body {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
.tem-creation-body > * {
  flex: 1 1 auto;
  min-height: 0;
}
.tem-creation.is-initializing .tem-creation-body > *:not(.tem-creation-initializing) {
  display: none !important;
}
.tem-creation-initializing {
  display: flex;
  flex: 1 1 auto;
  /* 14rem suffisaient pour trois lignes ; avec la liste d'étapes le contenu s'allonge, mais le
     panneau ne doit pas pour autant étirer la modale de création sur toute sa hauteur pour si peu.
     `justify-content: center` garde le bloc centré quel que soit le nombre d'étapes. */
  min-height: 18rem;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 2rem;
  text-align: center;
}
.tem-creation-initializing[hidden] {
  display: none !important;
}
.tem-creation-initializing-title {
  color: var(--text, #04151f);
  font-size: var(--text-lg, 1.125rem);
  font-weight: 800;
}
.tem-creation-initializing-message {
  max-width: 28rem;
  margin: 0;
  color: var(--text-muted, #64748b);
  font-size: var(--text-sm, 0.875rem);
}
/* Liste d'étapes de l'écran d'initialisation (traitements longs : import IA d'une station).
   Alignée à gauche dans un panneau centré : une liste centrée se lit mal, l'oeil perd la colonne
   des marqueurs. */
.tem-creation-initializing-steps {
  width: 100%;
  max-width: 22rem;
  margin: 0.25rem 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
/* ⚠️ Le gap VERTICAL interne (libellé → détail, 1re valeur) doit rester NETTEMENT plus petit que
   le gap entre étapes de la liste ci-dessus : à 0.6rem contre 0.5rem, le détail était plus proche
   de l'étape SUIVANTE que de la sienne et se lisait comme une étape en plus. */
.tem-creation-step {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.6rem;
  font-size: var(--text-sm, 0.875rem);
  color: var(--text-muted, #64748b);
}
.tem-creation-step-marker {
  flex: 0 0 1rem;
  width: 1rem;
  text-align: center;
  line-height: 1;
}
/* Marqueur de l'étape EN COURS : le socle `.spinner` se dimensionne par variables. 14px tient dans
   la colonne des marqueurs sans décaler les libellés des autres étapes. */
.tem-creation-step-marker.spinner {
  --spinner-size: 14px;
  --spinner-stroke: 2px;
  align-self: center;
  /* ⚠️ `.spinner` porte `margin: 8px auto` (disposition « bloc centré » historique, spinner.css).
     Dans un conteneur flex, une marge auto ABSORBE tout l'espace libre : le spinner restait collé
     à gauche et poussait le libellé de l'étape au centre, alors que les autres étapes s'alignaient
     normalement. */
  margin: 0;
}
.tem-creation-initializing-spinner {
  --spinner-size: 22px;
  /* Panneau en flex column : `margin: auto` verticale absorberait l'espace et décollerait le
     spinner du titre. Marge explicite, indépendante du réglage global de `.spinner`. */
  margin: 0;
}
/* Étape à venir : pastille creuse — l'état reste lisible sans dépendre de la couleur seule. */
.tem-creation-step.is-todo .tem-creation-step-marker::before {
  content: '○';
}
.tem-creation-step.is-done {
  color: var(--text, #04151f);
}
.tem-creation-step.is-done .tem-creation-step-marker {
  color: var(--success, #0f766e);
}
.tem-creation-step.is-current {
  color: var(--text, #04151f);
  font-weight: 600;
}
/* Le détail décrit l'étape : il passe SOUS son libellé, aligné sur lui. Placé à côté, il volait la
   largeur au libellé, qui se cassait alors sur deux lignes. En text-xs : à la même taille que les
   libellés, il était indiscernable d'une étape à venir (elle aussi grise en text-sm). */
.tem-creation-step-detail {
  flex: 1 0 100%;
  margin-left: 1.6rem;
  color: var(--text-muted, #64748b);
  font-weight: 400;
  font-size: var(--text-xs, 0.8125rem);
}
/* Marge haute franche : collé à la liste, le hint semblait être le détail de la dernière étape. */
.tem-creation-initializing-hint {
  max-width: 28rem;
  margin: 0.75rem 0 0;
  color: var(--text-muted, #64748b);
  font-size: var(--text-xs, 0.8125rem);
}
.tem-creation-initializing-hint--warning {
  padding: 0.7rem 0.85rem;
  border: 1px solid color-mix(in srgb, var(--warning, #d97706) 45%, var(--line, #dbe3ea));
  border-radius: 0.6rem;
  background: color-mix(in srgb, var(--warning, #d97706) 11%, var(--surface, #fff));
  color: color-mix(in srgb, var(--warning, #d97706) 78%, var(--text, #0f172a));
  font-size: var(--text-sm, 0.875rem);
  font-weight: 650;
  line-height: 1.4;
  text-align: left;
}
.tem-creation-initializing-hint--warning::before {
  content: '⚠ ';
}
.tem-creation-initializing-hint[hidden],
.tem-creation-initializing-steps[hidden] {
  display: none !important;
}
/* [2026-08-16] Une seule ligne défilante au lieu de deux lignes qui bouclent : les
   assistants à 9-13 étapes reprenaient ~100 px de hauteur rien qu'en navigation. Le
   form-engine ramène l'étape active dans la vue à chaque changement (scrollStepIntoView). */
.tem-creation-body .te-form-stepper {
  display: flex;
  gap: 0.4rem;
  /* [2026-08-16] `flex: 0 0 auto` OBLIGATOIRE ici : `overflow-x` annule la protection
     `min-height: auto` des enfants flex, et le stepper se faisait écraser en hauteur
     (pastilles rognées à mi-hauteur, constaté aussitôt en preview). */
  flex: 0 0 auto;
  flex-wrap: nowrap;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* Barre de défilement native masquée : elle ajoutait ~12 px de hauteur, ce qu'on
     cherchait justement à récupérer. Le défilement reste possible (trackpad, molette
     horizontale, tactile) et l'étape active est ramenée dans la vue par le form-engine. */
  scrollbar-width: none;
  padding: 8px 18px;
  border-bottom: 1px solid var(--line, #e5e7eb);
  /* Indice de défilement sans JS : les deux premières couches (`local`) défilent avec le
     contenu et masquent l'ombre en début/fin de course ; les deux suivantes (`scroll`)
     restent fixes et signalent qu'il y a une suite à gauche ou à droite. */
  background-color: var(--surface, #f9fafb);
  background-image:
    linear-gradient(to right, var(--surface, #f9fafb), transparent),
    linear-gradient(to left, var(--surface, #f9fafb), transparent),
    radial-gradient(farthest-side at 0 50%, rgba(2, 8, 23, 0.16), transparent),
    radial-gradient(farthest-side at 100% 50%, rgba(2, 8, 23, 0.16), transparent);
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-size: 28px 100%, 28px 100%, 12px 100%, 12px 100%;
  background-repeat: no-repeat;
  background-attachment: local, local, scroll, scroll;
}
.tem-creation-body .te-form-stepper::-webkit-scrollbar {
  display: none;
}
.tem-creation-body .te-form-step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  white-space: nowrap;
  min-height: 30px;
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
  color: var(--muted, #6b7280);
  font: inherit;
  font-size: var(--text-sm, 0.875rem);
  font-weight: 700;
}
/* [2026-08-20 — demande QG] Pastilles COMPACTES : le numéro seul, le libellé réservé à
   l'étape active et aux étapes en défaut — et seulement tant que la barre ne déborde pas
   (l'arbitrage, avec son ordre de repli, vit dans form-engine.js : layoutStepperLabels).
   À 9 étapes (station) la barre passait de ~1330 à ~440 px, à 14 (épreuve) de ~2200 à
   ~670 px, pour ~1080 px disponibles : plus de défilement à l'aveugle, et les couleurs de
   statut des 14 étapes restent lisibles d'un coup d'œil.

   Masquer par DÉFAUT (et non l'inverse) : tant que rien n'est mesuré — modale en cours
   d'ouverture — la barre est déjà compacte, donc jamais débordante l'espace d'une frame.
   Le nom d'une pastille repliée se lit au survol, via le socle TimeEcosTooltip. */
.tem-creation-body .te-form-step .te-form-step-label {
  display: none;
}
.tem-creation-body .te-form-step[data-step-label="shown"] .te-form-step-label {
  display: inline;
}
/* Le point de séparation appartient au LIBELLÉ, pas au numéro : il disparaît avec lui,
   sans règle supplémentaire ni recalcul JS. */
.te-form-step-label::before {
  content: '.';
  margin-right: 0.28rem;
}
/* Largeur plancher : sans elle, « 1 » et « 14 » donnent des pastilles de tailles
   différentes et la rangée de numéros perd son alignement. */
.tem-creation-body .te-form-step .te-form-step-num {
  min-width: 0.9rem;
  text-align: center;
}
/* [2026-09-26, maquette validée par QG, case 6] NUMÉRO COLLÉ AU POINT : « 1. Informations », pas
   « 1 . Informations ». La largeur plancher ne sert qu'à aligner une rangée de pastilles repliées
   au numéro ; dès que le libellé s'affiche, elle centrait le chiffre dans sa boîte et laissait un
   blanc avant le point. Vaut pour tous les assistants du moteur (épreuve, station, préparation). */
.tem-creation-body .te-form-step[data-step-label="shown"] .te-form-step-num {
  min-width: 0;
}
/* [2026-08-20 — demande QG] Icône d'étape (`step.stepperIcon`), posée à droite du numéro.
   Elle ne se montre QUE sur une pastille REPLIÉE : dès que le libellé s'affiche, il dit mieux
   que l'icône de quoi il s'agit, et la pastille reste aussi étroite qu'avant l'ajout.
   Masquée par défaut hors de la modale de création, où les libellés ne se replient jamais :
   l'icône y ferait doublon avec le texte. */
.te-form-step-ic {
  display: none;
}
.tem-creation-body .te-form-step:not([data-step-label="shown"]) .te-form-step-ic {
  display: inline-flex;
  align-items: center;
  margin-left: 0.3rem;
}
/* Le SVG est construit par form-engine.js sans width/height : la taille se pose ici, une
   seule fois, et la couleur suit `currentColor` — donc le statut vert/orange/rouge. */
.te-form-step-ic svg {
  display: block;
  width: 15px;
  height: 15px;
}

.tem-creation-body .te-form-step.is-complete {
  border-color: color-mix(in srgb, var(--success, #15803d) 55%, var(--line, #e5e7eb));
  background: color-mix(in srgb, var(--success, #15803d) 11%, var(--bg, #fff));
  color: var(--success, #15803d);
}
.tem-creation-body .te-form-step.is-incomplete {
  border-color: var(--warning, #d97706);
  background: color-mix(in srgb, var(--warning, #d97706) 14%, var(--bg, #fff));
  color: color-mix(in srgb, var(--warning, #d97706) 88%, #7c2d12);
}
/* Étape en DÉFAUT ROUGE. Deux causes, un même geste attendu — aller corriger l'étape :
   - [2026-08-06] INCOHÉRENCE : l'étape est remplie mais son contenu est faux (ex. répartition
     étudiante au-delà de la capacité après avoir raccourci une session). Signale sans bloquer,
     la création reste possible et l'alerte dure vient à la publication ;
   - [2026-08-20, décision QG] ÉTAPE OBLIGATOIRE NON FAITE, qui EMPÊCHE de créer l'épreuve. Le
     stepper ne distinguait pas ces étapes des facultatives laissées de côté : toutes deux en
     orange `is-incomplete`, pendant que le récapitulatif les montrait déjà en rouge. L'hôte ne
     la pose que sur une étape DÉJÀ VISITÉE (ou depuis le récapitulatif), pour ne pas juger une
     étape que l'on n'a pas encore ouverte.
   L'infobulle dit laquelle des deux causes s'applique (`data-step-issue-tooltip`).
   Posé APRÈS le moteur, donc plus bas que `is-incomplete` : le rouge l'emporte sur l'orange. */
.tem-creation-body .te-form-step.has-issue {
  border-color: var(--danger, #dc2626);
  background: color-mix(in srgb, var(--danger, #dc2626) 12%, var(--bg, #fff));
  color: color-mix(in srgb, var(--danger, #dc2626) 85%, #450a0a);
}

/* [2026-09-13 — constat QG « ici sujet doit être orange, pas rouge »] Une étape dont TOUTES les
   anomalies sont des pages à compléter garde la pastille et l'infobulle, en avertissement. Un
   seul vrai échec parmi ses onglets la remet en rouge (`data-step-issue-variant="danger"`). */
.tem-creation-body .te-form-step.has-issue[data-step-issue-variant="warning"] {
  border-color: var(--warning, #f59e0b);
  background: color-mix(in srgb, var(--warning, #f59e0b) 14%, var(--bg, #fff));
  color: color-mix(in srgb, var(--warning, #f59e0b) 85%, #431407);
}

.tem-creation-body .te-form-step.is-active {
  font-weight: 900;
  box-shadow: inset 0 0 0 1px currentColor, 0 0 0 1px currentColor;
}
.tem-creation-body .te-form-step.is-active:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}
.tem-creation-body .te-form-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 18px 24px;
  overflow-y: auto;
}
.tem-creation-body .te-form-panel {
  max-width: 100%;
}
.tem-creation-body .te-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 16px;
}
.tem-creation-body .te-form-field--full {
  grid-column: 1 / -1;
}

/* Champ en erreur (form-engine) : encadré rouge + message visible, pour repérer
   immédiatement quel champ corriger (le moteur pose déjà la classe is-invalid). */
.te-form-field.is-invalid input:not([type="radio"]):not([type="checkbox"]),
.te-form-field.is-invalid select,
.te-form-field.is-invalid textarea,
.te-form-field.is-invalid .form-input,
.te-form-field.is-invalid .form-select,
.te-form-field.is-invalid [contenteditable="true"] {
  border-color: var(--danger, #dc2626) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger, #dc2626) 18%, transparent);
}
.te-form-field.is-invalid .form-label {
  color: var(--danger, #dc2626);
}
.te-form-error {
  margin: 4px 0 0;
  color: var(--danger, #dc2626);
  font-size: 0.85rem;
  font-weight: 600;
}

/* Case présentée en INTERRUPTEUR (`variant: 'switch'` du form-engine, 2026-09-22, maquette validée
   par QG). Ici, UNIQUEMENT la mise en page de l'option : la piste, un vrai espace, le libellé. La
   piste, l'état coché, le focus et le grisé viennent de l'interrupteur existant
   (`epreuve-automations-switch__input` / `__track`, admin.css) que le moteur réutilise.
   ⚠️ `position: relative` n'est pas décoratif : l'input est masqué en position absolue, il se
   recalerait sur le premier ancêtre positionné, donc hors de son option. */
.te-form-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  cursor: pointer;
}

/* Le libellé passe à la ligne s'il le faut (Mobile S) ; la piste, elle, ne rétrécit JAMAIS : à
   320 px, un interrupteur écrasé à 20 px ne se lit plus ni ne se vise. */
.te-form-switch > :not(:last-child) {
  flex: 0 0 auto;
}

.te-form-switch > span:last-child {
  min-width: 0;
  white-space: normal;
}

.te-form-switch:has(input:disabled) {
  color: var(--muted, #6b7280);
  cursor: not-allowed;
}

/* Regroupement REPLIABLE du moteur de formulaire (`fieldset` + `collapsible`, 2026-09-19).
   Premier usage : le bloc « Objectifs et attendus » de l'étape « Informations » d'une station,
   dont les trois listes occupaient tout l'écran devant des champs remplis à chaque station.
   L'en-tête est un vrai bouton (clavier et lecteur d'écran compris) ; le résumé n'apparaît que
   REPLIÉ, puisque déplié le bloc montre déjà son contenu. */
.te-form-fieldset--collapsible {
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 10px;
  padding: 6px 12px 12px;
}
.te-form-fieldset--collapsible.is-collapsed {
  padding-bottom: 6px;
}
.te-form-fieldset-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.te-form-fieldset-toggle:focus-visible {
  outline: 2px solid var(--accent, #14b8c4);
  outline-offset: 2px;
  border-radius: 6px;
}
.te-form-fieldset-toggle .form-label {
  margin: 0;
  cursor: pointer;
}
.te-form-fieldset-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--muted, #94a3b8);
  transition: transform 0.15s ease;
}
.te-form-fieldset-chevron svg {
  width: 16px;
  height: 16px;
}
/* Replié : le chevron pointe vers la droite (le bloc s'ouvre vers le bas). */
.te-form-fieldset--collapsible.is-collapsed .te-form-fieldset-chevron {
  transform: rotate(-90deg);
}
/* Le résumé dit ce que le bloc cache : le nombre de lignes de chaque rubrique, rien d'autre. */
.te-form-fieldset-summary {
  margin-left: auto;
  color: var(--muted, #6b7280);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}
.te-form-fieldset-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 4px;
}
.tem-creation-body .te-form-footer {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 24px 14px;
  border-top: 1px solid var(--line, #e5e7eb);
  background: var(--surface, #f9fafb);
}
.tem-creation-body .te-form {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
  flex-direction: column;
}
.tem-creation-body > div {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
.tem-creation-body .te-form-status {
  margin-top: 0.75rem;
  color: var(--danger, #b42318);
  font-weight: 600;
}
.tem-creation-body .timer-profile-phase-row {
  display: grid;
  grid-template-columns: minmax(14rem, 1fr) auto auto auto auto;
  gap: 0.75rem;
  align-items: center;
}
.tem-creation-body .timer-profile-phase-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.tem-creation-body .timer-profile-duration-field {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  color: var(--muted, #6b7280);
  font-size: var(--text-sm, 0.875rem);
}
.tem-creation-body .timer-profile-duration-field .form-input {
  width: 4.25rem;
  text-align: center;
}
.tem-creation-body .timer-profile-color-picker {
  position: relative;
  display: inline-flex;
  justify-content: center;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
.tem-creation-body .timer-profile-color-picker .phase-color-trigger {
  width: 32px;
  height: 32px;
  border: 2px solid var(--surface, #fff);
  border-radius: 8px;
  box-shadow: 0 0 0 1px var(--line, #e5e7eb);
  cursor: pointer;
}
.tem-creation-body .timer-profile-color-picker .phase-color-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  display: flex;
  gap: 6px;
  padding: 6px;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 8px;
  background: var(--surface, #fff);
  box-shadow: var(--shadow-md, 0 12px 24px rgba(15, 23, 42, 0.14));
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
}
.tem-creation-body .timer-profile-color-picker .phase-color-menu[hidden] {
  display: none;
}
.tem-creation-body .timer-profile-color-picker .phase-color-swatch {
  width: 24px;
  height: 24px;
  border: 2px solid var(--surface, #fff);
  border-radius: 7px;
  box-shadow: 0 0 0 1px var(--line, #e5e7eb);
  cursor: pointer;
}
.tem-creation-body .timer-profile-color-picker .phase-color-swatch.is-active {
  box-shadow: 0 0 0 2px var(--text, #111827);
}

/* Preset `importFlow` — grand flux d'import avec contenu métier libre
   (CSV, panier, aperçu, résultats) et progression serveur optionnelle. */
.tem-import-flow {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
.tem-import-flow-top {
  padding: 10px 18px;
  border-bottom: 1px solid var(--line, #e5e7eb);
  background: color-mix(in srgb, var(--surface, #f9fafb) 92%, var(--accent, #00afb5) 3%);
}
.tem-import-flow-top[hidden] {
  display: none !important;
}
.tem-import-flow-progress {
  display: grid;
  gap: 0.4rem;
}
.tem-import-flow-progress-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
}
.tem-import-flow-progress-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text, #04151f);
  font-size: var(--text-sm, 0.875rem);
  font-weight: 700;
}
.tem-import-flow-progress-percent {
  flex: 0 0 auto;
  color: var(--muted, #6b7280);
  font-size: var(--text-sm, 0.875rem);
}
.tem-import-flow-progress-bar {
  height: 6px;
  overflow: hidden;
  border-radius: 999px;
  background: color-mix(in srgb, var(--line, #e5e7eb) 72%, var(--surface, #f9fafb) 28%);
}
.tem-import-flow-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: var(--accent, #00afb5);
  transition: width 0.2s ease;
}
.tem-import-flow-body {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
.tem-import-flow-body > * {
  flex: 1 1 auto;
  min-height: 0;
}

/* Indicateur de sauvegarde partage par les assistants de creation. Il vit ici
   car le preset `creation` peut etre utilise hors admin.css, notamment owner-config. */
.te-save-status {
  margin: 0;
  padding: 4px 10px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 240px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--muted, #6b7280);
  background: transparent;
  transition: background-color 0.2s ease, color 0.2s ease, padding 0.2s ease, gap 0.2s ease;
}

.te-save-status:empty {
  display: none;
}

.te-save-status-txt {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 14rem;
  opacity: 1;
  transition: max-width 0.25s ease, opacity 0.2s ease;
}

.te-save-status-ico {
  display: inline-flex;
  flex: 0 0 14px;
  width: 14px;
  height: 14px;
}

.te-save-status-ico svg {
  width: 14px;
  height: 14px;
}

/* [2026-08-20] Pastilles teintées : même vocabulaire visuel que les badges de statut de la
   banque de stations (fond doux + texte foncé de la même famille). */
.te-save-status.is-success { background: color-mix(in srgb, var(--success, #16a34a) 16%, white 84%); color: #15803d; }
.te-save-status.is-unsaved { background: color-mix(in srgb, #f59e0b 15%, white 85%); color: #92400e; }
.te-save-status.is-loading { background: color-mix(in srgb, #6b7280 12%, white 88%); color: #4b5563; }
.te-save-status.is-error { background: color-mix(in srgb, var(--danger, #dc2626) 15%, white 85%); color: #991b1b; }
.te-save-status.is-note { background: color-mix(in srgb, #6b7280 10%, white 90%); color: #4b5563; }
.te-save-status.is-loading .te-save-status-ico svg { animation: te-save-status-spin 0.8s linear infinite; }

/* Repos : 3 s après un succès, le texte se replie et il ne reste qu'une icône discrète.
   Le texte reste dans le DOM (réduit en CSS) pour les lecteurs d'écran, et pour que la
   région aria-live ne ré-annonce pas un contenu vidé. Seul le succès retombe : « Non
   enregistré », un échec ou un message d'état persistant restent lisibles. */
.te-save-status.is-idle { background: transparent; color: var(--muted, #6b7280); padding: 4px 0; gap: 0; }
.te-save-status.is-idle .te-save-status-txt { max-width: 0; opacity: 0; }
.te-save-status.is-idle .te-save-status-ico { flex: 0 0 17px; width: 17px; height: 17px; }
.te-save-status.is-idle .te-save-status-ico svg { width: 17px; height: 17px; }

@keyframes te-save-status-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .te-save-status,
  .te-save-status-txt { transition: none; }
  .te-save-status.is-loading .te-save-status-ico svg { animation-duration: 2.4s; }
}

/* [2026-09-25, maquette `indicateur-enregistrement-icone` validée par QG, cases 1, 3 et 4]
   Variante ICÔNE SEULE (`te-save-status--icon`, posée par le preset `creation` avec
   `statusDisplay: 'icon'`). L'élément ne porte plus de pastille : c'est l'icône, ronde, 28 px,
   focalisable, qui prend la teinte de l'état ; l'état et son détail passent dans l'infobulle
   `TimeEcosTooltip`. Le texte reste dans le DOM, masqué visuellement, pour la région aria-live.
   ⚠️ Bloc présent À L'IDENTIQUE dans time-ecos-modal.css et admin.css, APRÈS les états : la copie
   d'admin.css, chargée après, l'emporterait sinon à spécificité égale. */
.te-save-status.te-save-status--icon {
  padding: 0;
  gap: 0;
  max-width: none;
  border-radius: 0;
  background: transparent;
}
.te-save-status--icon .te-save-status-txt {
  position: absolute;
  width: 1px;
  height: 1px;
  max-width: none;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.te-save-status--icon .te-save-status-ico,
.te-save-status--icon.is-idle .te-save-status-ico {
  position: relative;
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  color: var(--muted, #6b7280);
  background: transparent;
  cursor: default;
}
.te-save-status--icon .te-save-status-ico > svg { width: 16px; height: 16px; }
.te-save-status--icon.is-idle .te-save-status-ico > svg { width: 17px; height: 17px; }
.te-save-status--icon .te-save-status-ico:focus-visible {
  outline: 2px solid var(--accent, #00afb5);
  outline-offset: 2px;
}
.te-save-status--icon.is-success .te-save-status-ico { background: color-mix(in srgb, var(--success, #16a34a) 16%, white 84%); color: #15803d; }
.te-save-status--icon.is-unsaved .te-save-status-ico { background: color-mix(in srgb, #f59e0b 15%, white 85%); color: #92400e; }
.te-save-status--icon.is-loading .te-save-status-ico { background: color-mix(in srgb, #6b7280 12%, white 88%); color: #4b5563; }
.te-save-status--icon.is-error .te-save-status-ico { background: color-mix(in srgb, var(--danger, #dc2626) 15%, white 85%); color: #991b1b; }
.te-save-status--icon.is-note .te-save-status-ico { background: color-mix(in srgb, #6b7280 10%, white 90%); color: #4b5563; }
.te-save-status--icon.is-idle .te-save-status-ico { background: transparent; color: var(--muted, #6b7280); }
/* Case 4 : nombre de champs non écrits, en pastille sur l'icône d'alerte. */
.te-save-status-compte {
  position: absolute;
  top: -3px;
  right: -4px;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  border-radius: 999px;
  background: #991b1b;
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  line-height: 15px;
  text-align: center;
}

.tem-workspace {
  display: grid;
  grid-template-columns: minmax(180px, 0.3fr) minmax(0, 1fr);
  gap: 1rem;
  flex: 1 1 auto;
  min-height: 420px;
}
.tem-workspace-sidebar,
.tem-workspace-canvas {
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-workspace-sidebar {
  padding: 0.8rem;
}
.tem-workspace-canvas {
  min-height: 420px;
  background:
    linear-gradient(var(--line, #e5e7eb) 1px, transparent 1px),
    linear-gradient(90deg, var(--line, #e5e7eb) 1px, transparent 1px),
    var(--surface, #f9fafb);
  background-size: 32px 32px;
  position: relative;
  overflow: hidden;
}
.tem-workspace-zone {
  position: absolute;
  left: 14%;
  top: 18%;
  width: 38%;
  height: 34%;
  border: 2px solid var(--brand, #004777);
  border-radius: var(--radius, 6px);
  background: color-mix(in srgb, var(--brand, #004777) 12%, transparent);
}
.tem-workspace-room {
  position: absolute;
  right: 14%;
  bottom: 18%;
  width: 24%;
  height: 22%;
  border: 2px solid var(--accent, #00afb5);
  border-radius: var(--radius, 6px);
  background: color-mix(in srgb, var(--accent, #00afb5) 16%, transparent);
}

/* ------------------------------------------------------------
   Preset `station` — cadre de la modale d'affichage de station
   (barre de vues + contenu principal + rail visio/PJ + slot chrono).
   Le contenu métier est injecté par l'appelant (station-display.js).
   ------------------------------------------------------------ */
dialog.tem-dialog.tem-size-station .tem-body {
  display: flex;
  flex-direction: column;
  padding: 0;
}
.tem-station {
  display: flex;
  flex: 1 1 auto;
  min-height: 0;
  flex-direction: column;
}
/* Barre de vues par rôle (Aperçu / Médecin / PS-PSS / Évaluateur) */
.tem-station-views {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 12px 18px;
  /* Pas de border-bottom : le fond gris sépare déjà des onglets ; la bordure pleine
     largeur réapparaissait sous le bandeau de progression (inset) de l'onglet Évaluateur. */
  background: var(--surface, #f9fafb);
}
.tem-station-views[hidden] { display: none; }
.tem-station-view-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
  color: var(--muted, #6b7280);
  font: inherit;
  font-weight: 700;
  font-size: var(--text-sm, 0.875rem);
  cursor: pointer;
  transition: var(--transition, 0.2s ease);
}
.tem-station-view-btn:hover { border-color: var(--accent, #00afb5); }
.tem-station-view-btn.is-active {
  border-color: var(--accent, #00afb5);
  background: color-mix(in srgb, var(--accent, #00afb5) 14%, var(--bg, #fff));
  color: var(--brand, #004777);
}
.tem-station-view-btn:focus-visible { outline: 2px solid var(--accent, #00afb5); outline-offset: 2px; }

/* Barre de disposition station (en-tête) */
dialog.tem-dialog.tem-size-station .tem-heading {
  flex: 1 1 auto;
}
.tem-station-layout-tools {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.2rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-station-layout-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: var(--radius, 6px);
  background: transparent;
  color: var(--muted, #6b7280);
  cursor: pointer;
}
.tem-station-layout-btn:hover {
  color: var(--brand, #004777);
  background: color-mix(in srgb, var(--accent, #00afb5) 10%, transparent);
}
.tem-station-layout-btn.is-active {
  color: var(--brand, #004777);
  background: color-mix(in srgb, var(--accent, #00afb5) 18%, var(--bg, #fff));
}
.tem-station-layout-btn:focus-visible { outline: 2px solid var(--accent, #00afb5); outline-offset: 2px; }
.tem-station-layout-btn .lucide-icon,
.tem-station-layout-btn svg {
  width: 17px;
  height: 17px;
}

/* Corps : contenu principal (gauche) + rail latéral (droite) */
.tem-station-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.36fr);
  gap: 1rem;
  flex: 1 1 auto;
  min-height: 0;
  padding: 18px;
  overflow: hidden;
}
dialog.tem-dialog.tem-size-station.tem-station-layout--half .tem-station-layout {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
dialog.tem-dialog.tem-size-station.tem-station-layout--focus .tem-station-layout {
  grid-template-columns: minmax(0, 0.36fr) minmax(0, 1fr);
}
/* [2026-08-28] Rail masqué (cache d'avant-démarrage d'une station d'entraînement, ou rail
   vidé de ses panneaux) : la colonne latérale restait réservée et le contenu principal
   paraissait décalé à gauche. Sélecteur volontairement plus spécifique que les 3 règles de
   disposition ci-dessus, pour les neutraliser toutes. La disposition « pleine largeur » est
   déjà en `display: block` : elle n'est pas concernée. */
dialog.tem-dialog.tem-size-station .tem-station-layout:has(> .tem-station-rail[hidden]) {
  grid-template-columns: minmax(0, 1fr);
}
/* [2026-07-25] « Pleine largeur » : une seule colonne, le rail retombe SOUS le contenu — le
   rendu déjà appliqué d'office sous 900px, ici offert comme choix sur grand écran.
   ⚠️ Volontairement 100 % CSS : les blocs ne sont PAS déménagés dans le DOM. `setupBlockDocking`
   (station-display.js) tient des ancres de retour et un placeholder de glisser-déposer ; les
   déplacer ici perdrait les ancres et casserait « Réinitialiser la disposition ». Revenir à
   « standard » suffit donc à tout remettre en place, et le drag & drop marche dans les 2 rendus. */
dialog.tem-dialog.tem-size-station.tem-station-layout--full .tem-station-layout {
  display: block;
  overflow-y: auto;
}
dialog.tem-dialog.tem-size-station.tem-station-layout--full .tem-station-main,
dialog.tem-dialog.tem-size-station.tem-station-layout--full .tem-station-rail {
  overflow: visible;
}
dialog.tem-dialog.tem-size-station.tem-station-layout--full .tem-station-rail {
  margin-top: 0.85rem;
}
.tem-station-main {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
}
.tem-station-view[hidden] { display: none; }
.tem-station-rail {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
}
.tem-station-rail[hidden] { display: none; }
/* [2026-08-27] Retrait aligné sur `.station-view-block` (station-display.css) : 0.95rem 1rem
   au lieu de 0.85rem. Les panneaux et les blocs partagent déjà bordure, rayon et fond ; seul le
   retrait différait, ce qui se voyait dès qu'un panneau était glissé au milieu des blocs. Avec
   les titres alignés le même jour, un panneau déplacé dans la colonne principale est désormais
   indiscernable d'un bloc. ⚠️ Valeur dupliquée de `.station-view-block` : si l'une bouge,
   bouger l'autre. */
.tem-station-visio,
.tem-station-psia,
.tem-station-attachments {
  padding: 0.95rem 1rem;
  border: 1px solid var(--line, #e5e7eb);
  border-radius: var(--radius, 6px);
  background: var(--bg, #fff);
}
.tem-station-visio[hidden],
.tem-station-psia[hidden],
.tem-station-attachments[hidden] { display: none; }

/* Capsule chrono lecture seule, posée dans l'en-tête (branchée au lot chrono) */
.tem-station-chrono {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  margin-left: auto;
}
.tem-station-chrono[hidden] { display: none; }

/* Capsule chrono du slot : rendu commun du site (chrono-capsule.js, styles dans
   chrono-capsule.css ; branchée par station-chrono-capsule.js). Petits écrans :
   l'en-tête est serré → en cours, le nom de phase se retire (sa couleur reste), temps et
   position restent. « Terminé », « Pause » et « En pause » restent écrits. */
@media (max-width: 640px) {
  .tem-station-chrono .te-capsule[data-etat="en_cours"] .te-capsule__libelle { display: none; }
}

/* [2026-09-22, lot 3 du chantier « capsule chrono »] Fente posée à droite du TITRE, dans la
   pastille de méta (poserCapsuleEnTete, emplacement « titre » : hub de session, dont la droite de
   l'en-tête porte la bascule et la publication). La rangée du titre passe à la ligne quand la
   place manque : la capsule descend sous le titre au lieu de le serrer lettre à lettre (N-6).
   Sans chrono (capsule masquée), la pastille de méta ne garde aucune place. */
.tem-title-row:has(> .tem-header-meta > .tem-station-chrono) { flex-wrap: wrap; }
/* [2026-09-26] …sauf si la pastille de méta porte autre chose que la capsule : dans le hub de
   session, elle porte aussi les pastilles d'épreuve et de session et la date, qui disparaissaient
   avec la capsule quand aucun chrono ne tournait. */
.tem-header-meta:has(> .tem-station-chrono > .te-capsule[hidden]):not(:has(> :not(.tem-station-chrono))) { display: none; }

/* Titres de section de la galerie owner « Affichage des modales ». */
.tem-station-demo-title { margin: 0 0 0.4rem; font-size: 1rem; }

/* Tablette portrait / mobile : passage en une seule colonne, le corps défile en entier */
@media (max-width: 899px) {
  /* Barres (rôles + Fiche/Visio/PJ) fixes en tête : seul le panneau de contenu
     actif défile en interne → les barres restent toujours visibles. Le corps de
     la modale ne défile pas lui-même (sinon les barres partiraient au scroll). */
  dialog.tem-dialog.tem-size-station .tem-body { overflow: hidden; }
  .tem-station-layout {
    display: block;
    overflow-y: auto;
  }
  .tem-station-main,
  .tem-station-rail { overflow: visible; }
  .tem-station-rail { margin-top: 0.85rem; }
  /* Plus de sticky par barre : c'est l'enveloppe .station-sticky-head qui se fige
     (les deux barres se chevauchaient quand chacune visait le même top:0). */
  .tem-station-views {
    flex-wrap: nowrap;
    overflow-x: auto;
  }
  .tem-station-layout-tools [data-station-layout-mode="half"] { display: none; }
  /* Sous-titre (présent uniquement sur la vue Aperçu) : 1 ligne tronquée pour
     gagner de la hauteur sur mobile/tablette ; le détail reste dans l'Aperçu. */
  dialog.tem-dialog.tem-size-station .tem-subtitle {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

/* Petits écrans : cadre quasi plein écran, boutons tactiles sans étirement forcé */
@media (max-width: 560px) {
  dialog.tem-dialog { padding: 8px; }
  .tem-frame { max-width: 100%; max-height: 94vh; }
  dialog.tem-dialog.tem-size-creation .tem-frame {
    height: calc(100vh - 16px);
    max-height: calc(100vh - 16px);
  }
  dialog.tem-dialog.tem-size-import .tem-frame {
    height: calc(100vh - 16px);
    max-height: calc(100vh - 16px);
  }
  /* Station : collée en haut (sous la status bar), hauteur dynamique + safe-area */
  dialog.tem-dialog.tem-size-station[open] { align-items: flex-start; }
  dialog.tem-dialog.tem-size-station {
    padding:
      max(8px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right))
      max(8px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
  }
  dialog.tem-dialog.tem-size-station .tem-frame {
    height: auto;
    max-height: 96dvh;
  }
  .tem-station-layout { padding: 14px; }
  .tem-header {
    align-items: flex-start;
    padding: 14px 14px;
  }
  .tem-title { font-size: 1rem; }
  .tem-subtitle { font-size: 0.8rem; }
  .tem-creation-top {
    padding: 10px 14px;
  }
  .tem-creation-status {
    justify-content: flex-start;
    min-width: 0;
  }
  /* [2026-09-25] Plus de plafond mobile (8rem, 14rem en erreur, depuis le 2026-08-20) :
     l'indicateur de l'en-tête est une icône de 28 px dans une fente de 42 px fixes (cf.
     `.tem-header-status-slot`), le message d'échec se lit dans son infobulle. */
  .tem-creation-body .te-form-stepper {
    padding: 8px 14px;
  }
  .tem-import-flow-top {
    padding: 10px 14px;
  }
  .tem-actions {
    justify-content: flex-end;
    align-items: center;
  }
  .tem-actions .btn {
    width: auto !important;
    flex: 0 0 auto;
    min-width: 112px;
    min-height: 44px;
    max-width: 100%;
  }
  .tem-eval-row { grid-template-columns: 1fr; }
  .tem-workspace { grid-template-columns: 1fr; }
  .tem-workspace-canvas { min-height: 320px; }
}
