/* ==========================================================================
   OpenLabCSS — composants spécifiques (apps / pages)
   --------------------------------------------------------------------------
   Chargé APRÈS openlab.css et AVANT styles.css (cf. core/templates/core/base.html).
   Ordre : Pico → openlab.css → components.css → styles.css.

   Rôle (cf. doc/openlabcss.md) :
   - openlab.css = primitives génériques (layouts + composants de base).
   - components.css = composants propres à une app ou des règles propres à une
     page, factorisés hors des templates (plus de bloc <style> ni d'inline).
   - Les styles propres à une page sont scopés sous une classe racine dédiée
     (ex. `.logistics-list`) afin de ne jamais fuir vers d'autres pages.
   ========================================================================== */

/* ==========================================================================
   Composant : badge de formation (trainings)
   Déplacé depuis trainings/templates/components/training_badge.html.
   ========================================================================== */

.training-badge {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    text-decoration: none;
    color: inherit;
    max-width: 80px;
}
.training-badge:hover .training-badge__icon {
    opacity: 0.85;
    transform: scale(1.06);
}
.training-badge__icon-wrap {
    position: relative;
    display: inline-block;
}
.training-badge__icon {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid transparent;
    transition: opacity 0.15s, transform 0.15s;
}
.training-badge__icon--validated {
    border-color: #4caf7d;
    background-color: #4caf7d;
}
.training-badge__icon--required {
    border-color: var(--pico-secondary-border);
    background-color: #151D34;
}
.training-badge__icon--optional {
    border-color: var(--pico-secondary-border);
    background-color: #151D34;
    opacity: 0.7;
}
.training-badge__check {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background-color: #4caf7d;
    color: #fff;
    font-size: 0.75rem;
    font-weight: bold;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--pico-background-color, #fff);
    line-height: 1;
}
.training-badge__label {
    font-size: 0.75rem;
    text-align: center;
    max-width: 80px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--pico-color);
}
.training-badge__optional-tag {
    font-size: 0.65rem;
    color: var(--pico-muted-color);
    font-style: italic;
}

/* ==========================================================================
   Composant : icône ronde de formation (trainings)
   Icône circulaire sur pastille colorée, avec calque `icon_foreground`
   optionnel superposé. Le fond signale la certification de l'utilisateur.

   Deux zones (règle des ≥ 2 zones) dans trainings/templates/trainings/
   training.html : l'en-tête de la fiche et la grille des formations
   prérequises. Remplace les `style=""` inline qui y étaient dupliqués.

   Variante plus riche (taille fixe, libellé, pastille ✓) : `.training-badge`
   ci-dessus, utilisé par la fiche machine. Les deux gagneraient à partager une
   primitive commune — refactor à faire quand une 3ᵉ zone apparaîtra.
   ========================================================================== */

.training-icon {
    position: relative;
    display: inline-block;
    flex-shrink: 0;
    /* Couleurs de marque, volontairement identiques en clair et en sombre :
       la pastille doit rester lisible derrière une icône détourée. */
    --ol-training-icon-bg: #151D34;
    --ol-training-icon-bg-validated: #75B758;
}

.training-icon__img {
    display: block;
    max-height: 100px;
    border-radius: 50%;
    background-color: var(--ol-training-icon-bg);
}

.training-icon--validated .training-icon__img {
    background-color: var(--ol-training-icon-bg-validated);
}

/* Calque décoratif superposé à l'icône (même gabarit, donc même max-height). */
.training-icon__overlay {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    z-index: 3;
    max-height: 100px;
}

/* ==========================================================================
   Composant : carte membre (équipe étudiante / salariés / anciens membres)
   Utilisé par core/about.html et core/old_members.html (règle des ≥ 2 zones).
   Avatar circulaire + méta centrées ; remplace le style inline des deux pages.
   Les contacts (LinkedIn / Portfolio / e-mail) vivent dans `.member-card__links`.
   ========================================================================== */

.member-card {
    text-align: center;
}
.member-card__avatar {
    width: 120px;
    height: 120px;
    border-radius: 50%;
    object-fit: cover;
    margin: 0 auto var(--ol-space-md);
    display: block;
}
.member-card__avatar--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--pico-primary) 0%, var(--pico-primary-hover) 100%);
    color: var(--pico-primary-inverse, #fff);
    font-size: 2rem;
    font-weight: bold;
    text-transform: uppercase;
}
.member-card__name {
    margin-bottom: var(--ol-space-xs);
}
.member-card__job {
    margin: 0;
    color: var(--pico-muted-color);
    font-size: 0.875rem;
}
.member-card__meta {
    margin-top: var(--ol-space-sm);
    font-size: 0.8rem;
    color: var(--pico-muted-color);
}
.member-card__links {
    justify-content: center;
    margin-top: var(--ol-space-md);
}

/* ==========================================================================
   Page : catalogue logistique (liste articles, vues cartes + tableau)
   Déplacé depuis logistics/templates/logistics/model_list.html.
   Scopé sous `.logistics-list` pour ne pas affecter les autres pages.
   ========================================================================== */

.logistics-list table {
  font-size: 0.8rem;
}

/* Filtres en en-tête de colonne (vue tableau). */
.logistics-list th .col-filter {
  display: block;
  margin-top: 0.25rem;
}
.logistics-list th .col-filter select,
.logistics-list th .col-filter input {
  width: 100%;
  font-size: 0.75rem;
  padding: 0.2rem 0.4rem;
}
.logistics-list th .col-filter .range-inputs {
  display: flex;
  gap: 0.2rem;
}
.logistics-list th .col-filter .range-inputs input {
  width: 60px;
}

/* Fourchette d'inputs dans la barre de filtres (vue cartes). */
.logistics-list .filter-bar .filter-range {
  display: flex;
  gap: 0.25rem;
}
.logistics-list .filter-bar .filter-range input {
  width: 80px;
}

/* ── Socle éditeur riche markdown (feat/183) ────────────────────────────────── */

/* Conteneur de rendu markdown sanitizé (core.markdown.render_markdown). Utilisé
   partout où un contenu riche est affiché (descriptions machines/formations,
   consignes de session…). Neutralise la marge haute du premier bloc et borne les
   médias/tables à la largeur du conteneur. */
.markdown-body > :first-child {
  margin-top: 0;
}
.markdown-body > :last-child {
  margin-bottom: 0;
}
.markdown-body img {
  max-width: 100%;
  height: auto;
}
.markdown-body pre {
  overflow-x: auto;
}

/* ==========================================================================
   Composant : actualités (news)
   ========================================================================== */
.news-card-grid {
  align-items: stretch;
}
.news-card {
  display: flex;
  flex-direction: column;
}
.news-card img,
.news-cover {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;
}
.news-card h2,
.news-card h3 {
  margin-top: var(--ol-space-sm);
}
.news-card p {
  flex-grow: 1;
}
.news-meta,
.news-taxonomy {
  color: var(--pico-muted-color);
  font-size: 0.9rem;
}
.news-taxonomy {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ol-space-xs);
}
.news-taxonomy span {
  border: 1px solid var(--pico-muted-border-color);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
}
.news-article {
  max-width: 900px;
  margin-inline: auto;
}
.news-share__actions,
.news-projects ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ol-space-sm);
}
.news-share__actions {
  padding: 0;
}
.news-share__status {
  min-height: 1.5rem;
  margin-top: var(--ol-space-sm);
  color: var(--pico-muted-color);
}
.news-manage-status--draft,
.news-manage-status--scheduled {
  color: var(--pico-muted-color);
}

/* ==========================================================================
   Composant : sélection d'équipe pédagogique (trainings — session_form)
   --------------------------------------------------------------------------
   Chips = checkbox « animateur » stylées en pastilles à bordure ; l'étoile ★
   (radio) désigne le responsable. 100 % CSS, aucun JS. La bordure/le fond
   accent signalent l'appartenance à l'équipe (coché OU responsable, car le
   responsable est implicitement animateur).
   ========================================================================== */

.staff-field {
  border: none;
  padding: 0;
  margin-block: var(--ol-space-md);
}
.staff-field > legend {
  font-weight: bold;
  padding: 0;
}
.staff-field__hint {
  display: block;
  color: var(--pico-muted-color);
  margin-bottom: var(--ol-space-sm);
}
.staff-field__error {
  display: block;
  color: var(--ol-danger-fg);
  margin-bottom: var(--ol-space-sm);
}

.staff-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ol-space-sm);
}

.staff-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--ol-space-xs);
  padding: var(--ol-space-xs) var(--ol-space-sm);
  border: 2px solid var(--pico-muted-border-color);
  border-radius: 2rem;
  transition: border-color 0.15s, background-color 0.15s;
}

/* Inputs natifs masqués : les <label> englobants restent cliquables. */
.staff-chip input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.staff-chip__toggle,
.staff-chip__star {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  user-select: none;
  line-height: 1;
}
.staff-chip__star {
  color: var(--pico-muted-color);
  font-size: 1.05rem;
  transition: color 0.15s, transform 0.15s;
}
.staff-chip__star:hover {
  transform: scale(1.15);
}

/* Membre de l'équipe (animateur coché OU responsable) → bordure + fond bleu ESIEA. */
.staff-chip:has(input:checked) {
  border-color: var(--esiea-blue);
  background-color: color-mix(in srgb, var(--esiea-blue) 14%, transparent);
}
/* Responsable → étoile dorée pleine (repère distinct du bleu « membre »). */
.staff-chip:has(input[type="radio"]:checked) .staff-chip__star {
  color: #f4b400;
}

/* Accessibilité clavier : anneau de focus sur la chip quand un input est focus. */
.staff-chip:has(input:focus-visible) {
  outline: 2px solid var(--esiea-blue);
  outline-offset: 2px;
}

/* Widget d'édition EasyMDE : borne la largeur à la colonne du formulaire. */
.EasyMDEContainer {
  max-width: 100%;
}

/* Thème EasyMDE aligné sur Pico : ses couleurs sont codées en dur (fond blanc,
   texte noir). On les remappe sur les variables --pico-* pour que l'éditeur suive
   automatiquement le mode clair ET sombre. La spécificité (préfixe .EasyMDEContainer)
   l'emporte sur le CSS vendorisé, chargé après dans le <head>. */
.EasyMDEContainer .CodeMirror {
  color: var(--pico-form-element-color, var(--pico-color));
  background-color: var(--pico-form-element-background-color);
  border-color: var(--pico-form-element-border-color);
}
.EasyMDEContainer .CodeMirror-cursor {
  border-left-color: var(--pico-color);
}
.EasyMDEContainer .CodeMirror-selected {
  background: var(--pico-text-selection-color, rgba(128, 128, 128, 0.3));
}
.EasyMDEContainer .CodeMirror-gutters {
  background-color: var(--pico-form-element-background-color);
  border-right-color: var(--pico-form-element-border-color);
}
.EasyMDEContainer .CodeMirror-linenumber {
  color: var(--pico-muted-color);
}
.EasyMDEContainer .CodeMirror-activeline-background {
  background: rgba(128, 128, 128, 0.12);
}
.EasyMDEContainer .editor-toolbar {
  border-color: var(--pico-form-element-border-color);
}
/* Pico redéfinit --pico-color localement sur <button> (= --pico-primary-inverse,
   blanc fixe pour ses boutons pleins) : var(--pico-color) s'y résout donc sur
   cette valeur locale, pas sur la couleur de texte du body. Même contournement
   que .CodeMirror ci-dessus, via une variable que Pico ne redéfinit pas sur
   button. */
.EasyMDEContainer .editor-toolbar button {
  color: var(--pico-form-element-color, var(--pico-color));
}
.EasyMDEContainer .editor-toolbar button.active,
.EasyMDEContainer .editor-toolbar button:hover {
  background: rgba(128, 128, 128, 0.15);
  border-color: var(--pico-muted-border-color);
}
.EasyMDEContainer .editor-toolbar i.separator {
  border-left-color: var(--pico-muted-border-color);
  border-right-color: transparent;
}
.EasyMDEContainer .editor-statusbar {
  color: var(--pico-muted-color);
}
.EasyMDEContainer .editor-preview,
.EasyMDEContainer .editor-preview-side {
  background-color: var(--pico-background-color);
  color: var(--pico-color);
  border-color: var(--pico-form-element-border-color);
}
.EasyMDEContainer .editor-preview pre,
.EasyMDEContainer .editor-preview code {
  background: var(--pico-code-background-color, rgba(128, 128, 128, 0.2));
}

/* Widget de sélection Select2 (django-select2, #27) : même piège qu'EasyMDE
   ci-dessus, couleurs codées en dur (fond blanc, texte gris foncé). Ici la
   spécificité seule ne suffit pas : ce fichier est chargé dans <head> AVANT le CSS
   vendorisé de select2 (`form.media.css`, servi par le bloc `custom_head` des
   templates de formulaire), donc à spécificité égale le CSS vendorisé — chargé
   après — gagnerait et écraserait ces règles. D'où `!important`, déjà le
   contournement choisi pour FullCalendar (voir calendar.css). */
.select2-container--default .select2-selection--single {
  background-color: var(--pico-form-element-background-color) !important;
  border-color: var(--pico-form-element-border-color) !important;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
  color: var(--pico-form-element-color, var(--pico-color)) !important;
}
.select2-container--default .select2-selection--single .select2-selection__placeholder {
  color: var(--pico-muted-color) !important;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b {
  border-color: var(--pico-muted-color) transparent transparent transparent !important;
}
.select2-container--default.select2-container--disabled .select2-selection--single {
  background-color: var(--pico-form-element-disabled-background-color, var(--pico-form-element-background-color)) !important;
}
.select2-dropdown {
  background-color: var(--pico-form-element-background-color) !important;
  border-color: var(--pico-form-element-border-color) !important;
  color: var(--pico-form-element-color, var(--pico-color));
}
.select2-container--default .select2-search--dropdown .select2-search__field {
  background-color: var(--pico-form-element-background-color) !important;
  color: var(--pico-form-element-color, var(--pico-color)) !important;
  border-color: var(--pico-form-element-border-color) !important;
}
.select2-container--default .select2-results__option {
  color: var(--pico-form-element-color, var(--pico-color));
}
.select2-container--default .select2-results__option[aria-selected="true"] {
  background-color: rgba(128, 128, 128, 0.2) !important;
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
  background-color: var(--pico-primary) !important;
  color: var(--pico-primary-inverse) !important;
}

/* ------------------------------------------------------------------ */
/* Plan d'espace interactif (floorplan) — cf. machines/espace_detail  */
/* ------------------------------------------------------------------ */
.floorplan {
  width: 100%;
  overflow-x: auto;
}
.floorplan svg {
  width: 100%;
  height: auto;
  display: block;
}
/* Zones cliquables (id="machine-<short_name>"), activées par floorplan.js */
.machine-zone {
  cursor: pointer;
  transition: fill 0.15s ease, opacity 0.15s ease, filter 0.15s ease;
}
.machine-zone:hover,
.machine-zone:focus-visible {
  opacity: 0.85;
  filter: brightness(1.08);
  outline: 2px solid var(--ol-accent, var(--pico-primary));
  outline-offset: 1px;
}

/* ------------------------------------------------------------------ */
/* Modale de confirmation / alerte (.ol-modal) — cf. doc/modal.md     */
/* Composant JS openlabModal (modal.bundle.js) remplaçant             */
/* confirm()/alert(). PicoCSS stylise déjà <dialog>/::backdrop ;      */
/* on ne cadre ici que la largeur et l'alignement des boutons.        */
/* ------------------------------------------------------------------ */
.ol-modal article {
  max-width: 32rem;
}
.ol-modal footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--ol-space-sm);
}
.ol-modal footer button {
  width: auto;
  margin: 0;
}
.ol-modal footer button[hidden] {
  display: none;
}

/* ------------------------------------------------------------------ */
/* Tableau de bord de gestion (.dashboard-*) — cf. doc/dashboard.md   */
/* KPI tiles + en-têtes de graphiques. Les graphiques eux-mêmes sont  */
/* rendus par Chart.js (dashboard.js) dans des <canvas>.              */
/* ------------------------------------------------------------------ */
.dashboard-toolbar {
  align-items: center;
  justify-content: flex-end;
  margin-bottom: var(--ol-space-md);
}
.dashboard-generated {
  margin-right: auto;
  color: var(--pico-muted-color);
}
.dashboard-api {
  margin-top: var(--ol-space-lg);
}
.dashboard-api pre {
  white-space: pre-wrap;
  word-break: break-all;
}
.dashboard-kpis {
  margin-bottom: var(--ol-space-md);
}
.dashboard-kpi {
  text-align: center;
}
.dashboard-kpi-value {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  margin: 0;
  color: var(--ol-accent, var(--pico-primary));
}
.dashboard-kpi-label {
  margin: var(--ol-space-xs) 0 0;
  color: var(--pico-muted-color);
  font-size: 0.85rem;
}
.dashboard-chart-header {
  align-items: center;
  justify-content: space-between;
}
.dashboard-inline-select {
  margin: 0;
  font-size: 0.85rem;
}
.dashboard-inline-select select {
  margin: 0;
  width: auto;
  display: inline-block;
}

/* ------------------------------------------------------------------ */
/* Page formations (.trainings-home) — cf. trainings/templates/trainings/home.html */
/* Bascule graphe/liste par classe racine (liste par défaut) + verrouillage */
/* du graphe sur mobile (inutilisable en tactile, cf. retour test UX).      */
/* ------------------------------------------------------------------ */
.trainings-home #graphCard {
  display: none;
}
.trainings-home.view-graph #graphCard {
  display: block;
}
.trainings-home.view-graph #listCard {
  display: none;
}

.trainings-home #cy {
  width: 100%;
  height: 80vh;
  background-color: var(--cy-bg);
}

@media (max-width: 768px) {
  .trainings-home #toggleBtn {
    display: none;
  }
  .trainings-home.view-graph #graphCard {
    display: none;
  }
  .trainings-home.view-graph #listCard {
    display: block;
  }
}
/* Environnement de développement : avertissement visible sur la page d'accueil. */
.debug-banner {
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  border: 1px solid var(--pico-color-amber-400, #f5a524);
  border-radius: var(--pico-border-radius);
  background: var(--pico-color-amber-100, #fff3cd);
  color: var(--pico-color-amber-950, #5c3b00);
  font-weight: 700;
  text-align: center;
}
