/* =============================================================
   OS25 — COUCHE D'IDENTITÉ
   assets/css/os25.css — 7 septembre 2026

   BORN. SPIDER. CERCLE. From Idea to Impact.

   ── CE FICHIER REMPLACE studio25.css, ET IL FAUT DIRE POURQUOI

   Le 7 septembre au matin, la consigne était : « chouf site
   kifach dayr, ghadi nraje3 OS b7alo » — mettre l'OS au langage
   d'el25studio.ma. J'ai donc écrit une couche qui remplaçait l'or
   par le pistache, Inter par Manrope, le bleu nuit par une nuit
   neutre.

   Le brief OS25 reçu l'après-midi dit l'inverse, et il est
   explicite :

     Background #05080D · Surface #0A1018 · Surface élevée #0E1621
     Border rgba(120,150,190,.14) · Texte #F5F7FA · Muted #8C98AA
     Gold #F2B940 · Purple #8B5CF6 · Blue #258BFF
     Cyan #12D9FF · Green #24D981 · Orange #F7A928 · Red #FF4D55

   C'est la palette que `neon-systeme.css` portait déjà. Autrement
   dit : la couche pistache était une réponse juste à une question
   qui a changé. Elle est retirée, pas corrigée — un demi-pistache
   sur un système or aurait été le pire des deux.

   ⚠ CE QUI EST GARDÉ DE studio25.css : les trois corrections
   qu'elle avait apportées et qui n'ont rien à voir avec la
   couleur. Elles sont reprises telles quelles plus bas, avec leur
   explication. Le reste est parti.

   ── CE QUE FAIT CE FICHIER

   Il ne repeint pas : il pose l'IDENTITÉ que le brief demande et
   que la palette seule ne donne pas.

     1. les jetons du brief, à la valeur exacte ;
     2. les deux moteurs — SPIDER violet, CERCLE cyan — visibles
        dans le menu et sur Command Vision ;
     3. l'échelle de Command Vision : un hero qui se lit debout,
        à trois mètres de l'écran ;
     4. le rail IDEA → IMPACT ;
     5. les corrections d'écran héritées.

   ── ORDRE DE CHARGEMENT
   tokens → base → shell → components → pages → neon →
   neon-systeme → espace → perf → CE FICHIER

   Retirer son <link> dans app.html rend à l'OS son apparence
   d'avant, à l'identique.

   ⚠ ON ÉCRIT `[data-theme="dark"]`, JAMAIS `:root`, pour une
   couleur de thème. `[data-theme="light"]` a la même spécificité
   que `:root` ; ce fichier étant chargé après, un `:root` ici
   repeindrait le thème clair en noir, et le défaut n'apparaîtrait
   qu'au premier clic sur le bouton soleil/lune.
   ============================================================= */


/* =============================================================
   1. LES JETONS DU BRIEF, À LA VALEUR EXACTE

   `neon-systeme.css` avait dérivé sur trois valeurs : la surface
   à #0B1119 au lieu de #0A1018, la surface élevée à #0E1621
   (juste), le muted à #8792A5 au lieu de #8C98AA. L'écart ne se
   voit pas à l'œil — et c'est précisément le problème : deux
   valeurs pour une même couleur, c'est deux vérités, et dans six
   mois personne ne saura laquelle est la bonne. On aligne sur le
   brief, qui fait foi.
   ============================================================= */
[data-theme="dark"] {
  --n-fond:      #05080D;   /* Background      */
  --n-fond-2:    #070B12;   /* creux, en-têtes */
  --n-surface:   #0A1018;   /* Surface         */
  --n-surface-h: #0E1621;   /* Surface élevée  */

  --n-bord:      rgba(120,150,190,.14);
  --n-bord-fort: rgba(120,150,190,.28);

  --n-tx:        #F5F7FA;
  --n-tx-2:      #8C98AA;

  --n-or:        #F2B940;   /* décision, CTA, priorité        */
  --n-violet:    #8B5CF6;   /* SPIDER, créatif, post-prod     */
  --n-bleu:      #258BFF;   /* production active              */
  --n-cyan:      #12D9FF;   /* progression, info active       */
  --n-vert:      #24D981;   /* succès, disponible, validé     */
  --n-orange:    #F7A928;   /* attente, risque                */
  --n-rouge:     #FF4D55;   /* retard, blocage, critique      */

  --n-or-lueur:  rgba(242,185,64,.28);

  /* Les deux moteurs. Ce ne sont pas de nouvelles couleurs : ce
     sont des NOMS posés sur celles du brief, pour qu'une règle
     qui parle de SPIDER se lise comme telle. */
  --spider: var(--n-violet);
  --cercle: var(--n-cyan);

  --n-carte:   linear-gradient(180deg, rgba(14,22,33,.96), rgba(7,11,18,.96));
  --n-carte-h: linear-gradient(180deg, rgba(19,29,43,.97), rgba(10,16,24,.97));

  /* Le pont vers components.css / pages.css / shell.css, qui ne
     connaissent que les anciens noms. */
  --line:       var(--n-bord);
  --line-soft:  rgba(120,150,190,.08);
  --tx-1:       var(--n-tx);
  --tx-2:       var(--n-tx-2);
  --tx-3:       #6C7A8C;
  --brand:      var(--n-or);
  --brand-tx:   #0A0D12;
  --brand-soft: rgba(242,185,64,.12);
  --brand-line: rgba(242,185,64,.34);
  --c-commercial: var(--n-or);

  /* ── LE MOTION SYSTEM DU BRIEF, EN CHIFFRES
     micro 150–220 · survol 180–260 · tiroir 250–400 ·
     section 300–500 · hero 600–900. Une valeur par usage, une
     seule, pour que deux écrans ne respirent jamais à des
     vitesses différentes. */
  --t-micro:   180ms;
  --t-survol:  220ms;
  --t-tiroir:  320ms;
  --t-section: 400ms;
  --t-hero:    720ms;
  --courbe:    cubic-bezier(.22, .61, .36, 1);

  scrollbar-color: rgba(120,150,190,.24) transparent;
  scrollbar-width: thin;
}


/* =============================================================
   6. TROIS CORRECTIONS D'ÉCRAN, HÉRITÉES DE studio25.css

   Elles ne concernent pas la couleur : elles corrigent des
   défauts trouvés en ouvrant l'application. Elles survivent au
   changement de direction visuelle.
   ============================================================= */

/* ── La pastille de phase s'étirait sur toute la hauteur.

   `pages.css:849` pose `.gal-phase { position:absolute;
   left:10px; bottom:10px }`. `neon-systeme.css:1102`, chargé
   après, la redéclare en `top:10px; left:10px` — sans annuler le
   `bottom`. Un élément absolu qui porte À LA FOIS `top` et
   `bottom` ne se dimensionne plus par son contenu : il s'étire
   d'un bord à l'autre. Sur chaque carte de l'écran Projets, un
   libellé de deux mots occupait 98 × 185 px, mesuré. Ça datait du
   5 septembre et l'analyse statique ne pouvait pas le voir. */
.gal-phase { bottom: auto; }

/* ── Le sigle du projet prioritaire écrasait son titre.

   L'affiche composée est dessinée sur 320 × 200 puis étirée sur
   toute la largeur de la scène : le sigle, prévu pour une
   vignette, arrivait à plus de 300 px de haut derrière le titre.
   On le garde — c'est la texture voulue — mais à la moitié. */
.scene-fond .affiche.affiche-generee { opacity: .5; }

/* ── Le pied de panneau creusait au noir.
   `rgba(0,0,0,.16)` sur une carte déjà sombre donne un trou ;
   une surface claire à 3 % donne une marche. */
[data-theme="dark"] .panel-foot { background: rgba(120,150,190,.05); }


/* =============================================================
   7. MOUVEMENT RÉDUIT
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  .affiche { transition: none !important; }
  .voie-carte:hover .voie-visuel .affiche,
  .gal-carte:hover .gal-visuel .affiche,
  .affiche-carte:hover .affiche-visuel .affiche { transform: none; }
  .nav-cat-btn::before { transition: none; }
}

/* =============================================================
   9. LA PROVENANCE D'UN CLIENT

   Quatre origines, quatre couleurs prises dans la palette du
   brief — aucune nouvelle teinte :

     Radar 25   cyan     la prospection à froid du studio
     Publicité  violet   ce que SPIDER a payé pour faire venir
     Lead       or       un contact entrant qualifié
     Direct     neutre   personne n'a noté d'où il venait

   Le neutre pour « Direct » est délibéré : ce n'est pas une
   provenance, c'est une absence de provenance, et lui donner une
   couleur la ferait passer pour un canal.
   ============================================================= */
.badge.prov-radar  { background: rgba(18,217,255,.12);  color: var(--n-cyan);   border-color: rgba(18,217,255,.30); }
.badge.prov-ads    { background: rgba(139,92,246,.14);  color: var(--n-violet); border-color: rgba(139,92,246,.32); }
.badge.prov-lead   { background: rgba(242,185,64,.13);  color: var(--n-or);     border-color: rgba(242,185,64,.30); }
.badge.prov-direct { background: rgba(120,150,190,.10); color: var(--n-tx-2);   border-color: var(--n-bord); }

/* Les puces de filtre reprennent la même couleur, mais seulement
   une fois allumées : au repos elles restent grises, sinon la
   rangée de filtres redevient un arc-en-ciel avant même qu'on ait
   choisi quoi que ce soit. */
.chip.prov-radar.is-on  { background: rgba(18,217,255,.14);  border-color: rgba(18,217,255,.40); color: var(--n-cyan); box-shadow: none; }
.chip.prov-ads.is-on    { background: rgba(139,92,246,.16);  border-color: rgba(139,92,246,.42); color: var(--n-violet); box-shadow: none; }
.chip.prov-lead.is-on   { background: rgba(242,185,64,.14);  border-color: rgba(242,185,64,.40); color: var(--n-or); box-shadow: none; }
.chip.prov-direct.is-on { background: rgba(120,150,190,.14); border-color: var(--n-bord-fort); color: var(--n-tx); box-shadow: none; }
.chip b.mono { margin-left: 6px; opacity: .75; font-variant-numeric: tabular-nums; }

/* =============================================================
   10. LIVE LOAD

   Grille asymétrique, et ici elle est justifiée : la file est le
   sujet de l'écran, l'équipe est la ressource qu'on lui applique.
   Deux colonnes égales auraient dit qu'on regarde autant l'une
   que l'autre — ce n'est pas vrai, on part toujours de ce qui
   attend.
   ============================================================= */
.live-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.28fr) minmax(300px, .72fr);
  gap: 12px;
  align-items: start;
}
@media (max-width: 1100px) { .live-grid { grid-template-columns: 1fr; } }

/* Une ligne de file porte beaucoup : signal, titre, client, phase,
   date, porteurs, action. Le sujet prend la place restante, tout
   le reste garde sa largeur — sinon le titre d'un projet long
   pousse la date hors de l'écran. */
.live-ligne { align-items: center; gap: 12px; }
.live-ligne > :not(.live-sujet) { flex: none; }
.live-sujet { display: flex; flex-direction: column; gap: 4px; min-width: 0; text-decoration: none; }
.live-sujet .progress { margin-top: 2px; }
.live-porteurs .avatar { margin-left: -6px; border: 1px solid var(--n-fond); }
.live-porteurs .avatar:first-child { margin-left: 0; }

/* Le filet de département sur le bord gauche, comme les cartes. */
.live-ligne[class*="dep-"] { border-left: 2px solid color-mix(in srgb, var(--dep) 60%, transparent); }

.live-membre { align-items: center; gap: 12px; }
.live-membre > .grow { min-width: 0; display: flex; flex-direction: column; }

/* Le bandeau d'ETA manquante : il informe, il n'alarme pas. Pas de
   rouge — rien n'est cassé, il manque une colonne. */
.eta-manquante {
  border-left: 2px solid var(--n-cyan);
  background: rgba(18,217,255,.05);
}
.eta-manquante .eyebrow { color: var(--n-cyan); }

/* =============================================================
   11. BORN — L'ESPACE CLIENT

   Le client n'a pas trente dossiers : il en a deux ou trois. On
   peut donc lui donner ce qu'un écran interne ne peut pas se
   permettre — une grande image par projet. C'est aussi ce que le
   brief demande : « grandes images projet ».

   Un format large plutôt que carré : une affiche de film se
   regarde en paysage, et ça évite qu'un seul projet occupe tout
   l'écran avant qu'on ait vu le deuxième.
   ============================================================= */
.born-projet { overflow: hidden; }
.born-visuel {
  position: relative;
  aspect-ratio: 21 / 9;
  overflow: hidden;
  background: var(--n-fond-2);
}
.born-visuel .affiche { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }

/* Le voile : deux dégradés, comme partout ailleurs. */
.born-visuel::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(0deg, rgba(5,8,13,.92) 0%, transparent 58%),
    linear-gradient(180deg, rgba(5,8,13,.45), transparent 30%);
}

/* Le sur-titre est un BLOC. En ligne, il se collait au titre —
   « PRÉPARATIONAftermovie ». */
.born-projet .eyebrow { display: block; margin-bottom: 6px; }
.born-titre {
  display: block;
  font-size: 20px; font-weight: 700; letter-spacing: -.02em;
  color: var(--n-tx);
  margin-bottom: 6px;
}
.born-projet .progress { margin-top: 14px; }

/* La ligne qui dit ce qui manque. Elle informe, elle n'alarme
   pas : pas de rouge, pas d'icône d'erreur. */
.born-attente { display: block; color: var(--n-tx-2); }
.born-avis { border-left: 2px solid var(--n-or); background: rgba(242,185,64,.05); }
.born-avis .eyebrow { color: var(--n-or); }

/* =============================================================
   12. LA FILMOTHÈQUE — LE RAIL

   Un rail qui s'arrête sur une affiche, pas sur un écran. Le
   défilement et son inertie viennent du navigateur : on ne
   réécrit pas une physique que le système fait mieux.
   ============================================================= */
.filmo-tete {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}
.filmo-piste {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Le rail déborde volontairement de la page : une affiche coupée
     au bord dit « ça continue », là où un rail qui s'arrête net
     laisse croire qu'on a tout vu. */
  padding: 2px 2px 14px;
  scrollbar-width: thin;
}
.filmo-case {
  flex: 0 0 clamp(280px, 27vw, 400px);
  scroll-snap-align: start;
}
.filmo-case > * { height: 100%; }
.filmo-piste::-webkit-scrollbar { height: 8px; }
.filmo-piste::-webkit-scrollbar-thumb {
  background: rgba(120,150,190,.20);
  border-radius: 999px;
}
.filmo-piste::-webkit-scrollbar-track { background: transparent; }

/* Sur le rail, l'affiche prend plus de place que dans la grille :
   c'est tout l'intérêt d'être passé en filmothèque. */
.filmo-case .gal-visuel { aspect-ratio: 3 / 2; }

/* =============================================================
   13. UN REPLI QUI SE REPLIE AUSSI SUR ORDINATEUR

   `.repliable` ne se ferme qu'en dessous de 1100 px (components.css
   :357). C'est juste pour un panneau de lecture — on ne fait pas
   cliquer quelqu'un pour voir ce qu'il y a la place d'afficher.

   Ça ne l'est pas pour un formulaire facultatif : cinq champs
   ouverts au-dessus d'un bouton d'enregistrement se lisent comme
   cinq champs à remplir, sur n'importe quel écran. `repli-toujours`
   applique la même mécanique à toutes les largeurs.

   On répète les règles au lieu de les sortir de la media query :
   components.css n'est pas à nous, et une couche qui déplace des
   règles d'une feuille qu'elle ne possède pas finit par les casser
   le jour où cette feuille change.
   ============================================================= */
.repliable.repli-toujours .repliable-tete { cursor: pointer; }
.repliable.repli-toujours .repliable-tete:hover h3 { color: var(--n-or); }
.repliable.repli-toujours .repliable-chevron { display: flex; }
.repliable.repli-toujours[data-open="false"] .repliable-chevron { transform: rotate(-90deg); }
.repliable.repli-toujours .repliable-corps {
  display: grid; grid-template-rows: 1fr;
  transition: grid-template-rows var(--t-survol) var(--courbe);
}
.repliable.repli-toujours[data-open="false"] .repliable-corps { grid-template-rows: 0fr; }
.repliable.repli-toujours .repliable-corps > * { overflow: hidden; min-height: 0; }

/* Le repli d'un formulaire facultatif n'est pas une carte : il ne
   doit pas peser autant qu'un panneau de contenu. */
.repliable.repli-toujours { background: none; border: 1px dashed var(--n-bord); box-shadow: none; }
.repliable.repli-toujours .repliable-tete { padding: 10px 14px; }
.repliable.repli-toujours .repliable-tete h3 {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-2);
}

/* =============================================================
   14. CE QUI VIENT APRÈS, DANS LA MISSION

   La ligne qui compte les entreprises à venir n'est pas une
   entreprise : elle ne doit pas se lire comme une ligne de plus
   dans la liste. Un filet pointillé et une teinte plus basse
   suffisent — on comprend que c'est un compte, pas un contact.
   ============================================================= */
.a-venir-bloc {
  border-top: 1px dashed var(--n-bord-fort);
  background: rgba(120,150,190,.04);
}
.a-venir-bloc .strong { color: var(--n-tx-2); }

/* =============================================================
   16. LIVE LOAD — LA FORME DE LA RÉFÉRENCE
   `OS25_NEW_SCREENS/05-responsable-production.png`

   Deux colonnes de cartes. À gauche la queue : une carte par
   dossier, filet de couleur de phase, temps à droite. À droite le
   Live Load : nom en capitales, pastille d'état, barre de charge.

   Le filet coloré est sur le BORD, jamais en fond : quatre cartes
   teintées l'une sous l'autre redonnent l'arc-en-ciel que tout le
   reste de l'OS évite.
   ============================================================= */
.queue-col { display: flex; flex-direction: column; gap: 10px; }
.queue-carte {
  padding: 14px 16px;
  border: 1px solid var(--n-bord);
  border-left: 2px solid color-mix(in srgb, var(--dep, var(--n-bleu)) 75%, transparent);
  border-radius: var(--n-r-m);
  background: rgba(120,150,190,.04);
  transition: border-color var(--t-survol) var(--courbe), background var(--t-survol) var(--courbe);
}
.queue-carte:hover { background: rgba(120,150,190,.07); border-color: var(--n-bord-fort); }
.queue-carte.brule { border-left-color: var(--n-rouge); }
.queue-titre {
  font-size: 14.5px; font-weight: 700; color: var(--n-tx);
  text-decoration: none; min-width: 0;
}
.queue-titre:hover { color: var(--n-or); }
.queue-temps {
  font-family: var(--f-mono); font-size: 13px; font-weight: 700;
  color: color-mix(in srgb, var(--dep, var(--n-bleu)) 85%, white);
  white-space: nowrap; flex: none;
}
.queue-temps.rouge { color: var(--n-rouge); }
.queue-carte .progress { margin-top: 10px; }

/* ── LIVE LOAD : une carte par personne. */
.load-carte {
  padding: 14px 16px;
  border: 1px solid var(--n-bord);
  border-radius: var(--n-r-m);
  background: rgba(120,150,190,.04);
  margin-bottom: 10px;
}
.load-carte:last-child { margin-bottom: 0; }
.load-point { width: 9px; height: 9px; border-radius: 50%; background: var(--etat, var(--n-vert)); flex: none; }
.load-nom { font-size: 14px; font-weight: 700; letter-spacing: .04em; color: var(--n-tx); }
.load-etat {
  font-size: 10px; font-weight: 700; letter-spacing: .12em;
  padding: 5px 12px; border-radius: 999px;
  color: var(--etat, var(--n-vert));
  border: 1px solid color-mix(in srgb, var(--etat, var(--n-vert)) 55%, transparent);
  white-space: nowrap; flex: none;
}
.load-temps {
  font-size: 12px; font-weight: 600;
  color: var(--etat, var(--n-vert));
  white-space: nowrap; flex: none;
}
.load-barre {
  height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(120,150,190,.14); margin-top: 10px;
}
.load-barre i {
  display: block; height: 100%; width: var(--h, 0%);
  border-radius: 999px; background: var(--etat, var(--n-vert));
  transition: width var(--t-grande, 640ms) var(--courbe);
}

/* Les cinq états de la référence, chacun sa couleur. */
.load-carte.etat-dispo  { --etat: var(--n-vert); }
.load-carte.etat-light  { --etat: var(--n-vert); }
.load-carte.etat-charge { --etat: var(--n-bleu); }
.load-carte.etat-sature { --etat: var(--n-rouge); }
.load-carte.etat-retard { --etat: var(--n-orange); }

.min0 { min-width: 0; }


/* =============================================================
   LA MISSION ACTIVE — l'écran du technicien
   Composition du build V12, captures du 7 septembre 2026.

   Une image plein cadre, la consigne en grand par-dessus,
   l'échéance dans le coin haut droit, les objectifs en bas.
   ============================================================= */
.mission-active {
  position: relative;
  min-height: 430px;
  margin-bottom: 16px;
  border: 1px solid rgba(120,150,190,.16);
  border-radius: 22px;
  overflow: hidden;
  background: #05080d;
  box-shadow: 0 34px 90px -38px #000;
  display: grid;
  grid-template-rows: 1fr auto;
}
.ma-fond { position: absolute; inset: 0; }
.ma-fond .affiche { width: 100%; height: 100%; object-fit: cover; filter: saturate(1.05) brightness(.72); }
/* Deux voiles superposés : l'un tient le texte à gauche, l'autre le
   bas. Un seul obligerait à noircir toute l'image. */
.ma-voile {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(90deg, rgba(4,7,11,.96) 0%, rgba(4,7,11,.74) 42%, rgba(4,7,11,.18) 78%),
    linear-gradient(0deg, rgba(4,7,11,.94), transparent 58%);
}

.ma-corps { position: relative; z-index: 2; align-self: end; padding: 38px 42px 26px; max-width: 720px; }
.ma-pill {
  display: inline-block; padding: 8px 15px; border-radius: 999px;
  background: #f2b940; color: #080b10;
  font: 800 10px/1 "JetBrains Mono", monospace; letter-spacing: .14em; text-transform: uppercase;
}
.ma-kicker {
  display: block; margin: 22px 0 10px;
  font: 800 10px/1 "JetBrains Mono", monospace; letter-spacing: .2em;
  text-transform: uppercase; color: #12d9ff;
}
.ma-titre {
  margin: 0; font-size: clamp(30px, 3.4vw, 52px); font-weight: 800;
  line-height: .98; letter-spacing: -.045em; color: #fff;
  text-shadow: 0 8px 30px rgba(0,0,0,.75); text-wrap: balance;
}
.ma-sous { margin: 14px 0 0; max-width: 560px; font-size: 14px; color: #cbd5e1; }
.ma-actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-top: 24px; }
.ma-lien { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: #aab4c3; text-decoration: none; }
.ma-lien:hover { color: #fff; }

/* L'échéance : une carte posée dans le coin, comme la référence. */
.ma-echeance {
  position: absolute; z-index: 3; right: 26px; top: 24px;
  min-width: 210px; padding: 18px 20px;
  border: 1px solid rgba(120,150,190,.18); border-radius: 14px;
  background: rgba(5,8,13,.72); backdrop-filter: blur(14px);
}
.ma-echeance .eyebrow { color: #8c98aa; }
.ma-jour { display: block; margin-top: 10px; font: 800 12px/1 "JetBrains Mono", monospace; letter-spacing: .14em; color: #24d981; }
.ma-jour.rouge { color: #ff4d55; }
.ma-date { display: block; margin-top: 8px; font-size: 30px; font-weight: 800; letter-spacing: -.03em; color: #fff; }
.ma-temps { display: block; margin-top: 10px; font-size: 11px; color: #8c98aa; }

/* Les objectifs, sur fond plein sous l'image. */
.ma-objectifs {
  position: relative; z-index: 2;
  padding: 22px 42px 26px;
  border-top: 1px solid rgba(120,150,190,.14);
  background: rgba(5,8,13,.92);
}
.ma-liste { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 10px 30px; margin: 14px 0 18px; }
.ma-obj { display: flex; align-items: baseline; gap: 12px; font-size: 14px; color: #dce3ed; }
.ma-num { font: 800 10px/1 "JetBrains Mono", monospace; color: #12d9ff; flex: none; }
.ma-lu {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 16px 18px; border: 1px solid rgba(242,185,64,.3); border-radius: 12px;
  background: rgba(242,185,64,.05); cursor: pointer;
}
.ma-lu input { width: 20px; height: 20px; accent-color: #f2b940; flex: none; margin-top: 2px; }
.ma-lu b { display: block; font-size: 14px; }
.ma-lu .hint { display: block; margin-top: 4px; }

@media (max-width: 900px) {
  .mission-active { min-height: 0; }
  .ma-echeance { position: static; margin: 18px 18px 0; }
  .ma-corps { padding: 26px 20px 20px; }
  .ma-objectifs { padding: 20px; }
  .ma-liste { grid-template-columns: 1fr; }
}


/* =============================================================
   18. LA COUVERTURE D'ACCUEIL — UNE SEULE, EN GRAND
   7 septembre 2026

   Direction : « la couverture doit être grande, comme ça, dans ce
   style ; pas deux l'une à côté de l'autre, une seule et belle,
   très grande. Rien ne doit l'encombrer visuellement — même le
   "Bonjour Achraf" passe SOUS la photo. »

   ⚠ CES RÈGLES REPRENNENT LA MAIN SUR master-v2.css.

   La feuille V12 fixe le hero en deux colonnes avec `!important`
   (`.hero-grid{grid-template-columns:…3.35fr…1fr!important}`).
   os25.css est chargée après elle : à spécificité et priorité
   égales, la dernière déclarée gagne. D'où les `!important` qui
   suivent — ils ne sont pas là par facilité, ils sont la seule
   façon de reprendre une déclaration déjà marquée.

   Le reste de la V12 est laissé intact : voile, cadran,
   vignettes, boutons. On ne change que la mise à l'échelle.
   ============================================================= */
.hero-grid.hero-solo {
  grid-template-columns: minmax(0, 1fr) !important;
  min-height: 0 !important;
}

/* La hauteur suit l'écran plutôt qu'un chiffre fixe : sur un
   portable la couverture reste lisible, sur un grand écran elle
   ne devient pas une bannière de 2 000 px. Le plancher (460 px)
   garantit que le titre, les badges et les deux boutons tiennent
   sans se serrer. */
.hero-solo .hero-scene {
  min-height: clamp(460px, 68vh, 780px) !important;
  border-radius: 24px !important;
}

/* Le titre redescend d'un cran. La consigne est « image très
   grande, écriture petite » : à 62 px sur toute la largeur, le
   nom du projet mangeait la photo au lieu de la légender. */
.hero-solo .scene-titre {
  font-size: clamp(34px, 3.2vw, 52px) !important;
  line-height: 1.02 !important;
}

/* Le texte se pose en bas à gauche, sur le tiers dense du voile,
   et s'arrête avant le cadran. */
.hero-solo .scene-corps {
  max-width: min(640px, 52%) !important;
  padding: 44px 48px 96px !important;
}

/* ⚠ LA COUVERTURE COMPOSÉE N'EST PLUS UN FANTÔME.

   `.scene-fond .affiche.affiche-generee` était à 50 % d'opacité,
   décidé quand la même image servait de vignette de 120 px et de
   fond de hero : à demi effacée, le sigle ne concurrençait plus
   le titre. Sur une couverture pleine largeur, le résultat est un
   rectangle presque vide — ce que la Direction a vu à l'écran.

   Le sigle a été rapetissé depuis (affiche.js : 46 px, en bas à
   gauche, à 13 % d'opacité) : le voile n'a plus besoin d'aide.
   On rend donc l'image, et on la traite comme une photo.

   ⚠ CE N'EST PAS UNE VRAIE PHOTO POUR AUTANT. Quand le dossier
   n'a pas de couverture, c'est une affiche composée qui s'affiche
   — pas une image trouvée ailleurs. Elle est simplement montrée
   pour ce qu'elle est, au lieu d'être à moitié effacée. */
.hero-solo .scene-fond .affiche.affiche-generee { opacity: 1; }
.hero-solo .scene-fond .affiche {
  filter: saturate(1.08) contrast(1.04) !important;
}

/* ⚠ LE VOILE COUVRAIT L'IMAGE, PAS SEULEMENT LE TEXTE.

   Le voile V12 est réglé pour un hero de 440 px de large utile :
   dense à gauche, il s'éclaircit à 76 % de la largeur. Sur une
   couverture pleine largeur, ces 76 % font près de 900 px — la
   quasi-totalité du cadre reste sous un noir à 78 %, et l'image
   ne se voit plus nulle part.

   Ici le voile suit le texte : il tient les 45 % de gauche, où le
   titre et les boutons se posent, puis s'efface. Le bas garde un
   fond léger pour les vignettes. Le contrat du 5 septembre disait
   déjà « l'image doit rester visible, gradient uniquement sur la
   zone du texte » — c'est cette phrase qu'on applique enfin à la
   bonne largeur. */
.hero-solo .scene-voile {
  background:
    linear-gradient(90deg,
      rgba(4,7,11,.94) 0%, rgba(4,7,11,.88) 24%,
      rgba(4,7,11,.52) 46%, rgba(4,7,11,.08) 72%, rgba(4,7,11,.20) 100%),
    linear-gradient(0deg, rgba(4,7,11,.76), transparent 42%) !important;
}

/* =============================================================
   LA SALUTATION SE POSE SUR LA PHOTO — 7 septembre 2026, le soir

   Direction : « Bonjour Achraf tji fou9 la photo […] tbadalha mn
   hna ou dirha f had l blassa l khawya. »

   ⚠ REMPLACE `.hero-solo + .command-head`, qui posait la
   salutation SOUS la couverture plus tôt dans la journée. Ce
   sélecteur n'a plus de cible : `.command-head` est maintenant
   DANS `.hero-coiffe`, plus après elle. Si vous le cherchez pour
   comprendre pourquoi il ne s'applique plus, c'est ici.

   Le coin haut-gauche est le seul des quatre que le hero laisse
   libre — le cadran tient le haut-droit, le corps du projet le
   bas-gauche, les vignettes le bas. La salutation s'y pose en
   absolu, calée sur le même bord gauche que le titre du projet
   (48 px), et s'arrête avant le cadran (200 px de garde).

   Elle est posée sur le tiers dense du voile (.94 → .88 sur les
   24 premiers pour cent) : le texte y tient sans ajouter de fond.
   Les ombres portées ci-dessous couvrent le cas d'une couverture
   claire, où le voile seul ne suffirait pas. */
.hero-grid.hero-coiffe { position: relative; }

.dashboard-home .hero-coiffe > .command-head {
  position: absolute;
  z-index: 4;
  top: 30px;
  left: 48px;
  right: 200px;
  margin: 0 !important;
  padding: 0 !important;
  min-height: 0 !important;
  grid-template-columns: auto auto auto auto !important;
  justify-content: start !important;
  align-items: center !important;
  gap: 16px !important;
  background: transparent;
  border: 0;
  box-shadow: none;
}

.hero-coiffe > .command-head .command-identity h1 {
  font-size: clamp(26px, 2.2vw, 36px) !important;
  text-shadow: 0 2px 24px rgba(4, 7, 11, .9), 0 1px 3px rgba(4, 7, 11, .8);
}
.hero-coiffe > .command-head .command-kicker,
.hero-coiffe > .command-head .command-identity p,
.hero-coiffe > .command-head .db-date {
  text-shadow: 0 1px 16px rgba(4, 7, 11, .95), 0 1px 2px rgba(4, 7, 11, .85);
}
.hero-coiffe > .command-head > .avatar {
  box-shadow: 0 0 0 1px rgba(242, 185, 64, .45), 0 10px 30px rgba(4, 7, 11, .7) !important;
}

/* ⚠ LE PLANCHER DE LA COUVERTURE MONTE AVEC LA SALUTATION.

   Le corps du projet est calé en bas (`align-self:end`) et grandit
   vers le HAUT : titre sur trois lignes, type, phrase, badges,
   deux boutons. À 500 px de plancher, son sur-titre « Projet
   prioritaire » venait mordre le « En direct depuis » de la
   salutation — mesuré à 12 px de chevauchement sur un écran de
   720 px de haut.

   ⚠ N'ESSAYEZ PAS DE RÉGLER CELA AVEC `padding-top` SUR LE CORPS :
   sur une boîte alignée en bas, augmenter le rembourrage haut
   pousse le haut de la boîte d'autant — le texte ne descend pas
   d'un pixel. Le seul levier est la hauteur de la scène.

   580 px de plancher laissent 67 px entre la salutation et le
   sur-titre : de la place pour un titre d'une ligne de plus. */
.hero-solo .hero-scene { min-height: clamp(580px, 74vh, 820px) !important; }

@media (max-width: 1100px) {
  .hero-solo .scene-corps { max-width: 100% !important; padding: 32px 24px 96px !important; }
  .dashboard-home .hero-coiffe > .command-head {
    top: 24px; left: 24px; right: 170px;
    grid-template-columns: auto auto auto !important;
    gap: 13px !important;
  }
}
@media (max-width: 760px) {
  .hero-solo .hero-scene { min-height: clamp(560px, 74vh, 680px) !important; }
  .hero-solo .scene-titre { font-size: 38px !important; }
  .dashboard-home .hero-coiffe > .command-head {
    top: 16px; left: 18px; right: 96px;
    grid-template-columns: auto minmax(0, 1fr) !important;
    gap: 11px !important;
  }
  .hero-coiffe > .command-head .command-identity h1 { font-size: 22px !important; }
  .hero-coiffe > .command-head > .avatar { width: 40px !important; height: 40px !important; }
}


/* =============================================================
   19. LA MATIÈRE — RELIEF, LUMIÈRE ET MOUVEMENT
   7 septembre 2026

   Direction : « ziiid Talaa3 lia l quality kaamla dial l'OS, ybaan
   high quality kter mn haka — les pop up, les animation, hadok
   les cercle kolhom ykono kidoro, les slides lfou9 kidozo, les
   boton kikhorjo, kolchi fih les effects. »

   ── CE QUE CETTE SECTION AJOUTE, ET CE QU'ELLE NE TOUCHE PAS

   Elle n'ajoute AUCUNE structure : pas un bloc, pas une colonne,
   pas un mot. Elle donne de la matière à ce qui existe déjà —
   comment une surface accroche la lumière, comment un bouton
   répond au doigt, comment une fenêtre arrive.

   ── LES TROIS RÈGLES QUI TIENNENT TOUT

   1. On n'anime que `transform`, `opacity` et `filter`. Ce sont
      les trois propriétés que le navigateur traite sur le
      compositeur, sans refaire la mise en page. Animer une
      hauteur ou une marge sur cinquante cartes fait tomber
      l'écran à quinze images par seconde ; animer une
      transformation n'en coûte aucune.

   2. Le relief se fait à l'ombre, pas au trait. Une bordure qui
      s'épaissit au survol déplace le contenu d'un pixel et fait
      sauter la ligne. Une ombre portée ne déplace rien.

   3. Rien ne bouge tout seul en permanence, sauf quatre objets :
      les anneaux, l'orbite des deux univers, les six points de la
      courbe, et la couverture. Un écran où douze choses respirent
      en même temps n'est pas vivant, il est nerveux. Tout le
      reste ne bouge qu'en réponse à un geste.

   ── ET LE MOUVEMENT RÉDUIT

   Tout ce qui suit s'éteint sous `prefers-reduced-motion` — voir
   la fin de la section. Ce n'est pas une politesse : pour
   certaines personnes une image qui dérive en continu donne la
   nausée. L'écran doit rester utilisable sans une seule
   animation, et il l'est.
   ============================================================= */

/* ── 19.1 Les courbes et les durées, nommées une fois.

   `--m-ressort` dépasse légèrement sa cible puis revient : c'est
   ce qui donne l'impression qu'un objet a une masse. On le
   réserve à ce qui apparaît. `--m-doux` ne dépasse pas : c'est
   pour ce qui suit le doigt, où un dépassement se lirait comme
   une imprécision. */
:root {
  --m-ressort: cubic-bezier(.22, 1, .36, 1);
  --m-doux:    cubic-bezier(.4, 0, .2, 1);
  --m-vif:     cubic-bezier(.16, 1, .3, 1);
  --m-court:   160ms;
  --m-moyen:   280ms;
  --m-long:    520ms;

  /* L'ombre en trois plans. Une ombre unique et large fait un
     halo gris ; trois ombres — contact, portée, ambiante —
     donnent une vraie hauteur. La dernière est teintée or : c'est
     la couleur de la marque qui éclaire la scène, pas un gris. */
  --o-pose:  0 1px 2px rgba(0,0,0,.5);
  --o-leve:  0 2px 4px rgba(0,0,0,.45), 0 12px 28px -12px rgba(0,0,0,.75),
             0 0 40px -22px rgba(242,185,64,.35);
  --o-haute: 0 4px 8px rgba(0,0,0,.45), 0 28px 60px -22px rgba(0,0,0,.85),
             0 0 70px -30px rgba(242,185,64,.45);
}

/* ── 19.2 LE GRAIN

   Un aplat numérique parfaitement lisse se lit comme du plastique.
   Quatre pour cent de bruit sur toute la page, et les grands fonds
   sombres prennent la texture d'une image argentique. C'est le
   détail qui fait le plus de différence pour le moins de travail.

   ⚠ `pointer-events: none` EST INDISPENSABLE : sans lui, ce voile
   plein écran intercepterait tous les clics de l'application. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* =============================================================
   19.3 LES BOUTONS QUI SORTENT DE L'ÉCRAN

   Trois états, et chacun dit quelque chose :

     au repos  — posé, une ombre de contact ;
     au survol — soulevé de 2 px, l'ombre s'ouvre, un reflet
                 traverse la surface de gauche à droite ;
     au clic   — enfoncé sous sa position de repos, l'ombre se
                 referme. C'est ce dernier état qu'on oublie
                 toujours, et c'est lui qui donne la sensation
                 d'avoir appuyé sur quelque chose de réel.

   ⚠ LE REFLET EST UN PSEUDO-ÉLÉMENT, PAS UN DÉGRADÉ DE FOND.
   Beaucoup de boutons de l'OS portent déjà un fond — plein, en
   verre, en dégradé. Le remplacer au survol les ferait tous
   changer de couleur. Le reflet passe par-dessus et n'efface
   rien.
   ============================================================= */
.btn,
.icon-btn,
.universe-link,
.scene-fleche,
.chip {
  position: relative;
  transition: transform var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux),
              filter var(--m-court) var(--m-doux);
}
.btn { box-shadow: var(--o-pose); }

.btn:hover:not(:disabled),
.universe-link:hover,
.chip:hover {
  transform: translateY(-2px);
  box-shadow: var(--o-leve);
  filter: brightness(1.06);
}
.btn:active:not(:disabled) {
  transform: translateY(1px) scale(.985);
  box-shadow: var(--o-pose);
  filter: brightness(.96);
  transition-duration: 60ms;
}
.btn:disabled { box-shadow: none; }

/* Le reflet. Une bande claire, inclinée, qui traverse en 620 ms.
   Elle est hors cadre au repos et n'existe donc pas tant que
   personne ne survole.

   ⚠ TROIS BOUTONS SONT EXCLUS, ET C'EST VOLONTAIRE.

   btn-primary, btn-hero et btn-gate ont DÉJÀ leur reflet, écrit
   dans neon.css puis repris dans neon-systeme.css. Le leur est
   fait d'une translation ; le nôtre, d'un fond qui défile. Comme
   os25.css est chargée en dernier, la nôtre gagnerait sur le
   fond — mais pas sur la translation, qui resterait et pousserait
   notre bande hors du cadre. Deux reflets qui se marchent dessus
   ne font pas un reflet plus brillant : ils n'en font aucun.

   On laisse donc le leur en place et on n'éclaire que les boutons
   qui n'avaient rien. */
.btn:not(.btn-primary):not(.btn-hero):not(.btn-gate)::after,
.universe-link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 38%, rgba(255,255,255,.20) 50%, transparent 62%);
  background-size: 280% 100%;
  background-position: 180% 0;
  opacity: 0;
}
.btn:not(.btn-primary):not(.btn-hero):not(.btn-gate):hover:not(:disabled)::after,
.universe-link:hover::after {
  opacity: 1;
  animation: os25-reflet 620ms var(--m-doux) 1;
}
@keyframes os25-reflet {
  from { background-position: 180% 0; }
  to   { background-position: -80% 0; }
}

/* Le bouton principal du hero mérite plus : il est le seul geste
   attendu sur l'écran d'accueil. Au survol, sa lueur or s'ouvre. */
.btn-hero:hover,
.scene-actions .btn-hero:hover {
  box-shadow: 0 4px 10px rgba(0,0,0,.4),
              0 18px 44px -14px rgba(242,185,64,.55),
              0 0 0 1px rgba(242,185,64,.35) !important;
}

/* Les boutons ronds d'icône tournent d'un rien : un mouvement
   minuscule, mais c'est celui qui fait qu'une croix de fermeture
   a l'air cliquable. */
.icon-btn:hover { transform: translateY(-1px) rotate(6deg); box-shadow: var(--o-leve); }
.icon-btn:active { transform: scale(.9); }

/* Les flèches du carrousel glissent dans leur sens. */
.scene-fleche:hover { transform: translateX(-3px) scale(1.12); }
.scene-fleche.retourne:hover { transform: translateX(3px) scale(1.12); }

/* =============================================================
   19.4 LES CARTES QUI SE SOULÈVENT

   Même grammaire que les boutons, à une échelle plus lente : une
   carte est plus lourde qu'un bouton, elle met plus de temps à
   monter. 280 ms au lieu de 160.

   ⚠ LE LISERÉ LUMINEUX EST UNE OMBRE INTÉRIEURE, PAS UNE BORDURE.
   `border` change la taille de la boîte ; `inset` ne déplace rien.
   ============================================================= */
.universe-card,
.projet-carte,
.kpi,
.voie-carte,
.gal-carte,
.eq-carte,
.ll-carte,
.filmo-carte {
  transition: transform var(--m-moyen) var(--m-ressort),
              box-shadow var(--m-moyen) var(--m-doux);
}
.universe-card:hover,
.voie-carte:hover,
.gal-carte:hover,
.eq-carte:hover,
.ll-carte:hover,
.filmo-carte:hover,
.kpi:hover {
  transform: translateY(-6px);
  box-shadow: var(--o-haute), inset 0 0 0 1px rgba(255,255,255,.09);
}

/* Les deux univers portent leur couleur : SPIDER en violet,
   CERCLE en cyan. Au survol, c'est cette couleur qui s'allume —
   pas un blanc générique. */
.universe-card.universe-spider:hover {
  box-shadow: 0 28px 60px -22px rgba(0,0,0,.85),
              0 0 70px -26px rgba(139,92,246,.55),
              inset 0 0 0 1px rgba(139,92,246,.35);
}
.universe-card.universe-cercle:hover {
  box-shadow: 0 28px 60px -22px rgba(0,0,0,.85),
              0 0 70px -26px rgba(18,217,255,.5),
              inset 0 0 0 1px rgba(18,217,255,.32);
}
.universe-card.universe-trame:hover {
  box-shadow: 0 28px 60px -22px rgba(0,0,0,.85),
              0 0 70px -26px rgba(242,185,64,.5),
              inset 0 0 0 1px rgba(242,185,64,.32);
}

/* Le lien d'une carte avance quand on survole la carte entière :
   la flèche part avant que la souris ne l'atteigne, et on
   comprend où cliquer. */
.universe-link .ico { transition: transform var(--m-court) var(--m-doux); }
.universe-card:hover .universe-link .ico { transform: translateX(4px); }

/* =============================================================
   19.5 LES CERCLES QUI TOURNENT

   Quatre couronnes tournent en continu, et pas au même rythme —
   des vitesses différentes évitent l'effet d'horloge où tout se
   synchronise et devient mécanique.

   ⚠ AUCUN DE CES MOUVEMENTS NE PORTE D'INFORMATION. L'arc de
   progression, lui, ne tourne pas : il se remplit une fois, à la
   valeur réelle, et s'arrête. Ce qui tourne est le décor autour.
   Un chiffre qui tourne serait un chiffre qu'on ne peut pas lire.
   ============================================================= */
@keyframes os25-orbite { to { transform: rotate(360deg); } }

/* L'anneau d'avancement : une couronne pointillée derrière lui,
   qui fait un tour en 22 secondes. */
.anneau-boite { position: relative; }
.anneau-boite::before {
  content: "";
  position: absolute;
  inset: -7px;
  border-radius: 50%;
  border: 1px dashed rgba(242,185,64,.28);
  animation: os25-orbite 22s linear infinite;
  pointer-events: none;
}
/* Le cadran du hero : sa monture tourne, lentement — et lui seul
   reçoit le halo coloré qui tourne à l'envers. C'est le
   croisement des deux sens qui donne la profondeur.

   ⚠ POURQUOI PAS SUR TOUS LES ANNEAUX. L'accueil en porte dix. Un
   dégradé conique flouté à 10 px et mis en rotation, multiplié
   par dix, oblige la carte graphique à refaire dix flous à chaque
   image : c'est le genre de détail qui fait passer un écran de 60
   à 25 images par seconde sur un portable. La couronne
   pointillée, qui ne coûte qu'une rotation de trait, reste sur
   tous les anneaux. */
.scene-cadran { position: relative; }
.scene-cadran::after {
  content: "";
  position: absolute;
  inset: -18px;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    transparent 0deg, rgba(18,217,255,.22) 40deg, transparent 120deg,
    transparent 240deg, rgba(242,185,64,.18) 290deg, transparent 340deg);
  filter: blur(10px);
  animation: os25-orbite 44s linear infinite reverse;
  pointer-events: none;
}
.scene-cadran::before {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  border: 1px solid rgba(18,217,255,.18);
  border-top-color: rgba(18,217,255,.55);
  border-right-color: rgba(242,185,64,.4);
  animation: os25-orbite 14s linear infinite;
  pointer-events: none;
}

/* L'étape en cours du CERCLE 25 : elle seule reçoit une couronne.
   Les étapes franchies et celles à venir restent immobiles — la
   rotation dit « c'est ici que ça se passe maintenant ». */
.c25-jalon.ici .c25-rond { position: relative; }
.c25-jalon.ici .c25-rond::after {
  content: "";
  position: absolute;
  inset: -8px;
  border-radius: 50%;
  border: 1.5px dashed currentColor;
  opacity: .5;
  animation: os25-orbite 9s linear infinite;
  pointer-events: none;
}

/* L'orbite des deux univers : elle existait déjà comme élément
   vide, sans mouvement. On la fait tourner, et on l'accélère
   quand la carte est survolée. */
.universe-orbit {
  transform-origin: center;
  animation: os25-orbite 30s linear infinite;
}
.universe-card:hover .universe-orbit { animation-duration: 9s; }

/* =============================================================
   19.6 LES SLIDES QUI PASSENT

   La couverture change toutes les huit secondes. Jusqu'ici
   l'ancienne s'effaçait et la nouvelle apparaissait — un fondu,
   correct mais plat.

   Maintenant : l'image entre en glissant depuis la droite et en
   se refermant (une caméra qui finit son travelling), pendant
   qu'une lame de lumière traverse le cadre une fois. Le texte,
   lui, monte depuis la gauche — il n'accompagne pas l'image, il
   arrive par un autre bord, et c'est ce décalage qui se lit comme
   un montage plutôt qu'un fondu.
   ============================================================= */
.hero-scene .scene-fond .affiche {
  animation: os25-entree-fond 900ms var(--m-vif) 1,
             pano 40s ease-in-out infinite !important;
}
@keyframes os25-entree-fond {
  from { opacity: 0; transform: translateX(26px) scale(1.07); }
  to   { opacity: 1; transform: none; }
}

/* La lame de lumière. Elle ne passe qu'une fois par changement,
   parce que l'élément est recréé à chaque rendu de la scène. */
.hero-scene .scene-voile::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg,
    transparent 40%, rgba(255,255,255,.09) 50%, transparent 60%);
  background-size: 300% 100%;
  animation: os25-lame 1400ms var(--m-doux) 1;
}
@keyframes os25-lame {
  from { background-position: 200% 0; }
  to   { background-position: -100% 0; }
}

/* Les vignettes : celle qui est active se soulève déjà. Les
   autres répondent au survol, et l'image dedans avance. */
.scene-vignette {
  transition: transform var(--m-court) var(--m-ressort),
              box-shadow var(--m-court) var(--m-doux);
}
.scene-vignette:hover { transform: translateY(-5px) scale(1.06); box-shadow: var(--o-leve); }
.scene-vignette .affiche { transition: transform var(--m-moyen) var(--m-doux); }
.scene-vignette:hover .affiche { transform: scale(1.12); }

/* La couverture elle-même : sa lueur s'ouvre au survol. Assez
   pour qu'on sente qu'elle est vivante, trop peu pour distraire. */
.hero-solo .hero-scene { transition: box-shadow var(--m-long) var(--m-doux); }
.hero-solo .hero-scene:hover {
  box-shadow: 0 40px 100px -34px #000,
              0 0 90px -40px rgba(18,217,255,.7) !important;
}

/* =============================================================
   19.7 LES FENÊTRES QUI S'OUVRENT

   Une fenêtre qui apparaît d'un coup ne dit pas d'où elle vient.
   Celle-ci monte de 18 px en se dépliant, pendant que le fond
   derrière se floute et s'assombrit. Les deux mouvements sont
   décalés de 60 ms : le fond part en premier, la fenêtre le suit.
   C'est l'ordre naturel — on éteint la salle avant que l'écran
   s'allume.

   ⚠ `backdrop-filter` EST RÉSERVÉ À CE VOILE. C'est un effet
   coûteux : le navigateur doit relire le rendu sous l'élément à
   chaque image. Sur un voile plein écran qui ne bouge pas, il est
   composité une fois. Sur trente cartes qui défilent, il ferait
   ramer l'écran.
   ============================================================= */
.modal-scrim {
  animation: os25-voile 260ms var(--m-doux) both;
  backdrop-filter: blur(10px) saturate(.85);
}
@keyframes os25-voile {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.modal {
  animation: os25-fenetre 420ms var(--m-ressort) 60ms both;
  box-shadow: 0 40px 110px -30px #000,
              0 0 0 1px rgba(255,255,255,.07),
              0 0 120px -50px rgba(242,185,64,.4);
}
@keyframes os25-fenetre {
  from { opacity: 0; transform: translateY(18px) scale(.965); }
  to   { opacity: 1; transform: none; }
}

/* L'en-tête de la fenêtre porte un filet de lumière : c'est ce
   qui sépare le titre du contenu sans tracer une ligne grise. */
.modal-head {
  position: relative;
  background: linear-gradient(180deg, rgba(255,255,255,.045), transparent);
}
.modal-head::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent,
    rgba(242,185,64,.5) 22%, rgba(18,217,255,.45) 62%, transparent);
}

/* Le pied : ses boutons entrent l'un après l'autre. */
@keyframes os25-monte {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.modal-foot .btn { opacity: 1; transform: none; animation: os25-monte 320ms var(--m-ressort); }
.modal-foot .btn:nth-child(1) { animation-delay: 180ms; }
.modal-foot .btn:nth-child(2) { animation-delay: 240ms; }
.modal-foot .btn:nth-child(3) { animation-delay: 300ms; }

/* =============================================================
   19.8 LES MESSAGES

   Un message arrive par la droite en dépassant sa place de 6 px,
   puis se pose. Un liseré coloré à gauche dit lequel des quatre
   états on lit, avant même de lire.
   ============================================================= */
@keyframes os25-toast {
  from { opacity: 0; transform: translateX(38px) scale(.96); }
  60%  { transform: translateX(-6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes os25-toast-sort {
  to { opacity: 0; transform: translateX(38px) scale(.96); }
}
.toast {
  animation: os25-toast 380ms var(--m-ressort) both;
  box-shadow: var(--o-haute);
  border-left: 3px solid rgba(255,255,255,.25);
}
.toast.ok   { border-left-color: #34D399; }
.toast.warn { border-left-color: #F2B940; }
.toast.err  { border-left-color: #F87171; }
.toast.out  { animation: os25-toast-sort 200ms var(--m-doux) both; }

/* =============================================================
   19.9 LE MENU

   Sept blocs, sept couleurs. Au survol, la pastille grossit et sa
   couleur déborde en lueur ; la ligne glisse de 3 px vers la
   droite.
   ============================================================= */
.nav-cat-btn,
.nav-lien {
  transition: transform var(--m-court) var(--m-doux),
              background-color var(--m-court) var(--m-doux);
}
.nav-cat-btn:hover,
.nav-lien:hover { transform: translateX(3px); }
.nav-cat-btn::before {
  transition: transform var(--m-moyen) var(--m-ressort),
              box-shadow var(--m-moyen) var(--m-doux);
}
.nav-cat-btn:hover::before {
  transform: scale(1.45);
  box-shadow: 0 0 14px currentColor;
}

/* Le sigle du studio répond au survol, et lui seul : c'est la
   marque, elle a le droit d'être la seule chose qui bouge dans
   une colonne par ailleurs immobile. */
.brand-marque { transition: transform var(--m-long) var(--m-ressort); }
.brand:hover .brand-marque { transform: scale(1.06) rotate(-2deg); }

/* =============================================================
   19.10 L'ENTRÉE D'ÉCRAN

   ⚠ LA CASCADE EXISTE DÉJÀ dans neon.css. On ne la redéclare pas —
   on lui donne seulement la courbe à ressort, pour que les blocs
   ne fassent pas que monter mais s'ouvrent aussi.
   ============================================================= */
.db-cascade > * { animation-timing-function: var(--m-ressort) !important; }

/* Les compteurs des univers : ils entrent en se dépliant. */
@keyframes os25-kpi {
  from { opacity: 0; transform: translateY(12px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
.universe-kpi { opacity: 1; transform: none; animation: os25-kpi 420ms var(--m-ressort); }
.universe-kpi:nth-child(1) { animation-delay: 120ms; }
.universe-kpi:nth-child(2) { animation-delay: 180ms; }
.universe-kpi:nth-child(3) { animation-delay: 240ms; }
.universe-kpi:nth-child(4) { animation-delay: 300ms; }

/* La courbe IDEA vers IMPACT : ses six points pulsent, chacun à
   son propre rythme, pour que la ligne ait l'air de circuler. */
@keyframes os25-point {
  0%, 100% { opacity: .45; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.35); }
}
.c25-wave i { animation: os25-point 2600ms var(--m-doux) infinite; }
.c25-wave i:nth-child(1) { animation-delay: 0ms; }
.c25-wave i:nth-child(2) { animation-delay: 220ms; }
.c25-wave i:nth-child(3) { animation-delay: 440ms; }
.c25-wave i:nth-child(4) { animation-delay: 660ms; }
.c25-wave i:nth-child(5) { animation-delay: 880ms; }
.c25-wave i:nth-child(6) { animation-delay: 1100ms; }

/* Les lignes de tableau : un survol qui se voit sans repeindre. */
tbody tr {
  transition: background-color var(--m-court) var(--m-doux),
              transform var(--m-court) var(--m-doux);
}
tbody tr:hover { transform: translateX(2px); }

/* =============================================================
   19.10 bis  L'ORBE 25 AI — 7 septembre 2026, le soir

   Direction : « l'icône AI t7al chat l studio wla t7al question l
   AI ; dirha bleu avec bleu canard, fiha dou, tji futuriste kter,
   circulaire futuriste. »

   ⚠ REPREND `.assistant-bulle` DE components.css, QUI EST DORÉE.
   La pastille or se confondait avec le bouton primaire du hero
   (`.btn-hero`, #f2b940) : deux ronds dorés à l'écran, un seul
   ouvre l'assistant. Le froid la distingue d'un geste.

   Les trois bleus sortent de la palette déjà en place — le cyan
   est celui de CERCLE (#12d9ff), le bleu celui du liseré du hero
   (#258bff) ; seul le canard (#0e7c86) est nouveau, et c'est lui
   qui porte le halo. On n'invente pas une quatrième couleur.

   Deux mouvements permanents, pas trois : la couronne qui tourne
   (elle dit « ça écoute ») et le halo qui s'ouvre (il dit « c'est
   là »). Le noyau ne pulse pas en plus — ce serait le nerveux
   dont parle la règle 3 de la section 19.

   ⚠ LES DEUX PSEUDO-ÉLÉMENTS SONT EN ABSOLU. `.assistant-bulle`
   est `display:grid` : posés en flux, la couronne et le halo
   deviendraient des cases de la grille et pousseraient l'icône
   hors du rond. */
.assistant-bulle {
  width: 58px !important;
  height: 58px !important;
  border: 0 !important;
  color: #9FEAF4 !important;
  background: radial-gradient(circle at 34% 28%, #0E3E4E 0%, #061620 74%) !important;
  box-shadow:
    0 0 0 1px rgba(127, 227, 238, .32),
    0 0 30px rgba(14, 124, 134, .55),
    0 12px 30px -12px rgba(0, 0, 0, .9) !important;
  isolation: isolate;
}

/* La couronne. Un dégradé conique masqué en anneau : un seul
   élément, aucune image, et la rotation ne coûte qu'un
   compositeur. */
.assistant-bulle::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  z-index: -1;
  background: conic-gradient(from 0deg,
    transparent 0deg, #0e7c86 70deg, #258bff 150deg,
    #12d9ff 205deg, transparent 262deg, transparent 360deg);
  -webkit-mask: radial-gradient(circle, transparent 0 64%, #000 65%);
          mask: radial-gradient(circle, transparent 0 64%, #000 65%);
  animation: orbe-couronne 4.5s linear infinite;
}
@keyframes orbe-couronne { to { transform: rotate(360deg); } }

/* Le halo. Il part du bord et s'efface : c'est un signal de
   présence, pas un clignotant. */
.assistant-bulle::after {
  content: "";
  position: absolute;
  inset: -12px;
  border-radius: 50%;
  z-index: -1;
  border: 1px solid rgba(18, 217, 255, .38);
  animation: orbe-halo 2.9s ease-out infinite;
  pointer-events: none;
}
@keyframes orbe-halo {
  0%   { transform: scale(.86); opacity: .85; }
  100% { transform: scale(1.24); opacity: 0; }
}

.assistant-bulle:hover {
  transform: translateY(-2px) scale(1.05) !important;
  box-shadow:
    0 0 0 1px rgba(127, 227, 238, .5),
    0 0 44px rgba(37, 139, 255, .6),
    0 14px 34px -12px rgba(0, 0, 0, .9) !important;
}

/* Ouvert, la couronne s'arrête : le panneau est la réponse, le
   bouton n'a plus rien à signaler. */
.assistant-bulle.est-ouvert { transform: scale(.92) !important; opacity: 1 !important; }
.assistant-bulle.est-ouvert::before { animation-play-state: paused; }
.assistant-bulle.est-ouvert::after { display: none; }

/* Le panneau prend le même froid, sinon le bouton bleu ouvre une
   fenêtre grise et le lien entre les deux se perd. */
.assistant-panneau {
  border-color: rgba(127, 227, 238, .22) !important;
  background: linear-gradient(180deg, #0B1B25 0%, #071119 100%) !important;
  box-shadow: 0 0 44px rgba(14, 124, 134, .26), 0 24px 60px -24px rgba(0, 0, 0, .9) !important;
}
.assistant-tete { border-bottom-color: rgba(127, 227, 238, .16) !important; }
.assistant-titre { color: #9FEAF4; }

/* =============================================================
   19.11 MOUVEMENT RÉDUIT

   ⚠ TOUT CE QUI PRÉCÈDE S'ÉTEINT ICI, Y COMPRIS LES ROTATIONS
   PERMANENTES. Une couronne qui tourne sans fin est exactement ce
   que ce réglage existe pour supprimer. Les états au survol
   restent — ils répondent à un geste, ils ne surprennent
   personne — mais sans transition.
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  .anneau-boite::before,
  .scene-cadran::before,
  .scene-cadran::after,
  .c25-jalon.ici .c25-rond::after,
  .universe-orbit,
  .assistant-bulle::before,
  .assistant-bulle::after,
  .c25-wave i,
  .hero-scene .scene-voile::after,
  .hero-scene .scene-fond .affiche,
  .universe-kpi,
  .modal,
  .modal-scrim,
  .toast,
  .modal-foot .btn {
    animation: none !important;
  }
  .btn::after,
  .universe-link::after { display: none; }
  .btn-primary::after, .btn-hero::after, .btn-gate::after { transition: none !important; }
  .btn, .icon-btn, .universe-card, .projet-carte, .kpi, .voie-carte,
  .gal-carte, .eq-carte, .ll-carte, .filmo-carte, .scene-vignette,
  .nav-cat-btn, .nav-lien, tbody tr {
    transition: none !important;
  }
  .btn:hover, .icon-btn:hover, .universe-card:hover, .scene-vignette:hover,
  .nav-cat-btn:hover, .nav-lien:hover, tbody tr:hover { transform: none !important; }
  body::after { display: none; }
}


/* =============================================================
   20. LA CONSOLE DU STUDIO — LE PIED DU MENU
   7 septembre 2026

   Direction : « dik le studio / fermer l'OS / accès et horaires
   mam9adach mzian, dir liha bouton temma bleu futuriste. »

   ── CE QUI N'ALLAIT PAS

   Les deux commandes portaient la classe des liens de menu. Elles
   ressemblaient donc à deux entrées de navigation de plus, collées
   sous les sept blocs — alors que l'une d'elles FERME L'OS POUR
   TOUTE L'ÉQUIPE. Le geste le plus lourd de l'application avait
   l'apparence d'un lien vers une page.

   ── CE QUE FAIT CE BLOC

   Il se détache du menu : un panneau de verre sombre, un liseré
   cyan, et un interrupteur qui a la forme de ce qu'il fait — une
   piste, une pastille qui glisse, une lueur qui s'allume quand le
   studio est ouvert et s'éteint en rouge quand il est fermé.

   ⚠ DEUX LIGNES DE TEXTE, ET ELLES NE DISENT PAS LA MÊME CHOSE.
   La première dit L'ÉTAT (« Studio ouvert »), la seconde
   L'ACTION (« Fermer l'accès »). C'est le piège classique des
   interrupteurs : un bouton marqué « Fermer l'OS » ne dit pas si
   l'OS est ouvert. Ici les deux sont écrits, l'un sous l'autre.
   ============================================================= */
.studio-console {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 14px 12px 10px;
  padding: 13px 13px 11px;
  border-radius: 15px;
  background:
    linear-gradient(160deg, rgba(18,217,255,.07), rgba(5,8,13,.5) 55%),
    rgba(8,13,21,.72);
  border: 1px solid rgba(18,217,255,.20);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05),
              0 14px 34px -22px #000;
}

/* Le liseré du haut : la seule ligne de couleur pleine du menu.
   Elle sépare la console des sept blocs sans tracer un trait
   gris de plus. */
.studio-console {
  position: relative;
  overflow: hidden;
}
.studio-console::before {
  content: "";
  position: absolute;
  top: 0;
  left: 12px;
  right: 12px;
  height: 1px;
  background: linear-gradient(90deg, transparent,
    rgba(18,217,255,.75) 30%, rgba(242,185,64,.45) 75%, transparent);
}

.sc-titre {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(148,180,214,.72);
}

/* ── L'INTERRUPTEUR */
.sc-bascule {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 9px 10px;
  border-radius: 11px;
  border: 1px solid rgba(18,217,255,.22);
  background: rgba(5,8,13,.55);
  color: #E8F1FA;
  text-align: left;
  cursor: pointer;
  transition: transform var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux),
              border-color var(--m-court) var(--m-doux);
}
.sc-bascule:hover {
  transform: translateY(-2px);
  border-color: rgba(18,217,255,.5);
  box-shadow: 0 10px 26px -14px #000, 0 0 26px -14px rgba(18,217,255,.8);
}
.sc-bascule:active { transform: translateY(1px) scale(.99); }

/* La piste et la pastille. La pastille glisse de gauche à droite
   selon l'état — c'est le seul endroit de l'OS où une position
   dans l'espace porte une information. */
.sc-piste {
  position: relative;
  display: block;
  height: 21px;
  border-radius: 999px;
  background: rgba(255,255,255,.09);
  box-shadow: inset 0 1px 3px rgba(0,0,0,.6);
  transition: background-color var(--m-moyen) var(--m-doux);
}
.sc-pastille {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #7C8DA3;
  transition: transform var(--m-moyen) var(--m-ressort),
              background-color var(--m-moyen) var(--m-doux),
              box-shadow var(--m-moyen) var(--m-doux);
}

/* Ouvert : la piste s'allume en cyan, la pastille passe à droite
   et respire. Fermé : elle revient à gauche, en rouge, immobile —
   un studio fermé ne doit pas avoir l'air vivant. */
.studio-console.on .sc-piste { background: rgba(18,217,255,.30); }
.studio-console.on .sc-pastille {
  transform: translateX(19px);
  background: #12D9FF;
  box-shadow: 0 0 12px rgba(18,217,255,.9), 0 0 22px rgba(18,217,255,.4);
}
.studio-console.off .sc-piste { background: rgba(248,113,113,.22); }
.studio-console.off .sc-pastille {
  background: #F87171;
  box-shadow: 0 0 10px rgba(248,113,113,.75);
}

.sc-texte { display: block; min-width: 0; }
.sc-texte b {
  display: block;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.2;
}
.studio-console.off .sc-texte b { color: #FCA5A5; }
.sc-action {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  color: rgba(148,180,214,.78);
}

/* ── LE LIEN SECONDAIRE

   Il reste un lien, et il doit le rester : ouvrir un écran de
   réglages n'a rien de commun avec fermer le studio. Il est donc
   plus petit, sans fond, et ne se soulève pas — il glisse. */
.sc-lien {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 4px 2px;
  font-size: 12px;
  color: rgba(148,180,214,.8);
  text-decoration: none;
  transition: color var(--m-court) var(--m-doux),
              transform var(--m-court) var(--m-doux);
}
.sc-lien .ico { display: inline-flex; color: rgba(18,217,255,.75); }
.sc-lien:hover { color: #E8F1FA; transform: translateX(3px); }

/* Menu réduit : la console se réduit à son interrupteur. Le
   titre et le lien disparaissent — dans une colonne de 68 px,
   « Accès et horaires » ne tiendrait pas, et le tronquer en
   « Accè… » ne rend service à personne. */
.app[data-nav="reduit"] .studio-console { margin-inline: 8px; padding: 10px 8px; }
.app[data-nav="reduit"] .sc-titre,
.app[data-nav="reduit"] .sc-texte,
.app[data-nav="reduit"] .sc-lien span:not(.ico) { display: none; }
.app[data-nav="reduit"] .sc-bascule { grid-template-columns: 1fr; gap: 0; padding: 8px; }
.app[data-nav="reduit"] .sc-lien { justify-content: center; padding: 6px 0 2px; }

@media (prefers-reduced-motion: reduce) {
  .sc-bascule, .sc-piste, .sc-pastille, .sc-lien { transition: none !important; }
  .sc-bascule:hover, .sc-lien:hover { transform: none !important; }
}


/* =============================================================
   21. LA DENSITÉ ET LA LUMIÈRE
   7 septembre 2026, tard

   Direction : « dartiha kbira bzffff, machi ghir hia, ch7al mn
   haja. 7awl tsaghar chwiya lktaba f system ou les elements. Ou
   zidni plus de light et plus de pop up ou plus d'energie
   positive f OS. »

   ── CE QUI ÉTAIT TROP GRAND, MESURÉ AVANT DE TOUCHER

       couverture      703 px de haut
       titre du projet  48 px
       salutation       33 px
       titre de page    33 px
       titre d'univers  29 px
       compteurs        21 px
       cartes           26 / 28 px de rembourrage
       texte courant    14 px

   Ce n'est pas une impression : sur un écran de 950 px de haut,
   la couverture seule en mangeait les trois quarts. Il fallait
   défiler pour voir le premier projet.

   ── LE PRINCIPE DU RÉGLAGE

   On ne rapetisse pas tout du même pourcentage. Plus un élément
   est gros, plus il descend :

       −21 %  la couverture   703 → 555
       −27 %  le titre projet  48 → 35
       −21 %  le titre de page 33 → 26
       −24 %  le titre univers 29 → 22
       −19 %  les compteurs    21 → 17
       −30 %  le rembourrage   26 → 18
        −7 %  le texte courant 14 → 13

   Le texte courant bouge le moins, et c'est volontaire : c'est
   lui qu'on lit vraiment. Ce qui prenait de la place sans rien
   dire — les grands titres, les marges — cède la sienne.

   ⚠ CE N'EST PAS UNE RÈGLE DE GOÛT, C'EST UNE RÈGLE DE TRAVAIL.
   Un outil qu'on ouvre trente fois par jour n'est pas une page
   d'accueil de site : chaque pixel donné à un titre est un pixel
   pris à une information. La grandeur, on la garde pour la
   couverture — c'est la seule image de l'écran.
   ============================================================= */

/* ── 21.1 LA COUVERTURE REDESCEND

   Elle reste la plus grande chose de l'écran, mais elle laisse
   voir ce qui vient après. 56 % de la hauteur au lieu de 74 %,
   et le premier projet apparaît sans défiler. */
.hero-solo .hero-scene { min-height: clamp(440px, 56vh, 620px) !important; }
.hero-solo .scene-titre { font-size: clamp(26px, 2.4vw, 35px) !important; }
.hero-solo .scene-corps { padding: 34px 38px 82px !important; }
.hero-coiffe > .command-head .command-identity h1 {
  font-size: clamp(19px, 1.5vw, 25px) !important;
}
.hero-coiffe > .command-head { top: 22px; left: 38px; }
.hero-coiffe > .command-head > .avatar { width: 40px !important; height: 40px !important; }

/* ── 21.2 LES TITRES DE PAGE

   33 px pour « Clients » sur un écran de tableau, c'est une
   affiche. 26 px reste un titre. */
.page h1,
.page-head h1,
.page-title { font-size: clamp(21px, 1.7vw, 26px) !important; letter-spacing: -.02em; }
.page-head p,
.page-head .muted { font-size: 12.5px; }

/* ── 21.3 LES DEUX UNIVERS */
.universe-card { padding: 18px 20px 16px !important; }
.universe-card h2 { font-size: clamp(18px, 1.5vw, 22px) !important; }
.universe-copy { font-size: 12.5px !important; }
.universe-kpi b { font-size: 17px !important; }
.universe-kpi span { font-size: 10.5px; }
.universe-link { font-size: 12px; }

/* ── 21.4 LE TEXTE COURANT ET LES ESPACES

   Un point de moins sur le corps, et l'écran gagne une ligne par
   panneau sans que rien devienne illisible. Les écarts entre
   blocs se resserrent d'un tiers. */
body { font-size: 13px; }
.dashboard-home { gap: 13px !important; }
.dashboard-home .panel-head { padding: 10px 14px 6px !important; }
.dashboard-home .panel-body { padding: 6px 14px 12px !important; }
.panel-head h3 { font-size: 12px !important; }
.eyebrow { font-size: 10px !important; }

/* Les tableaux respirent moins, et c'est ce qu'on leur demande :
   voir dix lignes d'un coup plutôt que six. */
tbody td, thead th { padding-block: 8px !important; }

/* ── 21.5 LES ANNEAUX ET LES JALONS

   Le cadran de la couverture est dessiné à 118 px par le code
   (anneau.js). On ne touche pas au code pour une question de
   taille : la mise à l'échelle est l'affaire de la feuille. */
.scene-cadran .anneau-boite { transform: scale(.82); transform-origin: top right; }
.c25-jalon .c25-rond { width: 32px !important; height: 32px !important; }
.c25-titre { font-size: 11.5px !important; }
.c25-compte { font-size: 10.5px !important; }

/* =============================================================
   21.6 LA LUMIÈRE

   Direction : « plus de light ».

   Un OS de production tourne dans une pièce sombre, sur des
   fonds à #05080D. Sans source, tout est plat : les panneaux se
   confondent avec le fond, et l'œil ne sait pas où regarder.

   On pose donc trois lumières, comme sur un plateau :

     1. une lueur d'ambiance, très large, en haut de l'écran ;
     2. un filet clair sur l'arête haute de chaque panneau —
        c'est ce qui donne l'impression que la surface est
        éclairée par le dessus ;
     3. une lueur qui suit l'élément actif du menu.

   ⚠ AUCUNE N'EST ANIMÉE. Trois sources fixes donnent du relief ;
   trois sources qui respirent donnent le mal de mer.
   ============================================================= */

/* 1. L'ambiance. Elle ne teinte rien, elle éclaire.

   ⚠ ELLE EST POSÉE SUR `body`, PAS SUR `.app`, ET EN z-index
      NÉGATIF.

      La première version la posait sur `.app::before` en
      `z-index: 0`, ce qui obligeait à écrire
      `.app > * { z-index: 1 }` pour repasser le contenu devant.
      Cette ligne aurait écrasé le z-index du voile du menu
      mobile — même spécificité, feuille chargée plus tard — et
      le menu serait passé DERRIÈRE son propre voile.

      Sur `body::before` en `z-index: -1`, la lueur se glisse
      entre le fond de la page et son contenu. Rien d'autre à
      déclarer, et aucun empilement existant n'est touché. */
body::before {
  content: "";
  position: fixed;
  top: -20vh;
  left: 18%;
  right: 0;
  height: 72vh;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60% 55% at 30% 0%, rgba(18,217,255,.11), transparent 70%),
    radial-gradient(45% 50% at 78% 8%, rgba(242,185,64,.08), transparent 72%),
    radial-gradient(38% 44% at 55% 4%, rgba(139,92,246,.065), transparent 70%);
}

/* 2. L'arête haute. Un pixel de blanc à 7 % sur le bord
      supérieur : c'est le geste le moins cher et le plus
      efficace de toute cette feuille. */
  ⚠ `box-shadow` NE S'AJOUTE PAS À CELUI D'AVANT, IL LE
      REMPLACE. Écrire ici le seul filet intérieur effacerait
      l'ombre portée que ces surfaces avaient déjà, et les cartes
      se retrouveraient à plat sur le fond — l'inverse de ce
      qu'on cherche. On redéclare donc les deux : le filet ET une
      ombre de contact. */
.panel,
.universe-card,
.kpi,
.eq-carte,
.ll-carte,
.projet-carte {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.07),
              0 10px 26px -20px rgba(0,0,0,.85);
}

/* 3. Le menu. L'écran ouvert porte une lueur dans la couleur de
      son bloc — on sait où l'on est sans lire. */
.nav-item.is-actif,
.nav-item.is-active,
.nav-lien.is-actif {
  box-shadow: inset 2px 0 0 currentColor, 0 0 22px -12px currentColor;
}

/* =============================================================
   21.7 LE POP — CE QUI RÉPOND QUAND ON FAIT QUELQUE CHOSE

   Direction : « plus de pop up ou plus d'énergie positive ».

   ⚠ ON N'AJOUTE PAS DE FENÊTRES. Une fenêtre de plus, c'est un
   clic de plus pour tout le monde, toute la journée — l'inverse
   exact de « clean, simple, saheel ». Ce qui manquait n'était
   pas des fenêtres : c'était la RÉPONSE. L'OS encaissait les
   gestes sans rien dire.

   Maintenant il répond : le message qui arrive rebondit et
   compte son temps, le message de réussite s'allume en vert, les
   panneaux se posent au lieu d'apparaître, et ce qu'on touche
   s'éclaire.
   ============================================================= */

/* Le message porte une barre de temps : on voit combien il reste
   avant qu'il parte, au lieu de le voir disparaître d'un coup. */
.toast { position: relative; overflow: hidden; padding-right: 18px; }
.toast::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  transform-origin: left;
  background: currentColor;
  opacity: .5;
  animation: os25-minuteur 3600ms linear forwards;
}
.toast.err::after { animation-duration: 9000ms; }
@keyframes os25-minuteur { to { transform: scaleX(0); } }

/* La réussite s'allume : une pulsation verte, une seule fois.
   C'est la seule récompense de l'OS, et elle dure 900 ms. */
.toast.ok {
  animation: os25-toast 380ms var(--m-ressort) both,
             os25-reussite 900ms var(--m-doux) 380ms 1;
}
@keyframes os25-reussite {
  0%, 100% { box-shadow: var(--o-haute); }
  40%      { box-shadow: var(--o-haute), 0 0 34px -6px rgba(52,211,153,.75); }
}

/* Les panneaux se posent. Trois paliers suffisent : au-delà,
   l'attente se voit. */
@keyframes os25-pose {
  from { opacity: 0; transform: translateY(9px) scale(.995); }
  to   { opacity: 1; transform: none; }
}
/* ⚠ PAS DE `both`. MÊME RAISON QUE POUR .revele, ET ELLE A ÉTÉ
   MESURÉE ICI AVANT D'ÊTRE COMPRISE LÀ-BAS.

   Une animation d'entrée avec `animation-fill-mode: both` fait
   porter à l'élément son état de DÉPART tant que l'animation n'a
   pas joué — soit `opacity: 0`. Or une animation ne joue pas
   dans un onglet en arrière-plan : elle est suspendue à sa
   première image. Les panneaux y étaient donc parfaitement
   invisibles, et le sont restés jusqu'au retour sur l'onglet.

   En pratique ils réapparaissaient dès qu'on revenait — les
   animations reprennent — mais la règle est mauvaise : elle fait
   dépendre la VISIBILITÉ d'un contenu du bon déroulement d'une
   décoration.

   Sans `both`, les valeurs ci-dessous sont l'état normal du
   panneau. L'animation ne fait que le mettre en scène quand elle
   peut. */
.page > .panel {
  opacity: 1;
  transform: none;
  animation: os25-pose 340ms var(--m-ressort);
}
.page > .panel:nth-of-type(2) { animation-delay: 55ms; }
.page > .panel:nth-of-type(3) { animation-delay: 110ms; }

/* Ce qu'on touche s'éclaire — les pastilles, les puces, les
   filtres. Ce sont les gestes les plus fréquents de la journée
   et ils ne renvoyaient rien. */
.chip, .pill, .filtre, .scene-badge {
  transition: transform var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux),
              filter var(--m-court) var(--m-doux);
}
.chip:hover, .pill:hover, .filtre:hover {
  transform: translateY(-1px);
  filter: brightness(1.12);
  box-shadow: 0 0 18px -8px currentColor;
}

/* Le bouton enfoncé pousse un anneau vers l'extérieur. C'est le
   « pop » d'un vrai bouton : quelque chose part de sous le
   doigt. */
.btn:active:not(:disabled)::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  animation: os25-onde 420ms var(--m-doux) 1;
}
@keyframes os25-onde {
  from { box-shadow: 0 0 0 0 rgba(242,185,64,.45); }
  to   { box-shadow: 0 0 0 12px rgba(242,185,64,0); }
}

@media (prefers-reduced-motion: reduce) {
  .toast::after, .toast.ok, .page > .panel,
  .btn:active:not(:disabled)::before { animation: none !important; }
  .chip, .pill, .filtre, .scene-badge { transition: none !important; }
  .chip:hover, .pill:hover, .filtre:hover { transform: none !important; }
  body::before { display: none; }
}

@media (max-width: 760px) {
  .hero-solo .hero-scene { min-height: clamp(400px, 54vh, 520px) !important; }
  .hero-solo .scene-titre { font-size: 30px !important; }
  .hero-solo .scene-corps { padding: 24px 18px 92px !important; }
  body::before { display: none; }
}


/* =============================================================
   22. DEUXIÈME PASSE DE DENSITÉ — ET LE SIGLE DU STUDIO
   7 septembre 2026, tard

   Direction : « zid saghar chwiya, ou zid sghar l'econe dial
   studio. »

   ── LE SIGLE, MESURÉ

   Le « 25 » du menu fait 41 × 56 px, dans un bandeau de 92 px de
   haut — soit 10 % de la colonne, avant même le premier lien du
   menu. C'est une enseigne, pas un repère. Un logo dans un outil
   de travail sert à savoir où l'on est en un coup d'œil ; il n'a
   pas à se faire regarder.

       le sigle      56 → 38 px   (−32 %)
       le mot        34 → 23 px   (−32 %)
       le bandeau    92 → 66 px   (−28 %)

   Vingt-six pixels rendus à la colonne : un lien de menu entier.

   ── ET LE RESTE, ENCORE UN CRAN

   La première passe (section 21) avait ramené la couverture de
   703 à 532 px et les titres de 48 à 35. Ce second cran est plus
   court — de 8 à 12 % — parce qu'on approche du plancher : en
   dessous, on ne gagne plus de la densité, on perd de la
   lisibilité.

       couverture      532 → 470 px
       titre projet     35 → 31 px
       titre de page  22,5 → 20 px
       titre univers    22 → 19 px
       ligne de menu    40 → 35 px
       colonne         278 → 256 px
       bandeau haut     72 → 62 px

   ⚠ LE TEXTE COURANT NE BOUGE PLUS. Il est à 13 px depuis la
   première passe et il y reste. Douze pixels sur un écran qu'on
   lit huit heures par jour, ce n'est plus de la densité, c'est
   de la fatigue.
   ============================================================= */

/* ── 22.1 LE SIGLE DU STUDIO */
.brand {
  height: 66px !important;
  min-height: 0 !important;
  padding: 8px 14px 12px !important;
}
.brand-logo { height: 38px !important; }
.brand-marque { height: 23px !important; max-width: 72px !important; }
.build-mark { font-size: 6.5px !important; }

/* ── 22.2 LA COLONNE ET LE BANDEAU

   Les deux jetons sont posés par master-v2.css. On les redéfinit
   au lieu de réécrire les règles qui s'en servent : une valeur
   changée à un seul endroit, et la grille suit. */
:root,
.app {
  --sidebar-w: 256px !important;
  --header-h: 62px !important;
}

/* ── 22.3 LE MENU */
.nav-item {
  padding: 7px 10px !important;
  font-size: 12.5px !important;
}
.nav-cat-btn {
  padding: 7px 12px !important;
  font-size: 9.5px !important;
}

/* ── 22.4 LA COUVERTURE ET LES TITRES */
.hero-solo .hero-scene { min-height: clamp(400px, 50vh, 560px) !important; }
.hero-solo .scene-titre { font-size: clamp(24px, 2.1vw, 31px) !important; }
.hero-solo .scene-corps { padding: 28px 32px 74px !important; }
.hero-coiffe > .command-head .command-identity h1 {
  font-size: clamp(17px, 1.35vw, 21px) !important;
}
.hero-coiffe > .command-head { top: 18px; left: 32px; }
.hero-coiffe > .command-head > .avatar { width: 34px !important; height: 34px !important; }

.page h1,
.page-head h1,
.page-title { font-size: clamp(18px, 1.45vw, 21px) !important; }

.universe-card { padding: 15px 17px 14px !important; }
.universe-card h2 { font-size: clamp(16px, 1.3vw, 19px) !important; }
.universe-kpi b { font-size: 15.5px !important; }

/* Le cadran suit la couverture. */
.scene-cadran .anneau-boite { transform: scale(.72); }

@media (max-width: 760px) {
  .hero-solo .hero-scene { min-height: clamp(370px, 50vh, 480px) !important; }
  .hero-solo .scene-titre { font-size: 27px !important; }
  .brand { height: 58px !important; padding: 6px 12px 10px !important; }
  .brand-logo { height: 32px !important; }
}

/* ⚠ LE JETON NE SUFFISAIT PAS POUR LE BANDEAU.

   `--header-h` est bien redéfini plus haut, et `shell.css` s'en
   sert à quatre endroits — mais `master-v2.css` écrit la hauteur
   du bandeau en dur : `.header{height:72px!important}`. Le jeton
   n'y passe pas.

   On redéclare donc la hauteur à la même spécificité. os25.css
   étant chargée après, c'est la dernière qui parle. Les deux
   valeurs restent d'accord : le jeton à 62 px pour les décalages
   calculés dans shell.css, et la hauteur à 62 px ici. Les
   désaccorder ferait flotter le contenu sous un bandeau qui n'a
   plus la taille qu'on lui prête. */
.header { height: 62px !important; }


/* =============================================================
   23. L'ÉCLAT — LA LUMIÈRE QUI RÉPOND
   7 septembre 2026, nuit

   Direction : « zidni plus les animations et la dynamique avec
   les effects et les pop up et les lights, je veux plus de
   quality f OS. »

   ── LA DIFFÉRENCE ENTRE « PLUS D'ANIMATIONS » ET « PLUS DE
   QUALITÉ »

   Ce ne sont pas la même demande, et c'est la seconde qui
   compte. On peut faire clignoter trente choses et obtenir un
   écran fatigant ; la qualité vient d'ailleurs — de ce qui
   RÉPOND. Une surface qui s'éclaire sous la main, un chiffre qui
   se pose au lieu d'apparaître, un bord qui suit le regard :
   trois signes que la machine est vivante, sans qu'aucun d'eux
   ne bouge tout seul dans le vide.

   Cette section n'ajoute donc presque aucun mouvement autonome.
   Elle ajoute des RÉPONSES.

   ⚠ TROIS EFFETS ONT BESOIN DE assets/js/core/eclat.js. Ils sont
   marqués ci-dessous. Si ce fichier ne se charge pas, aucune
   règle d'ici ne casse quoi que ce soit : les classes qu'il pose
   n'existent simplement jamais, et les surfaces restent telles
   qu'elles étaient.
   ============================================================= */

/* ── 23.1 LA LUMIÈRE QUI SUIT LE DOIGT   [eclat.js]

   Une tache douce sous le curseur, à l'intérieur de la carte.
   `--mx` et `--my` sont écrits par le JS en pourcentage ; la
   feuille n'a pas besoin de connaître la taille de la carte.

   ⚠ AU REPOS, ELLE N'EXISTE PAS : `opacity: 0`. Elle n'apparaît
   qu'avec la classe `.a-lueur`, posée à l'entrée du curseur et
   retirée à la sortie. Rien ne tourne quand personne ne
   regarde. */
/* ⚠ ON NE POSE PAS `overflow: hidden` SUR CES CARTES.

   Ce serait la façon évidente d'empêcher la tache de dépasser
   des coins arrondis — et elle rognerait du même coup tout ce
   qui déborde déjà de ces cadres : l'orbite des deux univers,
   une pastille posée sur un bord, une ombre interne. Le rayon
   hérité par la tache elle-même fait le même travail sans rien
   couper. */
.universe-card, .kpi, .eq-carte, .ll-carte,
.projet-carte, .voie-carte, .gal-carte, .filmo-carte {
  position: relative;
}
.universe-card::after, .kpi::after, .eq-carte::after, .ll-carte::after,
.projet-carte::after, .voie-carte::after, .gal-carte::after, .filmo-carte::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 280ms var(--m-doux);
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%),
              rgba(255,255,255,.09), transparent 62%);
}
.a-lueur::after { opacity: 1 !important; }

/* Les deux univers prennent leur propre couleur plutôt que du
   blanc : SPIDER en violet, CERCLE en cyan. */
.universe-card.universe-spider::after {
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
              rgba(139,92,246,.20), transparent 62%);
}
.universe-card.universe-cercle::after {
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
              rgba(18,217,255,.18), transparent 62%);
}
.universe-card.universe-trame::after {
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%),
              rgba(242,185,64,.18), transparent 62%);
}

/* ⚠ LE CONTENU DOIT RESTER AU-DESSUS DE LA TACHE. Sans cette
   ligne, la lueur passerait par-dessus le texte des cartes. */
.universe-card > *, .kpi > *, .eq-carte > *, .ll-carte > *,
.projet-carte > *, .voie-carte > *, .gal-carte > *, .filmo-carte > * {
  position: relative;
  z-index: 1;
}

/* ── 23.2 LE BORD QUI TOURNE

   Un filet lumineux fait le tour de la couverture, très
   lentement — un tour en cinquante secondes. C'est la seule
   chose de l'écran qui bouge sans qu'on l'ait touchée, et elle
   est assez lente pour ne jamais attirer l'œil : on la remarque
   quand on la cherche, pas quand on travaille.

   ⚠ IL EST DESSINÉ SUR UN CADRE, PAS SUR LA CARTE. Un dégradé
   conique posé en fond de la couverture passerait sous l'image ;
   ici il est peint dans un cadre de 1 px découpé au masque, donc
   uniquement sur le bord. */
.hero-solo .hero-scene::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  border-radius: inherit;
  padding: 1px;
  pointer-events: none;
  background: conic-gradient(from 0deg,
    transparent 0deg, rgba(18,217,255,.55) 30deg, transparent 90deg,
    transparent 200deg, rgba(242,185,64,.45) 240deg, transparent 300deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation: os25-orbite 50s linear infinite;
}

/* ── 23.3 LES BLOCS QUI SE RÉVÈLENT   [eclat.js]

   ⚠ LA CLASSE `.a-reveler` N'EST POSÉE QUE SUR CE QUI EST HORS
   DE L'ÉCRAN. Un bloc déjà visible n'est jamais masqué — voir le
   commentaire de eclat.js. Si le script ne tourne pas, ces deux
   règles ne s'appliquent à rien. */
.a-reveler {
  opacity: 0;
  transform: translateY(16px);
}
/* ⚠ PAS DE `both` ICI, ET C'EST TOUT LE SUJET.

   Avec `animation-fill-mode: both`, un élément dont l'animation
   n'a pas encore démarré porte l'état de DÉPART — donc
   `opacity: 0`. Et une animation ne démarre pas dans un onglet
   caché : les animations y sont suspendues. Un bloc révélé
   pendant que l'onglet dort restait donc invisible, et le
   redevenait à chaque retour.

   Mesuré : opacité 0 après révélation, dans un onglet en
   arrière-plan.

   Sans `both`, les valeurs écrites ci-dessous s'appliquent
   toujours — avant l'animation, pendant qu'elle est suspendue, et
   après. L'animation ne fait plus que décorer le passage. C'est
   la règle de toute cette couche : un effet qui tombe en panne
   perd son brillant, il ne cache jamais le contenu. */
.revele {
  opacity: 1;
  transform: none;
  animation: os25-revele 520ms var(--m-ressort);
}
@keyframes os25-revele {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

/* ── 23.4 LE NOM DU PROJET SOUS LA VIGNETTE

   Survoler une vignette de la couverture disait jusqu'ici le nom
   du projet dans l'infobulle du navigateur — après une seconde,
   dans la police du système, en bas du curseur. Autant dire
   nulle part.

   ⚠ LE TEXTE VIENT DE `data-nom`, PAS DE `title`. eclat.js
   déplace l'attribut : sinon l'infobulle native s'ajouterait à
   la nôtre et on en verrait deux. Le bouton garde son
   `aria-label`, donc rien n'est perdu pour la lecture d'écran. */
.scene-vignette { position: relative; }
.scene-vignette::after {
  content: attr(data-nom);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  z-index: 6;
  padding: 5px 9px;
  border-radius: 7px;
  white-space: nowrap;
  font-size: 11px;
  font-weight: 600;
  color: #EAF2FB;
  background: rgba(5,8,13,.94);
  border: 1px solid rgba(18,217,255,.28);
  box-shadow: 0 10px 26px -12px #000;
  opacity: 0;
  transform: translate(-50%, 6px);
  pointer-events: none;
  transition: opacity 160ms var(--m-doux), transform 160ms var(--m-ressort);
}
.scene-vignette:hover::after,
.scene-vignette:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ── 23.5 LES DÉTAILS QUI SE VOIENT SANS QU'ON LES REGARDE

   Ce bloc ne contient aucune animation. C'est pourtant lui qui
   fait le plus pour la qualité perçue : ce sont les endroits où
   un logiciel soigné se distingue d'un logiciel monté vite. */

/* La barre de défilement. Celle du système, sur un fond sombre,
   est une barre grise de Windows au milieu d'un écran de studio. */
* { scrollbar-width: thin; scrollbar-color: rgba(120,150,190,.32) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
  background-color: rgba(120,150,190,.28);
}
::-webkit-scrollbar-thumb:hover { background-color: rgba(18,217,255,.45); }

/* Le texte sélectionné prend la couleur de la marque. */
::selection { background: rgba(242,185,64,.32); color: #fff; }

/* Le clavier. Un contour de focus qui a été dessiné, et non
   celui que le navigateur invente. Il ne s'affiche qu'au clavier
   — `:focus-visible`, pas `:focus` — donc jamais après un clic. */
:focus-visible {
  outline: 2px solid rgba(18,217,255,.75);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Les chiffres s'alignent en colonne. Sans cela, un « 1 » est
   plus étroit qu'un « 8 » et une colonne de montants ondule. */
.kpi b, .kpi .v, .universe-kpi b, td, .mono, .c25-compte {
  font-variant-numeric: tabular-nums;
}

/* L'attente. Un reflet traverse les blocs de chargement au lieu
   de les laisser gris : on voit que ça travaille. */
.skeleton, .sk-ligne {
  background: linear-gradient(90deg,
    rgba(120,150,190,.07) 25%, rgba(120,150,190,.16) 37%, rgba(120,150,190,.07) 63%);
  background-size: 400% 100%;
  animation: os25-attente 1400ms ease-in-out infinite;
}
@keyframes os25-attente {
  from { background-position: 100% 0; }
  to   { background-position: -100% 0; }
}

/* Les images arrivent en fondu plutôt qu'en claquant. */
.affiche { transition: opacity 320ms var(--m-doux); }

/* ── 23.6 MOUVEMENT RÉDUIT

   ⚠ eclat.js NE DÉMARRE MÊME PAS sous ce réglage : la lumière,
   les chiffres et les révélations n'existent pas. Ce qui reste à
   éteindre ici, c'est ce que la feuille fait seule. */
@media (prefers-reduced-motion: reduce) {
  .hero-solo .hero-scene::after,
  .skeleton, .sk-ligne { animation: none !important; }
  .a-reveler { opacity: 1 !important; transform: none !important; }
  .scene-vignette::after,
  .universe-card::after, .kpi::after, .eq-carte::after, .ll-carte::after,
  .projet-carte::after, .voie-carte::after, .gal-carte::after, .filmo-carte::after {
    transition: none !important;
  }
  .affiche { transition: none !important; }
}


/* =============================================================
   24. LA LUMIÈRE VIVANTE
   7 septembre 2026, nuit

   Direction : « zidni plus de light et plus des effects, les pop
   up khfaf kicha3lo ou ytfaw, les animation khfifa b light, les
   background et les pop up et les cercle kidiro b light
   futuriste. »

   ── CE QUE VEUT DIRE « KHFIF »

   Léger. C'est la consigne, et c'est aussi la seule façon que
   ça marche : une lumière qu'on remarque en travaillant est une
   lumière ratée. Tout ce qui suit reste sous 12 % d'opacité et
   au-dessus de 6 secondes de cycle. On doit sentir que l'écran
   est allumé sans jamais pouvoir dire ce qui bouge.

   ── ⚠ LA RÈGLE DE COÛT, APPRISE À LA SECTION 19

   Dix anneaux avec un dégradé conique FLOUTÉ mis en rotation
   faisaient tomber l'écran de 60 à 25 images par seconde : le
   flou doit être recalculé à chaque image, pour chacun.

   Ici, aucun `filter: blur()` n'est animé. Les balayages sont
   des dégradés coniques NETS découpés au masque, mis en rotation
   par `transform` — le navigateur les compose sur la carte
   graphique sans rien redessiner. Même effet à l'œil, coût
   quasi nul.

   ── CE QUI TOURNE EN PERMANENCE, ET C'EST TOUT

       la dérive du fond          1 élément
       le balayage des anneaux    n anneaux, transform seul
       la pastille du menu actif  1 élément
       le souffle d'une fenêtre   seulement quand elle est ouverte

   Tout le reste ne s'allume qu'au passage : les fenêtres et les
   messages s'allument en arrivant puis s'éteignent, comme
   demandé.
   ============================================================= */

/* ── 24.1 LE FOND QUI DÉRIVE

   La lueur d'ambiance posée à la section 21 était fixe. Elle
   respire maintenant et se déplace très lentement — 80 secondes
   pour un aller-retour de quelques pour cent. C'est en dessous
   du seuil où l'œil suit un mouvement : on ne voit pas la lueur
   bouger, on voit l'écran vivre.

   ⚠ C'EST UN `transform`, PAS UNE POSITION. Animer `left` ou
   `background-position` sur un calque plein écran force un
   nouveau rendu à chaque image. Une transformation est composée
   par la carte graphique, sans redessiner un pixel. */
body::before {
  animation: os25-derive 80s ease-in-out infinite;
  will-change: transform, opacity;
}
@keyframes os25-derive {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1);          opacity: 1; }
  33%      { transform: translate3d(-3%, 2%, 0) scale(1.08);    opacity: .82; }
  66%      { transform: translate3d(3%, -1.5%, 0) scale(1.04);  opacity: .93; }
}

/* Une seconde nappe, plus basse et plus lente encore, dans les
   couleurs des deux univers. Elle croise la première : c'est le
   croisement qui empêche de repérer un cycle. */
.app::after {
  content: "";
  position: fixed;
  left: 12%;
  right: -10%;
  bottom: -30vh;
  height: 60vh;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(50% 60% at 25% 100%, rgba(139,92,246,.07), transparent 72%),
    radial-gradient(45% 55% at 80% 92%, rgba(18,217,255,.055), transparent 74%);
  animation: os25-derive-basse 110s ease-in-out infinite;
}
@keyframes os25-derive-basse {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(4%, -3%, 0) scale(1.12); }
}

/* ── 24.2 LES CERCLES, EN LUMIÈRE FUTURISTE

   Un balayage fait le tour de chaque anneau, comme l'aiguille
   d'un radar : un arc clair sur trente degrés, le reste
   transparent, le tout découpé en couronne par un masque.

   ⚠ LE MASQUE EST CE QUI REND LA CHOSE GRATUITE. Sans lui, il
   faudrait un flou pour adoucir un disque plein. Avec lui, on
   découpe une couronne de 2 px dans un dégradé net : le
   navigateur ne fait plus que la tourner.

   Trois vitesses différentes selon l'objet — un anneau de
   panneau, le cadran de la couverture, une étape du CERCLE — pour
   qu'ils ne se synchronisent jamais entre eux. */
.anneau-boite::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(from 0deg,
    transparent 0deg 296deg,
    rgba(18,217,255,.65) 338deg,
    rgba(18,217,255,0) 360deg);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
  animation: os25-orbite 7s linear infinite;
}

/* Le cadran de la couverture : plus grand, plus lent, et en or —
   c'est la couleur de la marque, et c'est le seul anneau de
   l'écran qui la porte. */
.scene-cadran .anneau-boite::after {
  inset: -5px;
  background: conic-gradient(from 0deg,
    transparent 0deg 288deg,
    rgba(242,185,64,.7) 336deg,
    rgba(242,185,64,0) 360deg);
  animation-duration: 11s;
}

/* L'étape en cours du CERCLE 25 : un halo qui s'allume et
   s'éteint, sur six secondes. Elle en a déjà une couronne
   pointillée qui tourne ; le halo dit « c'est ici », la couronne
   dit « ça avance ». */
/* ⚠ ON PASSE OUTRE UNE PROTECTION DE PERFORMANCE. IL FAUT DIRE
   POURQUOI, ET DIRE JUSTE.

   perf.css, ligne 116, écrit exactement ceci :

       .c25-jalon.ici .c25-rond { animation: none !important }

   Elle vise donc le jalon ACTIF, et lui seul — pas les cinq. Elle
   éteignait `c25-battement` de neon.css, un battement de quatre
   secondes hérité de l'ancien CERCLE.

   Ce qu'on rallume n'est pas ce battement : c'est un souffle de
   six secondes sur l'ombre portée, sur UN élément. Les quatre
   autres jalons ne portent rien et n'en porteront pas — c'est le
   contraste avec eux qui rend celui-ci lisible. Cinq ronds qui
   battent ensemble ne disent rien ; un seul dit « c'est ici ».

   Le `!important` est nécessaire pour repasser devant celui de
   perf.css. Il ne va pas plus loin que le sélecteur le plus
   étroit possible. */
.c25-jalon.ici .c25-rond {
  animation: os25-souffle 6s ease-in-out infinite !important;
}
@keyframes os25-souffle {
  0%, 100% { box-shadow: 0 0 0 0 rgba(18,217,255,.34), 0 0 14px -6px rgba(18,217,255,.5); }
  50%      { box-shadow: 0 0 0 5px rgba(18,217,255,0),  0 0 28px -4px rgba(18,217,255,.85); }
}

/* ── 24.3 LES FENÊTRES QUI S'ALLUMENT PUIS S'ÉTEIGNENT

   Direction : « les pop up khfaf kicha3lo ou ytfaw ».

   Une fenêtre qui s'ouvre allume un anneau de lumière qui
   s'écarte et disparaît en 900 ms — l'ampoule qu'on vient
   d'allumer. Puis elle respire, très lentement, tant qu'elle
   est ouverte. Quand elle se ferme, il ne reste rien : aucune
   des deux ne tourne quand aucune fenêtre n'est ouverte. */
/* ⚠ `position: relative` N'EST PAS DÉCORATIF ICI.

   Un pseudo-élément en `inset: 0` se cale sur le plus proche
   ancêtre POSITIONNÉ. Si la fenêtre est en position statique,
   l'anneau de lumière ne se pose pas sur elle : il s'étale sur
   tout le voile, et on allume l'écran entier au lieu d'allumer
   la fenêtre. */
.modal { position: relative; }
.modal::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  animation: os25-allumage 900ms var(--m-doux) 1;
}
@keyframes os25-allumage {
  from { box-shadow: 0 0 0 0 rgba(18,217,255,.55), 0 0 60px 0 rgba(242,185,64,.4) inset; }
  to   { box-shadow: 0 0 0 26px rgba(18,217,255,0), 0 0 0 0 rgba(242,185,64,0) inset; }
}

/* Le souffle, tant qu'elle est là. Sur un liseré, pas sur une
   ombre portée : une ombre qui respire fait respirer toute la
   page derrière. */
/* ⚠ CETTE DÉCLARATION RETIRE AUSSI LE `both` DE L'OUVERTURE, ET
   C'EST VOULU.

   La règle de la section 19.7 écrivait
   `os25-fenetre … both` : la fenêtre portait donc son état de
   départ — invisible — tant que l'animation n'avait pas joué.
   Dans un onglet en arrière-plan, les animations sont
   suspendues : la fenêtre restait vide. C'est le même défaut que
   celui corrigé sur les panneaux, au même endroit du
   raisonnement. Ici il disparaît en passant. */
.modal {
  animation: os25-fenetre 420ms var(--m-ressort) 60ms,
             os25-veille 7s ease-in-out 1s infinite !important;
}
@keyframes os25-veille {
  0%, 100% { border-color: rgba(255,255,255,.09); }
  50%      { border-color: rgba(18,217,255,.34); }
}

/* Le voile derrière prend lui aussi une lueur, très basse, qui
   vient du centre — là où est la fenêtre. */
.modal-scrim {
  background-image: radial-gradient(60% 55% at 50% 45%, rgba(18,217,255,.07), transparent 70%);
}

/* ── 24.4 LES MESSAGES QUI S'ALLUMENT

   Même geste, en plus court : le message s'allume en arrivant,
   380 ms, puis plus rien. Il porte déjà sa barre de temps et,
   s'il annonce une réussite, sa pulsation verte. */
.toast::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  animation: os25-allumage-court 620ms var(--m-doux) 1;
}
@keyframes os25-allumage-court {
  from { box-shadow: inset 0 0 30px 0 rgba(255,255,255,.16); }
  to   { box-shadow: inset 0 0 0 0 rgba(255,255,255,0); }
}

/* ── 24.5 LE MENU

   La pastille du bloc ouvert respire, sur huit secondes. Une
   seule à la fois — c'est ce qui la rend lisible. */
.nav-cat[data-open="true"] > .nav-cat-btn::before {
  animation: os25-pastille 8s ease-in-out infinite;
}
@keyframes os25-pastille {
  0%, 100% { box-shadow: 0 0 0 0 currentColor; }
  50%      { box-shadow: 0 0 12px 0 currentColor; }
}

/* ── 24.6 LES PANNEAUX QUI S'ALLUMENT EN ARRIVANT

   Une lame de lumière traverse le panneau une fois, à son
   apparition. Elle ne se rejoue pas : l'élément n'est créé
   qu'une fois par écran. */
/* Même raison que pour la fenêtre : sans ancêtre positionné, la
   lame de lumière balaierait la page au lieu du panneau. */
.page > .panel { position: relative; }
.page > .panel::before,
.universe-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(100deg,
    transparent 42%, rgba(255,255,255,.055) 50%, transparent 58%);
  background-size: 300% 100%;
  animation: os25-lame-panneau 1600ms var(--m-doux) 1;
}
@keyframes os25-lame-panneau {
  from { background-position: 200% 0; }
  to   { background-position: -120% 0; }
}

/* ── 24.7 MOUVEMENT RÉDUIT

   ⚠ TOUT S'ARRÊTE. Une lueur qui dérive en permanence est
   exactement ce que ce réglage existe pour supprimer — et les
   éléments gardent leur état visible, puisque aucune de ces
   animations ne porte de remplissage.
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  body::before,
  .app::after,
  .anneau-boite::after,
  .scene-cadran .anneau-boite::after,
  .c25-jalon.ici .c25-rond,
  .modal::before,
  .toast::before,
  .nav-cat[data-open="true"] > .nav-cat-btn::before,
  .page > .panel::before,
  .universe-card::before {
    animation: none !important;
  }
  .modal { animation: none !important; }
  .app::after { display: none; }
}


/* =============================================================
   25. LA FINITION — LE RESTE DE L'ÉCRAN
   7 septembre 2026, nuit

   Direction : « zidni plus de lights ou plus des effects ou les
   animations. »

   Les sections 19 à 24 ont éclairé la couverture, les cartes, les
   anneaux, les fenêtres et le fond. Restaient les endroits où la
   main passe le plus souvent et où il ne se passait encore rien :
   la barre du haut, les champs, les tableaux, les filtres, les
   jauges, les avatars.

   ⚠ AUCUNE DE CES RÈGLES N'ANIME QUOI QUE CE SOIT EN PERMANENCE,
   sauf deux — la pastille de présence et le reflet des jauges —
   et les deux ne tournent que là où il y a une information à
   porter : quelqu'un est en ligne, une barre est en train de se
   remplir. Le reste répond au doigt et se rendort.
   ============================================================= */

/* ── 25.1 LA BARRE DE NAVIGATION QUI PASSE

   Une ligne de lumière traverse le haut du contenu à chaque
   changement d'écran, une fois, en 700 ms.

   ⚠ ELLE NE COÛTE PAS UNE LIGNE DE JAVASCRIPT. L'élément `.page`
   est reconstruit à chaque navigation ; une animation posée sur
   son pseudo-élément se rejoue donc toute seule, à chaque fois,
   sans qu'on ait rien à déclencher. C'est le genre d'effet qu'on
   code d'habitude avec un état, un minuteur et trois bogues.

   ⚠ CORRECTION DU 8 SEPTEMBRE — ELLE NE PASSAIT PAS, ELLE
   RESTAIT.

   Signalé depuis l'écran : « had light statique makit7arakch ».
   Vérifié en l'éteignant en direct — le trait a disparu, c'était
   bien celui-ci.

   La cause tient en un mot : `animation-fill-mode`. Sans lui, une
   animation ne laisse RIEN derrière elle. Les 700 ms passées, le
   pseudo-élément revient à son état de repos — et cet état de
   repos, faute d'`opacity` déclarée, valait 1. Le dégradé restait
   donc peint en travers de l'écran, immobile, jusqu'au prochain
   changement d'écran. La ligne de lumière était devenue une
   barre.

   Le repos est donc écrit noir sur blanc : `opacity: 0`. Pendant
   l'animation, les images-clés imposent 1 puis 0 ; après, on
   retombe sur 0. Et si les animations sont coupées — mouvement
   réduit, onglet en arrière-plan — le repos vaut 0 aussi, donc
   rien ne s'affiche. C'est l'inverse exact du piège de la section
   23.3 : ici on décore, on ne porte aucun contenu, donc l'état
   invisible est le bon état par défaut. */
.page::before {
  content: "";
  position: fixed;
  top: var(--header-h, 62px);
  left: var(--sidebar-w, 256px);
  right: 0;
  height: 2px;
  z-index: 20;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(90deg,
    transparent, rgba(18,217,255,.85), rgba(242,185,64,.7), transparent);
  background-size: 45% 100%;
  background-repeat: no-repeat;
  animation: os25-passage 700ms var(--m-doux) 1;
}
@keyframes os25-passage {
  from { background-position: -50% 0; opacity: 1; }
  70%  { opacity: 1; }
  to   { background-position: 150% 0; opacity: 0; }
}
.app[data-nav="reduit"] .page::before { left: 76px; }
@media (max-width: 1000px) { .page::before { left: 0; } }

/* ── 25.2 LES CHAMPS

   Un champ qui reçoit le curseur s'allume : le contour prend la
   couleur du studio et une lueur basse s'ouvre autour. C'est le
   geste le plus fréquent de la journée, et il ne renvoyait rien
   d'autre qu'un contour bleu de navigateur. */
input, textarea, select {
  transition: border-color var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux),
              background-color var(--m-court) var(--m-doux);
}
input:focus, textarea:focus, select:focus {
  border-color: rgba(18,217,255,.55) !important;
  box-shadow: 0 0 0 3px rgba(18,217,255,.10), 0 0 22px -10px rgba(18,217,255,.8) !important;
  outline: none;
}

/* La barre de recherche du bandeau : plus large quand on écrit
   dedans. Elle prend la place qu'il faut au moment où il la
   faut, et la rend ensuite. */
.searchbox { transition: box-shadow var(--m-moyen) var(--m-doux); }
.searchbox:focus-within {
  box-shadow: 0 0 0 1px rgba(18,217,255,.4), 0 0 30px -12px rgba(18,217,255,.9);
}

/* ── 25.3 LES TABLEAUX

   Une ligne survolée reçoit un filet lumineux à gauche, dans la
   couleur du studio. Pas un fond : un fond change la couleur du
   texte qu'on est en train de lire. */
tbody tr {
  box-shadow: inset 0 0 0 0 rgba(18,217,255,0);
  transition: background-color var(--m-court) var(--m-doux),
              transform var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux);
}
tbody tr:hover {
  box-shadow: inset 2px 0 0 0 rgba(18,217,255,.75);
}

/* ── 25.4 LES FILTRES ET LES ONGLETS

   Le filtre actif porte un trait de lumière sous lui. Il glisse
   d'un filtre à l'autre parce qu'il grandit depuis le centre —
   pas parce qu'on a calculé une position. */
.chip.on, .chip.actif, .chip[aria-pressed="true"],
.pill.on, .pill.actif { position: relative; }
.chip.on::after, .chip.actif::after, .chip[aria-pressed="true"]::after,
.pill.on::after, .pill.actif::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, currentColor, transparent);
  animation: os25-trait 320ms var(--m-ressort);
}
@keyframes os25-trait {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}

/* ── 25.5 LES JAUGES

   Un reflet parcourt la partie remplie d'une barre de
   progression. Il ne parcourt QUE le rempli : c'est ce qui fait
   qu'on lit la barre au lieu de la regarder. */
.barre > i, .jauge i, .eq-jauge i, .ll-charge i {
  position: relative;
  overflow: hidden;
}
.barre > i::after, .jauge i::after, .eq-jauge i::after, .ll-charge i::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    transparent 35%, rgba(255,255,255,.35) 50%, transparent 65%);
  background-size: 250% 100%;
  animation: os25-reflet-jauge 2600ms ease-in-out infinite;
}
@keyframes os25-reflet-jauge {
  from { background-position: 180% 0; }
  to   { background-position: -80% 0; }
}

/* ── 25.6 LA PRÉSENCE — RÈGLE RETIRÉE, ET IL FAUT DIRE POURQUOI

   J'avais écrit ici une pulsation verte sur
   `.point-sig.sig-termine`, en croyant viser « quelqu'un est en
   ligne ». Vérification faite dans le code, cette classe veut
   dire quatre choses différentes :

       shell.js        « l'OS est ouvert »
       dashboard.js    « en ligne »
       horaires.js     « le studio est ouvert »
       ma-mission.js   « cette étape est faite »

   La faire battre aurait donc fait clignoter en vert toutes les
   cases cochées de l'écran « Ma mission ». Une pastille qui bat
   ne veut plus rien dire quand tout bat.

   Et deux décisions existantes disaient déjà non :

       perf.css:246          .point-sig { animation: none !important }
       neon-systeme.css:629  .point-sig.sig-termine { animation: none }

   La première parce qu'un écran en porte des dizaines. La
   seconde parce qu'un état terminé est un état au repos.

   Enfin, le vrai voyant de présence existe déjà et respire déjà :
   `.eq-lampe.vivant { animation: breathe 2s }`, dans neon.css.
   Il n'y avait rien à ajouter — seulement à ne pas casser ce qui
   marchait. */

/* ── 25.7 LES ÉTATS VIDES

   Un écran vide n'est pas une panne, et il ne doit pas en avoir
   l'air. Son icône reçoit une lueur lente : la page est allumée,
   il n'y a simplement rien dedans. */
.empty .ico {
  animation: os25-vide 5s ease-in-out infinite;
}
@keyframes os25-vide {
  0%, 100% { opacity: .55; filter: drop-shadow(0 0 0 transparent); }
  50%      { opacity: .85; filter: drop-shadow(0 0 14px rgba(18,217,255,.45)); }
}

/* ── 25.8 LA CLOCHE

   Quand il y a du non-lu, la pastille bat. Quand il n'y en a
   pas, rien ne bouge — sinon la pastille ne veut plus rien dire.

   ⚠ CORRECTION DU 8 SEPTEMBRE — CETTE RÈGLE NE S'APPLIQUAIT PAS.

   Elle visait `.notif-btn .badge`. Ces deux classes n'existent
   nulle part : le bouton s'écrit `.icon-btn#notif-btn` et sa
   pastille `.compteur` (shell.css:301). La règle était donc
   valide, silencieuse, et sans effet depuis le jour où je l'ai
   écrite. Une feuille de style ne prévient jamais qu'elle vise
   du vide — c'est pour cela qu'on relit les sélecteurs contre le
   code qui produit le HTML, pas contre le souvenir qu'on en a.

   ⚠ ET LA PULSATION D'ARRIVÉE EST RECONDUITE EXPRÈS.

   `#notif-btn .compteur` (1,0,1) bat `.icon-btn .compteur.arrive`
   (0,3,0), et os25.css se charge après shell.css : poser le
   battement seul aurait supprimé le sursaut du moment où le
   nombre augmente. La seconde règle redonne les deux ensemble. */
#notif-btn .compteur {
  animation: os25-cloche 2400ms ease-in-out infinite;
}
#notif-btn .compteur.arrive {
  animation: arrivee 900ms var(--e-out) 1,
             os25-cloche 2400ms ease-in-out infinite;
}
@keyframes os25-cloche {
  0%, 100% { box-shadow: 0 0 0 0 rgba(248,113,113,.55); }
  50%      { box-shadow: 0 0 0 6px rgba(248,113,113,0); }
}

/* ── 25.9 MOUVEMENT RÉDUIT */
@media (prefers-reduced-motion: reduce) {
  .page::before,
  .chip.on::after, .chip.actif::after, .chip[aria-pressed="true"]::after,
  .pill.on::after, .pill.actif::after,
  .barre > i::after, .jauge i::after, .eq-jauge i::after, .ll-charge i::after,
  .empty .ico,
  #notif-btn .compteur, #notif-btn .compteur.arrive {
    animation: none !important;
  }
  input, textarea, select, .searchbox, tbody tr { transition: none !important; }
}


/* =============================================================
   26. LE NOM DE L'ASSISTANT, À CÔTÉ DE SON ORBE
   7 septembre 2026

   ⚠ CE N'EST PAS UN NOUVEL ASSISTANT. Celui de l'OS existe
   depuis le 4 septembre, il est monté sur la coque
   (shell.js → monterAssistant), il est présent sur les 44 écrans
   et il répond — vérifié en production le 7 septembre : ouvert
   depuis « Projets », il a répondu « Vous êtes sur l'écran : la
   liste des projets. »

   Ce qu'il lui manquait, c'était son nom. Un orbe de 58 px avec
   une icône de terminal ne dit pas « intelligence
   artificielle », et la capture de référence portait, elle, un
   bouton écrit « 25 ASSISTANT » en toutes lettres.

   ⚠ ON N'ÉLARGIT PAS L'ORBE POUR AUTANT.

   Première version : en faire une pastille allongée. Mauvaise
   idée, et la raison est dans la section juste au-dessus —
   l'orbe porte une couronne conique et un halo, tous deux
   découpés par des masques CIRCULAIRES : un dégradé radial en
   cercle, et un rayon de 50 %. Étirer le bouton aurait tordu
   les deux en ellipses décentrées.

   L'étiquette se pose donc À CÔTÉ, en absolu, sans toucher au
   bouton. L'orbe garde sa forme, sa couronne et son halo. */
.assistant-bulle { overflow: visible !important; }

.assistant-bulle .bulle-nom {
  position: absolute;
  right: calc(100% + 10px);
  top: 50%;
  transform: translateY(-50%);
  padding: 6px 11px;
  border-radius: 999px;
  white-space: nowrap;
  font: 700 9.5px/1 "JetBrains Mono", ui-monospace, monospace;
  letter-spacing: .16em;
  color: #CFE6F6;
  background: rgba(6, 22, 32, .92);
  border: 1px solid rgba(18, 217, 255, .3);
  box-shadow: 0 10px 26px -14px #000;
  pointer-events: none;
}

/* Ouvert, le nom s'efface : le panneau le porte déjà, et
   l'écrire deux fois à trente centimètres est du bruit. */
.assistant-bulle.est-ouvert .bulle-nom { display: none; }

/* Sous 1100 px, il ne reste que l'orbe : l'étiquette mordrait
   sur le contenu. */
@media (max-width: 1100px) {
  .assistant-bulle .bulle-nom { display: none; }
}


/* =============================================================
   27. L'OS EST SOMBRE, ET LE BOUTON DE THÈME LE DIT MAINTENANT
   7 septembre 2026 — trouvé pendant l'audit général

   ⚠ LE BOUTON « CHANGER LE THÈME » RENDAIT L'OS ILLISIBLE.

   Mesuré en thème clair, dans l'aperçu :

       titre de page     texte #101720 sur fond #05080D  = 1,11:1
       titre de panneau  idem                            = 1,11:1
       corps du texte    idem                            = 1,11:1
       titre d'univers   #0E1116 sur #05080D             = 1,06:1

   Le minimum lisible est 4,5:1. À 1,1, c'est du noir sur noir :
   l'écran entier devenait vide à l'œil.

   ── LA CAUSE

   tokens.css contient un thème clair complet et soigné — chaque
   couleur y porte en commentaire son contraste mesuré, plusieurs
   ont été assombries exprès pour passer le seuil. Ce travail est
   juste, et il fonctionnait.

   master-v2.css — la feuille du build V12, adoptée le
   7 septembre — est un OS SOMBRE. Elle ne contient pas une seule
   règle de thème clair, et elle repeint les fonds. Chargée en
   avant-dernier, elle gagne partout où elle parle.

   Les textes passaient donc au sombre pendant que les fonds
   restaient sombres.

   ── POURQUOI ON NE « RÉPARE » PAS LE THÈME CLAIR ICI

   J'ai essayé : re-déclarer les quatorze jetons écrasés sous
   `:root[data-theme="light"]`. Les jetons changent bien — vérifié,
   `--bg-0` passe à #F4F5F7 — et les fonds restent noirs quand
   même. master-v2 ne se contente pas de poser des jetons, elle
   peint. Rendre cette feuille bi-thème, c'est réécrire ses
   28 000 caractères de décisions sombres, une par une. C'est un
   chantier, pas une correction d'audit.

   ── CE QU'ON FAIT

   On retire le bouton. Un OS sombre assumé vaut mieux qu'un
   bouton qui mène à un écran vide — et personne ne perd rien
   qu'il avait : le thème clair ne marchait plus depuis l'adoption
   de master-v2.

   ⚠ RIEN N'EST SUPPRIMÉ DU CODE. `appliquerTheme` reste, le
   jeton reste, tokens.css garde son thème clair intact. Le jour
   où l'on voudra un vrai thème clair, il n'y aura qu'à retirer
   ces quatre lignes et faire le chantier de master-v2.
   ============================================================= */
#theme-btn { display: none !important; }


/* =============================================================
   28. LES PROPOSITIONS DE L'ASSISTANT
   7 septembre 2026

   L'assistant ne modifie rien tout seul : il prépare, et la carte
   ci-dessous attend un clic. Elle doit donc se lire SANS effort
   et sans confiance — le tableau visé en haut, chaque champ avec
   sa valeur en dessous, deux boutons en bas.

   ⚠ ELLE NE RESSEMBLE PAS À UNE BULLE DE CONVERSATION. Une
   proposition qui va écrire dans la base ne doit pas avoir
   l'apparence d'un message qu'on survole : liseré or à gauche,
   fond légèrement plus clair, coins moins arrondis. On doit voir
   qu'elle demande une décision.
   ============================================================= */
.as-action {
  margin: 2px 0 4px;
  padding: 12px 13px 11px;
  border-radius: 10px;
  border: 1px solid rgba(242,185,64,.28);
  border-left: 3px solid #F2B940;
  background: linear-gradient(160deg, rgba(242,185,64,.07), rgba(9,14,22,.6));
  animation: os25-as-bulle 320ms var(--m-ressort);
}
.as-action-tete { display: flex; align-items: flex-start; gap: 9px; }
.as-action-pastille {
  display: inline-flex;
  flex: none;
  width: 22px;
  height: 22px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(242,185,64,.16);
  color: #F2B940;
}
.as-action-tete b { display: block; font-size: 12.5px; color: #F0E4C8; }
.as-action-ou { display: block; margin-top: 1px; font-size: 11px; color: rgba(148,180,214,.8); }

/* Les champs. `dl` plutôt qu'un tableau : c'est une liste de
   couples, et un lecteur d'écran l'annonce comme telle. */
.as-action-champs {
  margin: 10px 0 0;
  display: grid;
  grid-template-columns: minmax(0, 34%) minmax(0, 1fr);
  gap: 5px 10px;
  font-size: 12px;
}
.as-action-champs dt { color: rgba(148,180,214,.85); }
.as-action-champs dd {
  margin: 0;
  color: #E4ECF5;
  word-break: break-word;
  white-space: pre-wrap;
}

.as-action-pied {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 11px;
  padding-top: 9px;
  border-top: 1px solid rgba(242,185,64,.16);
}

/* Une fois écrit, la carte se calme : le vert dit que c'est
   fait, et le liseré or n'a plus de décision à réclamer. */
.as-action-faite {
  border-color: rgba(52,211,153,.3);
  border-left-color: #34D399;
  background: linear-gradient(160deg, rgba(52,211,153,.07), rgba(9,14,22,.6));
}
.as-action-ok { font-size: 12px; font-weight: 700; color: #34D399; }


/* =============================================================
   29. « CERCLE » DÉCALÉ DANS LA CHAÎNE DU HAUT
   8 septembre 2026

   Signalé depuis l'écran : « mdarag lktaba » — le mot CERCLE ne
   s'alignait pas sur BORN et SPIDER, il flottait au-dessus.

   ── CE N'ÉTAIT PAS UN PROBLÈME D'ALIGNEMENT

   Mesuré dans la page : BORN et SPIDER font 8 px de haut,
   CERCLE en faisait 38. La chaîne est en `align-items: center`,
   donc une étiquette trois fois plus haute que ses voisines
   déborde en haut et en bas. Le décalage n'était que le symptôme.

   ── DEUX CHOSES DIFFÉRENTES PORTENT LE MÊME NOM

   `pages.css:6` définit `.cercle` comme un COMPOSANT : l'anneau
   de progression de 38 × 38 px, avec son `svg`, ses `.arc` et son
   `.core`. Le dashboard, lui, écrit
   `el("span", { class: "cercle", text: "CERCLE" })` — une simple
   étiquette de couleur (dashboard.js:476). Le sélecteur `.cercle`
   ne fait pas la différence : il imposait 38 × 38 à un mot.

   ⚠ ET C'EST BIEN UNE COLLISION DE NOM, PAS UNE ERREUR DE STYLE.
   Tant que les deux partagent le nom, n'importe quelle étiquette
   `.cercle` ajoutée ailleurs se fera écraser pareil. Le vrai
   remède serait de renommer l'un des deux — mais la couleur cyan
   de l'étiquette vient de `master-v2.css`, un fichier minifié
   qu'on ne touche pas pour un mot. On rend donc ici sa taille
   naturelle à l'étiquette, sans approcher le composant : le
   sélecteur est limité à la chaîne du haut, et à elle seule.

   Les vrais anneaux — `.cercle` avec un `svg` dedans, et
   `.cercle.lg` — gardent leurs dimensions : aucun n'est dans
   `.command-chain`. */
.command-chain .cercle {
  width: auto;
  height: auto;
}


/* =============================================================
   30. LE BORD DE LA COUVERTURE : IL NE TOURNAIT PAS AUTOUR,
       IL TRAVERSAIT
   8 septembre 2026

   Signalé depuis l'écran : « had light statique makit7arakch ».
   Vérifié en l'éteignant en direct — le trait a disparu, c'était
   bien la règle 23.2.

   ── CE QUE JE CROYAIS AVOIR ÉCRIT, ET CE QUI TOURNAIT VRAIMENT

   23.2 promet « un filet lumineux qui fait le tour de la
   couverture ». Le mécanisme, lui, faisait autre chose :

       @keyframes os25-orbite { to { transform: rotate(360deg); } }

   On ne faisait pas tourner la LUMIÈRE le long du bord : on
   faisait tourner LE CADRE ENTIER sur lui-même. Sur un cercle,
   les deux reviennent au même — c'est pourquoi les six autres
   usages d'`os25-orbite` sont corrects, ils sont tous en
   `border-radius: 50%` (vérifié un par un). Sur un rectangle,
   non : un cadre de 1 px penché de soixante-treize degrés coupe
   la couverture en travers. Le « filet du bord » était devenu une
   barre au milieu de l'image.

   ⚠ ET C'EST BIEN POUR ÇA QU'IL PARAISSAIT IMMOBILE. Il tournait
   — un tour en cinquante secondes. À cette vitesse, une aiguille
   qui traverse l'écran ne se lit pas comme un mouvement : elle se
   lit comme un trait oublié là.

   ── LA CORRECTION

   On ne bouge plus l'élément, on bouge l'angle du dégradé. Le
   cadre reste collé au bord, et c'est la lumière qui en fait le
   tour — ce que la section 23.2 décrivait depuis le début.

   `os25-orbite` n'est pas touché : les six cercles qui s'en
   servent continuent de tourner comme avant. Cette règle-ci a son
   propre nom, et ne vise que la couverture.

   Le repli `var(--os25-tour, 0deg)` couvre le navigateur qui ne
   connaîtrait pas `@property` : il verra un bord coloré fixe,
   au bon endroit, plutôt que rien. */
@property --os25-tour {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

.hero-solo .hero-scene::after {
  background: conic-gradient(from var(--os25-tour, 0deg),
    transparent 0deg, rgba(18,217,255,.55) 30deg, transparent 90deg,
    transparent 200deg, rgba(242,185,64,.45) 240deg, transparent 300deg);
  animation: os25-tour-bord 50s linear infinite;
}
@keyframes os25-tour-bord { to { --os25-tour: 360deg; } }


/* =============================================================
   31. SPIDER 25 — L'ÉCRAN UNIQUE
   8 septembre 2026

   Huit entrées de menu deviennent une. Les styles vivent ici
   plutôt que dans la page : la politique de sécurité de l'OS
   interdit les styles en ligne, et une classe se relit.

   ⚠ LES COULEURS D'ÉTAPE NE SONT PAS DÉCORATIVES. Elles
   remplacent le surlignage manuel du Google Sheet — sauf qu'ici
   personne ne les choisit à la main : elles viennent de l'étape,
   qui vient elle-même de la dernière trace.
   ============================================================= */

.spider { --sp-r: 13px; }

/* ── 31.1 LES CINQ VUES */
.sp-vues {
  display: flex; gap: 5px; flex-wrap: wrap; margin: 0 0 14px;
  padding: 5px; border: 1px solid var(--n-bord); border-radius: 12px;
  background: rgba(12,19,28,.8);
}
.sp-vue {
  flex: 1 1 auto; min-width: 118px; padding: 10px 14px;
  border: 0; border-radius: 8px; background: transparent; color: var(--n-tx-2);
  font: 600 13px/1.3 inherit; letter-spacing: -.01em; cursor: pointer;
  transition: background var(--m-court) var(--m-doux), color var(--m-court) var(--m-doux);
}
.sp-vue:hover { color: var(--n-tx); background: rgba(255,255,255,.03); }
.sp-vue.on {
  background: linear-gradient(160deg, #2A1D4D, #151C29); color: #fff;
  box-shadow: inset 0 0 0 1px rgba(139,92,246,.36);
}

.sp-panneau { margin-bottom: 12px; }
.sp-panneau .panel-head { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.sp-note { margin-left: auto; color: var(--n-tx-3); font-size: 12px; }
.sp-vide { padding: 6px 2px; }
.sp-defile { overflow-x: auto; }
.sp-num { font-variant-numeric: tabular-nums; }
.sp-muet { color: var(--n-tx-3); }
.sp-ok { color: var(--n-vert); }
.sp-mal { color: var(--n-rouge); }

/* ── 31.2 LES TUILES DU MATIN */
.sp-tuiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 10px; }
.sp-tuile {
  position: relative; overflow: hidden;
  padding: 15px 16px; border: 1px solid var(--n-bord); border-radius: 12px;
  background: rgba(17,26,37,.7);
}
.sp-tuile::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--sp-tn, var(--n-bord));
}
.sp-tuile b {
  display: block; font-size: 29px; line-height: 1; letter-spacing: -.04em;
  font-variant-numeric: tabular-nums; color: var(--sp-tn, var(--n-tx));
}
.sp-tuile span { display: block; margin-top: 8px; color: var(--n-tx-2); font-size: 12.5px; line-height: 1.35; }
.sp-tuile small { display: block; margin-top: 5px; color: var(--n-tx-3); font-size: 11px; }
.sp-t-urgent { --sp-tn: var(--n-rouge); }
.sp-t-jour   { --sp-tn: var(--n-or); }
.sp-t-ok     { --sp-tn: var(--n-vert); }
.sp-t-info   { --sp-tn: var(--n-cyan); }

/* ── 31.3 LES HUIT ÉTAPES */
.sp-rail { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 6px; }
@media (max-width: 1100px) { .sp-rail { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 560px)  { .sp-rail { grid-template-columns: repeat(2, 1fr); } }
.sp-etape {
  padding: 12px 10px; text-align: left; cursor: pointer;
  border: 1px solid var(--n-bord); border-radius: 10px;
  background: rgba(17,26,37,.7); color: inherit; font: inherit;
  transition: border-color var(--m-court) var(--m-doux), transform var(--m-court) var(--m-doux);
}
.sp-etape:hover { border-color: rgba(120,150,190,.34); transform: translateY(-2px); }
.sp-etape.on { border-color: rgba(139,92,246,.55); background: rgba(139,92,246,.10); }
.sp-etape b {
  display: block; font-size: 21px; line-height: 1; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; color: var(--sp-c, var(--n-tx));
}
.sp-etape span { display: block; margin-top: 6px; font-size: 11.5px; font-weight: 600; }
.sp-etape small { display: block; margin-top: 2px; font-size: 10px; color: var(--n-tx-3); line-height: 1.25; }

/* Une couleur par étape, partagée par la pastille et le rail. */
.sp-e-nouveau      { --sp-c: var(--n-cyan); }
.sp-e-tentative    { --sp-c: var(--n-tx-2); }
.sp-e-discussion   { --sp-c: var(--n-violet); }
.sp-e-rdv          { --sp-c: var(--n-or); }
.sp-e-presentation { --sp-c: #FF9F6B; }
.sp-e-devis        { --sp-c: #7EEAFF; }
.sp-e-signe        { --sp-c: var(--n-vert); }
.sp-e-ecarte       { --sp-c: var(--n-tx-3); }

.sp-puce {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 4px 10px; border-radius: var(--r-full); font-size: 11px; font-weight: 600;
  color: var(--sp-c, var(--n-tx-2));
  border: 1px solid color-mix(in srgb, var(--sp-c, var(--n-bord)) 36%, transparent);
  background: color-mix(in srgb, var(--sp-c, transparent) 10%, transparent);
}
.sp-puce i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

/* ── 31.4 LA PROVENANCE — comment ouvrir la conversation */
.sp-prov {
  display: inline-block; padding: 3px 9px; border-radius: 6px;
  font-family: var(--f-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; white-space: nowrap;
  color: var(--sp-vc); border: 1px solid color-mix(in srgb, var(--sp-vc) 38%, transparent);
  background: color-mix(in srgb, var(--sp-vc) 11%, transparent);
}
.sp-v-pub    { --sp-vc: #C9B4FF; }
.sp-v-radar  { --sp-vc: #7EEAFF; }
.sp-v-ancien { --sp-vc: #F7D89A; }
.sp-source { color: var(--n-tx-3); font-size: 12px; }

/* ── 31.5 LES LISTES */
.sp-table tbody tr { cursor: pointer; }
.sp-table tbody tr.sp-fixe { cursor: default; }
.sp-ent { font-weight: 600; letter-spacing: -.01em; }
.sp-sous { display: block; color: var(--n-tx-3); font-size: 11.5px; margin-top: 2px; }
.sp-dort { color: var(--n-rouge); font-weight: 700; }
.sp-dort-doux { color: var(--n-or); font-weight: 600; }

/* ── 31.6 LES CARTES — les trois piles, puis l'équipe */
.sp-cartes { display: grid; grid-template-columns: repeat(auto-fit, minmax(248px, 1fr)); gap: 11px; }
.sp-carte {
  border: 1px solid var(--n-bord); border-radius: 12px;
  background: rgba(17,26,37,.7); padding: 16px 17px;
}
.sp-carte-tete { margin-bottom: 8px; }
.sp-carte h3 { margin: 0 0 4px; font-size: 20px; letter-spacing: -.025em; }
.sp-quoi { margin: 0 0 13px; color: var(--n-tx-3); font-size: 12.5px; line-height: 1.45; }
.sp-entonnoir { display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; }
.sp-mesures { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.sp-mini, .sp-entonnoir > div {
  padding: 9px 10px; border-radius: 9px;
  background: rgba(255,255,255,.022); border: 1px solid rgba(120,150,190,.10);
}
.sp-mini b, .sp-entonnoir b {
  display: block; font-size: 18px; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -.03em;
}
.sp-mini span, .sp-entonnoir span {
  display: block; margin-top: 5px; font-size: 10px; color: var(--n-tx-3); line-height: 1.2;
}
.sp-verdict { margin: 12px 0 0; font-size: 12.5px; color: var(--n-tx-2); }

.sp-gen-tete { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }
.sp-rond {
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  font-family: var(--f-mono); font-weight: 700; font-size: 13px; color: #C9B4FF;
  background: linear-gradient(150deg, #241a44, #10151f);
  border: 1px solid rgba(139,92,246,.35);
}
.sp-gen-tete b { display: block; font-size: 15px; letter-spacing: -.02em; }
.sp-role {
  display: block; color: var(--n-tx-3); font-family: var(--f-mono);
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
}
.sp-alerte {
  margin: 11px 0 0; padding: 9px 11px; border-radius: 9px; font-size: 12px; color: #FFB3B7;
  border: 1px solid rgba(255,77,85,.26); background: rgba(255,77,85,.06);
}
.sp-calme {
  margin: 11px 0 0; padding: 9px 11px; border-radius: 9px; font-size: 12px; color: #8FE9BC;
  border: 1px solid rgba(36,217,129,.22); background: rgba(36,217,129,.05);
}

/* ── 31.7 LA FICHE — le journal des tentatives */
.sp-fond {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(3,6,10,.72); display: grid; place-items: end center;
}
.sp-fiche {
  width: min(720px, 100%); max-height: 88vh; overflow-y: auto;
  padding: 22px 24px 30px; border-radius: 16px 16px 0 0;
  border: 1px solid rgba(120,150,190,.3); background: #0C131C;
  box-shadow: 0 -30px 90px rgba(0,0,0,.8);
}
.sp-fiche-tete { display: flex; align-items: flex-start; gap: 12px; }
.sp-fiche-tete h3 { margin: 0; font-size: 22px; letter-spacing: -.03em; }
.sp-fermer {
  margin-left: auto; flex: none; width: 32px; height: 32px; cursor: pointer;
  border: 1px solid var(--n-bord); border-radius: 9px;
  background: transparent; color: var(--n-tx-2); font-size: 17px; line-height: 1;
}
.sp-fermer:hover { color: var(--n-tx); border-color: rgba(120,150,190,.34); }
.sp-fiche-meta { margin: 4px 0 14px; color: var(--n-tx-3); font-size: 12.5px; }
.sp-fiche-puces { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 6px; }
.sp-titre-fil {
  margin: 20px 0 8px; font-family: var(--f-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .15em; text-transform: uppercase; color: var(--n-tx-3);
}
.sp-fil { list-style: none; margin: 0; padding: 0 0 0 20px; position: relative; }
.sp-fil::before {
  content: ""; position: absolute; left: 5px; top: 6px; bottom: 6px;
  width: 1px; background: var(--n-bord);
}
.sp-fil li { position: relative; padding: 8px 0; }
.sp-fil li::before {
  content: ""; position: absolute; left: -19px; top: 15px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #0C131C; border: 2px solid var(--sp-fc, var(--n-bord));
}
.sp-f-appel { --sp-fc: var(--n-cyan); }
.sp-f-rdv   { --sp-fc: var(--n-or); }
.sp-f-doc   { --sp-fc: #7EEAFF; }
.sp-f-vide  { --sp-fc: var(--n-tx-3); }
.sp-quand { font-family: var(--f-mono); font-size: 10.5px; color: var(--n-tx-3); letter-spacing: .04em; }
.sp-quoi { display: block; margin-top: 2px; }
.sp-qui { color: var(--n-tx-3); font-size: 12px; }
.sp-prochaine {
  margin: 18px 0 0; padding: 14px 16px; border-radius: 11px;
  border: 1px solid rgba(242,185,64,.3); border-left: 2px solid var(--n-or);
  background: rgba(242,185,64,.06);
}
.sp-prochaine b {
  display: block; margin-bottom: 5px; font-family: var(--f-mono);
  font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--n-or);
}
.sp-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 18px; }

/* ── 31.8 L'ATELIER — trois champs, un document */
.sp-atelier { display: grid; grid-template-columns: 300px 1fr; gap: 14px; }
@media (max-width: 900px) { .sp-atelier { grid-template-columns: 1fr; } }
.sp-champ { display: block; margin-bottom: 12px; }
.sp-champ > span {
  display: block; margin-bottom: 6px; font-family: var(--f-mono);
  font-size: 9.5px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--n-tx-3);
}
.sp-champ textarea { min-height: 74px; resize: vertical; }
.sp-avis {
  margin: 4px 0 0; padding: 12px 14px; border-radius: 10px; font-size: 12.5px; color: #9FE8FA;
  border: 1px solid rgba(18,217,255,.24); background: rgba(18,217,255,.055);
}

/* ⚠ LA FEUILLE EST LE SEUL ENDROIT CLAIR DE L'OS, ET C'EST VOULU.
   C'est un document destiné à sortir — un PDF sur fond noir ne
   s'imprime pas, et un client ne reçoit pas une page d'interface. */
.sp-feuille {
  min-height: 400px; padding: 34px 36px; border-radius: 11px;
  background: #FBFAF7; color: #14161A;
  box-shadow: 0 26px 70px rgba(0,0,0,.55);
}
.sp-marque {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: 14px; margin-bottom: 22px; border-bottom: 2px solid #14161A;
}
.sp-marque b { font-size: 17px; letter-spacing: -.02em; }
.sp-marque span {
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: #6B7280;
}
.sp-feuille h4 { margin: 0 0 5px; font-size: 27px; letter-spacing: -.035em; line-height: 1.1; }
.sp-destinataire { margin: 0 0 24px; color: #6B7280; font-size: 13px; }
.sp-feuille h5 {
  margin: 22px 0 7px; font-family: var(--f-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: #7C3AED;
}
.sp-feuille p { margin: 0 0 10px; font-size: 13.5px; line-height: 1.65; color: #2A2F38; }
.sp-manque { color: #9CA3AF; font-style: italic; }
.sp-pied {
  margin-top: 26px; padding-top: 12px; border-top: 1px solid #D8D5CE;
  color: #6B7280; font-size: 11.5px;
}

/* ── 31.9 LA CHAÎNE ENTIÈRE — ajoutée le 8 septembre 2026

   La Direction : « kayn vu global ou dakchi lié ou organisé ? »
   SPIDER s'arrêtait au contrat, CERCLE 25 commençait au projet, et
   personne ne voyait le passage entre les deux. Les maillons se
   lisent de gauche à droite ; la flèche est dessinée en CSS parce
   qu'elle relie sans rien ajouter à lire. */
.sp-chaine {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 18px;
}
@media (max-width: 1100px) { .sp-chaine { grid-template-columns: repeat(3, 1fr); gap: 20px 18px; } }
@media (max-width: 620px)  { .sp-chaine { grid-template-columns: repeat(2, 1fr); } }

.sp-maillon {
  position: relative;
  padding: 14px 14px; border: 1px solid var(--n-bord); border-radius: 11px;
  background: rgba(17,26,37,.7);
}
/* La flèche entre deux maillons. Elle ne s'affiche pas après le
   dernier, ni en bout de ligne quand la grille se replie. */
.sp-maillon::after {
  content: ""; position: absolute; right: -13px; top: 50%;
  width: 8px; height: 8px; margin-top: -4px;
  border-top: 1px solid var(--n-bord); border-right: 1px solid var(--n-bord);
  transform: rotate(45deg);
}
.sp-maillon:last-child::after { display: none; }
@media (max-width: 1100px) { .sp-maillon:nth-child(3n)::after { display: none; } }
@media (max-width: 620px)  { .sp-maillon:nth-child(2n)::after { display: none; } }

.sp-maillon b {
  display: block; font-size: 25px; line-height: 1; letter-spacing: -.04em;
  font-variant-numeric: tabular-nums; color: var(--sp-tn, var(--n-tx));
}
.sp-maillon span { display: block; margin-top: 7px; font-size: 12px; color: var(--n-tx-2); line-height: 1.3; }
.sp-maillon small { display: block; margin-top: 4px; font-size: 10.5px; color: var(--n-tx-3); }

/* ── 31.10 CE QUI SE PASSE APRÈS LA SIGNATURE */
.sp-apres { margin-top: 20px; padding-top: 4px; }
.sp-projets { list-style: none; margin: 11px 0 0; padding: 0; }
.sp-projets li {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 0; border-bottom: 1px solid rgba(120,150,190,.09);
}
.sp-projets li:last-child { border-bottom: 0; }
.sp-lien {
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--n-cyan); font: 600 13.5px/1.4 inherit; letter-spacing: -.01em;
  text-align: left;
}
.sp-lien:hover { text-decoration: underline; }

/* La colonne de saisie de l' atelier. Sans cette règle elle marche
   quand même, mais une classe sans règle fait douter le prochain
   lecteur : soit elle sert, soit elle part. */
.sp-atelier-gauche { min-width: 0; }


/* =============================================================
   32. L'APPEL EN UN GESTE
   8 septembre 2026

   ⚠ CES CINQ BOUTONS SONT LA PIÈCE DONT TOUT SPIDER DÉPEND.

   Les cartes du matin, les leads qui dorment, les compteurs par
   commercial, la conversion par campagne : tout se calcule à
   partir de `prospect_interactions`. Si la trace n'est pas écrite,
   l'écran est un joli vide.

   Or enregistrer un appel demandait sept champs, quand le Google
   Sheet de l'équipe en demande un seul. Sur trente appels dans une
   journée, le formulaire perd — et il perdait, tous les jours,
   depuis des mois.

   D'où leur taille : ils sont volontairement plus gros que les
   boutons ordinaires de l'OS. C'est le geste le plus fréquent de
   la journée d'un commercial ; il doit être le plus facile à
   viser, au doigt comme à la souris.
   ============================================================= */

.sp-appel {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-bottom: 4px;
}
.sp-appel .btn {
  flex: 1 1 auto; min-width: 128px; min-height: 46px;
  font-size: 14px; font-weight: 600;
  border-color: var(--sp-ab, var(--n-bord));
  color: var(--sp-ac, var(--n-tx));
  background: color-mix(in srgb, var(--sp-ac, transparent) 8%, rgba(22,32,44,.9));
  transition: transform var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux);
}
.sp-appel .btn:hover:not(:disabled) {
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--sp-ac, var(--n-bord)) 70%, transparent);
}
.sp-appel .btn:disabled { opacity: .45; }

/* Une couleur par résultat, la même que celle de l'étape où il
   mène. Le commercial apprend la correspondance sans qu'on la lui
   explique : « Devis » est cyan ici et cyan dans le rail. */
.sp-b-injoignable   { --sp-ac: var(--n-tx-2);  --sp-ab: var(--n-bord); }
.sp-b-relance       { --sp-ac: var(--n-violet); --sp-ab: rgba(139,92,246,.4); }
.sp-b-rdv           { --sp-ac: var(--n-or);     --sp-ab: rgba(242,185,64,.42); }
.sp-b-devis         { --sp-ac: #7EEAFF;         --sp-ab: rgba(126,234,255,.4); }
.sp-b-pasintress    { --sp-ac: var(--n-tx-3);   --sp-ab: var(--n-bord); }

/* Le chemin long n'a pas disparu : il a cessé d'être obligatoire.
   Il reste à portée, en lien discret, pour les fois où la
   conversation a vraiment donné quelque chose. */
.sp-detailler {
  flex: 0 0 auto; padding: 0 6px;
  color: var(--n-tx-3); font-size: 12.5px; text-decoration: none;
  border-bottom: 1px solid transparent;
}
.sp-detailler:hover { color: var(--n-cyan); border-bottom-color: currentColor; }

@media (max-width: 560px) {
  .sp-appel .btn { flex: 1 1 46%; min-width: 0; }
  .sp-detailler { flex: 1 1 100%; padding-top: 4px; }
}


/* =============================================================
   33. « À FAIRE » — LA FILE DE CE QUI EST DÉJÀ PRÉPARÉ
   8 septembre 2026

   ⚠ CET ÉCRAN A REMPLACÉ UN TABLEAU DE BORD.

   La première version affichait « 3 leads dorment », « rien
   envoyé », « aucun projet ouvert ». La Direction : « 3awdty nafss
   l'erreur li kan 3andi ana — khassni solution machi problem ».
   Signaler un travail non fait ne le fait pas : ça le déplace sur
   celui qui lit l'écran.

   D'où la forme de ces cartes : le texte préparé occupe le centre,
   pas un chiffre rouge. Ce qu'on lit, c'est la réparation — le
   défaut n'est plus qu'une ligne de justification, en petit.
   ============================================================= */

.sp-intro-prep { margin: 0 0 16px; color: var(--n-tx-2); font-size: 13.5px; max-width: 76ch; }
.sp-intro-prep b { color: var(--n-tx); }

.sp-carte-action {
  margin-bottom: 10px; padding: 15px 17px;
  border: 1px solid var(--n-bord); border-left: 2px solid var(--sp-tn, var(--n-bord));
  border-radius: 12px; background: rgba(17,26,37,.7);
}

.sp-ca-tete { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.sp-ca-type {
  flex: none; padding: 4px 10px; border-radius: 6px;
  font-family: var(--f-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--sp-tn, var(--n-tx-2));
  border: 1px solid color-mix(in srgb, var(--sp-tn, var(--n-bord)) 60%, transparent);
}
.sp-ca-titre { flex: 1 1 220px; }
.sp-ca-titre b { display: block; font-size: 15.5px; letter-spacing: -.02em; }
.sp-ca-raison { display: block; margin-top: 2px; color: var(--n-tx-3); font-size: 12px; }
.sp-ca-qui { color: var(--n-tx-3); font-size: 12px; font-family: var(--f-mono); }

/* Le texte préparé. C'est lui le sujet de la carte : il prend la
   place, il se lit d'un coup, et il est modifiable sur place. */
.sp-ca-texte, .sp-ca-doc {
  margin-top: 12px; padding: 13px 15px; border-radius: 10px;
  font-size: 13px; line-height: 1.6; white-space: pre-wrap;
  color: var(--n-tx-2);
  background: rgba(255,255,255,.022); border: 1px solid rgba(120,150,190,.12);
}
.sp-ca-doc {
  color: #D3C6F5;
  background: rgba(139,92,246,.06); border-color: rgba(139,92,246,.22);
}
.sp-editable {
  outline: none; color: var(--n-tx);
  border-color: rgba(18,217,255,.5); background: rgba(18,217,255,.05);
}

.sp-ca-pied { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 12px; }
.sp-ca-plus { margin-left: auto; opacity: .7; }

/* ── CE QUI S'EST FAIT TOUT SEUL */
.sp-auto { list-style: none; margin: 0; padding: 0; }
.sp-auto li {
  margin-bottom: 10px; padding: 12px 14px 12px 15px;
  border-left: 2px solid rgba(36,217,129,.45); border-radius: 0 9px 9px 0;
  background: rgba(36,217,129,.035);
}
.sp-auto b { display: block; font-size: 14px; letter-spacing: -.015em; }
.sp-af-quoi { display: block; margin-top: 4px; color: var(--n-tx-2); font-size: 12.5px; line-height: 1.55; }

/* ── LA RÈGLE DE L'ÉTAPE SÉLECTIONNÉE

   Elle n'existe que pendant qu'on regarde cette étape. Une
   explication affichée en permanence n'est plus lue au bout de
   deux jours. */
.sp-regle-etape {
  margin: 12px 0 0; padding: 11px 14px; border-radius: 10px;
  border: 1px solid rgba(18,217,255,.24); border-left: 2px solid var(--n-cyan);
  background: rgba(18,217,255,.05); color: #9FE8FA;
  font-size: 12.5px; line-height: 1.55;
}
.sp-regle-etape::before {
  content: "Se déclenche tout seul — "; color: var(--n-tx-3);
}

/* Le bouton « Il a signé » une fois armé : il ne demande plus, il
   confirme. La couleur change pour que personne ne clique deux
   fois sans le voir. */
.sp-arme {
  border-color: rgba(36,217,129,.55) !important;
  background: rgba(36,217,129,.12) !important;
  color: #8FE9BC !important;
}

/* Ce qui reste derrière la file plafonnée. Discret, mais dit :
   une file qui cache son reste ferait croire que tout est fait. */
.sp-reste {
  margin: 14px 0 0; padding: 12px 15px; border-radius: 10px;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.02);
  color: var(--n-tx-3); font-size: 13px;
}
.sp-reste b { color: var(--n-tx); }

/* =============================================================
   34. LA MATINÉE, LE CANAL, ET CE QUI RÉPOND AU SURVOL
   8 septembre 2026

   Quatre demandes de la Direction, dans le même message :
   la répartition du matin, savoir où part le message, voir que
   deux fiches portent le même nom — et « ila w9aft b souris
   tkbar l'image bach tban l'info ou ay haja tkon clicable avec
   les pop up ou lights ».

   ⚠ LE SURVOL AJOUTE, IL NE DÉPLACE PAS. Une carte qui grandit
   au survol pousse ses voisines et fait sauter la file sous le
   curseur. Tout ce qui grossit ici le fait dans son propre plan
   — `transform`, jamais une largeur ni une marge — et rien ne
   dépend du survol pour être lisible : le tactile n'en a pas.
   ============================================================= */

/* ── LA RÉPARTITION DU MATIN ──────────────────────────────── */
.sp-filtre-actif {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; margin: 12px 0 0; padding: 10px 14px; border-radius: 10px;
  border: 1px solid rgba(242,185,64,.28); border-left: 2px solid var(--n-or, #F2B940);
  background: rgba(242,185,64,.05); color: #F4D89A; font-size: 12.5px;
}

.sp-reporte {
  margin: 14px 0 0; padding: 11px 15px; border-radius: 10px;
  border: 1px dashed var(--n-bord); color: var(--n-tx-3); font-size: 12.5px;
}
.sp-reporte b { color: var(--n-tx-2); }

/* ── OÙ PART LE MESSAGE ───────────────────────────────────

   Le bouton disait « Envoyer » sans jamais nommer le canal. Cette
   ligne le nomme, avec le numéro en clair, et se colore en rouge
   quand WhatsApp ne pourra pas le joindre — l'échec se lit AVANT
   le clic, pas après. */
.sp-ca-vers {
  display: inline-flex; align-items: baseline; gap: 3px;
  margin-right: auto; padding: 5px 10px; border-radius: 999px;
  border: 1px solid rgba(36,217,129,.3); background: rgba(36,217,129,.06);
  font-size: 11.5px; letter-spacing: .01em;
}
.sp-ca-vers b { color: #7BE3AE; font-weight: 700; }
.sp-ca-vers span { color: var(--n-tx-3); font-variant-numeric: tabular-nums; }
.sp-ca-vers-ko {
  border-color: rgba(255,107,107,.34); background: rgba(255,107,107,.07);
}
.sp-ca-vers-ko b { color: #FFA79C; }

/* ── LES FICHES QUI PORTENT LE MÊME NOM ───────────────────── */
.sp-ca-jumelles {
  margin: 0 0 10px; padding: 9px 13px; border-radius: 9px;
  border: 1px solid rgba(139,92,246,.24); background: rgba(139,92,246,.05);
  color: #CDBCF7; font-size: 12px; line-height: 1.55;
}
.sp-ca-jum-liste { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.sp-jum {
  padding: 4px 10px; border-radius: 999px; cursor: pointer;
  border: 1px solid rgba(139,92,246,.32); background: rgba(139,92,246,.08);
  color: #DDD1FF; font: inherit; font-size: 11.5px;
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}
.sp-jum:hover {
  transform: translateY(-1px);
  border-color: rgba(139,92,246,.6);
  box-shadow: 0 0 0 3px rgba(139,92,246,.12);
}

/* La carte reportée s'en va au lieu de disparaître : le geste se
   voit, donc il se comprend. */
.sp-ca-part {
  opacity: .25; transform: translateX(14px);
  transition: opacity .18s ease, transform .18s ease;
}

/* ── CE QUI RÉPOND AU SURVOL ──────────────────────────────── */
.sp-carte-action,
.sp-carte,
.sp-tuile,
.sp-maillon {
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.sp-carte-action:hover,
.sp-carte:hover {
  transform: translateY(-2px);
  border-color: rgba(120,150,190,.34);
  box-shadow: 0 22px 46px -30px #000, 0 0 0 1px rgba(255,255,255,.03);
}
.sp-tuile:hover,
.sp-maillon:hover {
  transform: translateY(-2px);
  box-shadow: 0 16px 34px -26px #000;
}

/* L'initiale d'un commercial grossit sous le curseur et s'allume
   à sa couleur : c'est la seule « image » de cet écran, et c'est
   elle qu'on cherche des yeux quand on parcourt l'équipe. */
.sp-rond { transition: transform .2s ease, box-shadow .2s ease; }
.sp-carte:hover .sp-rond {
  transform: scale(1.12);
  box-shadow: 0 0 0 4px rgba(139,92,246,.14), 0 0 26px rgba(139,92,246,.22);
}

/* Les lignes du pipeline : le survol éclaire la ligne entière,
   pour qu'on sache laquelle on va ouvrir avant de cliquer. */
.sp-table tbody tr { transition: background .15s ease, box-shadow .15s ease; }
.sp-table tbody tr:hover {
  background: rgba(255,255,255,.035);
  box-shadow: inset 2px 0 0 var(--n-cyan, #12D9FF);
}

/* ⚠ ET RIEN DE TOUT CELA POUR QUI A DEMANDÉ LE CALME.
   `prefers-reduced-motion` n'est pas une préférence esthétique :
   c'est une consigne médicale pour une partie des gens. */
@media (prefers-reduced-motion: reduce) {
  .sp-carte-action, .sp-carte, .sp-tuile, .sp-maillon,
  .sp-rond, .sp-jum, .sp-ca-part, .sp-table tbody tr {
    transition: none !important; transform: none !important;
  }
}

/* ── LA CARTE DU TABLEAU DE BORD S'OUVRE EN ENTIER ─────────

   « spider makadkholch lia mn deashbord » : les deux liens de la
   carte pointaient vers des écrans retirés du menu. Ils sont
   corrigés, et la carte elle-même devient une porte.

   ⚠ LE LIEN DE FOND PASSE SOUS LES LIENS D'ACTION. `.universe-card
   > *` pose z-index 2 sur tous les enfants ; sans les deux règles
   qui suivent, le fond recouvrirait les boutons et les trois
   destinations n'en feraient plus qu'une. */
.universe-fond {
  position: absolute; inset: 0; z-index: 1;
  border-radius: inherit; text-decoration: none;
}
.universe-card .universe-actions { z-index: 3; }
.universe-ouvrable { cursor: pointer; }
.universe-fond:focus-visible {
  outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: -3px;
}

/* ── LA FICHE : DEUX CANAUX ET UN RESPONSABLE ─────────────── */
.sp-fiche-canaux { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0 4px; }
.sp-canal {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 14px; border-radius: 10px; text-decoration: none;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.022);
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease;
}
.sp-canal b { font-size: 13px; letter-spacing: -.01em; color: var(--n-tx); }
.sp-canal span { font-size: 11.5px; color: var(--n-tx-3); font-variant-numeric: tabular-nums; }
.sp-canal-tel:hover {
  transform: translateY(-2px); border-color: rgba(18,217,255,.5);
  box-shadow: 0 0 0 3px rgba(18,217,255,.1);
}
.sp-canal-wa b { color: #7BE3AE; }
.sp-canal-wa:hover {
  transform: translateY(-2px); border-color: rgba(36,217,129,.5);
  box-shadow: 0 0 0 3px rgba(36,217,129,.1);
}
/* Un canal impossible n'est pas un bouton : il ne réagit pas au
   survol, parce qu'il n'y a rien à cliquer. */
.sp-canal-ko { border-style: dashed; opacity: .72; cursor: default; }
.sp-canal-ko b { color: #FFA79C; }

.sp-fiche-confie {
  display: flex; align-items: center; gap: 10px; margin: 12px 0 2px;
  font-size: 12.5px; color: var(--n-tx-3);
}
.sp-confie {
  flex: 1; min-width: 0; padding: 8px 11px; border-radius: 9px;
  border: 1px solid var(--n-bord); background: #0B141E; color: var(--n-tx);
  font: inherit; font-size: 12.5px;
}
.sp-confie:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: 1px; }
.sp-confie:disabled { opacity: .55; }

@media (prefers-reduced-motion: reduce) {
  .sp-canal { transition: none !important; transform: none !important; }
}

/* =============================================================
   35. FAIRE SORTIR LE DOCUMENT
   8 septembre 2026

   La douleur d'origine, dite par la Direction : « les mini
   présentations li kanw3edhom bihom makanssiftomch » — les
   présentations promises ne partent jamais.

   Une feuille qui se dessine à l'écran et s'arrête là ne règle
   rien : Word le faisait déjà. Ce qui manquait, ce sont les deux
   gestes d'après — l'avoir en fichier, et l'envoyer en laissant
   une trace sur la fiche.

   ⚠ AUCUNE BIBLIOTHÈQUE PDF. La feuille EXISTE DÉJÀ, mise en
   page, dans `.sp-feuille`. Embarquer un générateur PDF
   reviendrait à la redessiner une seconde fois, dans un langage
   qui ne connaît ni le catalogue ni la marque. L'impression du
   navigateur sait fabriquer le fichier ; il suffit de lui donner
   la feuille SEULE.
   ============================================================= */
.sp-sortie { margin-top: 16px; align-items: center; }
.sp-sortie-vers {
  margin-left: auto; color: var(--n-tx-3); font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}
.sp-sortie-manque { margin: 14px 0 0; }

/* ── LA FEUILLE SEULE, À L'IMPRESSION

   `visibility` plutôt que `display` : masquer par `display` ferait
   s'effondrer la mise en page autour de la feuille, et elle
   sortirait décalée. `visibility: hidden` garde la place, et la
   feuille remonte en haut de la page imprimée.

   ⚠ RIEN N'EST MASQUÉ À L'INTÉRIEUR DE LA FEUILLE, y compris les
   mentions « le besoin n'est pas encore écrit ». Cacher un manque
   à l'impression laisserait partir un document troué sans que
   personne ne le voie — c'est le bouton qui refuse d'imprimer
   tant qu'il manque quelque chose, pas la feuille qui triche. */
@media print {
  @page { margin: 14mm; }
  html, body { background: #FFF !important; }
  body * { visibility: hidden !important; }
  .sp-feuille, .sp-feuille * { visibility: visible !important; }
  .sp-feuille {
    position: absolute; left: 0; top: 0; width: 100%;
    padding: 0; border-radius: 0; box-shadow: none;
    background: #FFF; color: #000;
  }
  .sp-feuille h5 { color: #4C1D95; }
  .sp-pied { color: #4B5563; }
}

/* Les deux portes du document, depuis n'importe quelle fiche.
   Retaper un nom déjà présent dans la fiche est exactement le
   travail que cet écran existe pour supprimer. */
.sp-fiche-doc { display: flex; gap: 8px; flex-wrap: wrap; margin: 14px 0 2px; }

/* =============================================================
   36. CERCLE 25 — LE MÊME ÉCRAN, L'AUTRE MOITIÉ DU STUDIO
   9 septembre 2026

   La Direction : « aji bach nçado cercle b7al spider ».

   ⚠ CET ÉCRAN RÉUTILISE LES CLASSES `.sp-*`, ET C'EST VOULU.
   Elles ne sont plus le vocabulaire de SPIDER : ce sont celles de
   la file d'actions de l'OS — tuiles, cartes, chaîne, tableau,
   panneaux. Les recopier sous un préfixe `c25-` aurait donné
   soixante règles jumelles qui divergent au premier ajustement,
   et deux écrans qui se ressemblent de moins en moins alors qu'on
   les a demandés identiques.

   Ne sont définies ici que les DEUX choses qui diffèrent
   réellement : cinq étapes au lieu de huit, et les couleurs du
   circuit de production.
   ============================================================= */
.c25-rail { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
@media (max-width: 1100px) { .c25-rail { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 560px)  { .c25-rail { grid-template-columns: repeat(2, 1fr); } }

/* ⚠ LES VARIANTES `-tx`, PAS LES COULEURS BRUTES.

   `--c-preprod` (#8B5CF6) et `--c-production` (#3B82F6) tombent
   sous 4,5:1 sur le fond sombre : lisibles en aplat, pas en
   texte. Les jetons `-tx` existent pour ça, avec le contraste
   déjà corrigé dans tokens.css. Prendre la couleur brute ici
   aurait rendu deux étapes sur cinq difficiles à lire — celles
   du milieu du circuit, justement là où les projets s'arrêtent. */
.c25-e-commercial     { --sp-c: var(--c-commercial-tx); }
.c25-e-preproduction  { --sp-c: var(--c-preprod-tx); }
.c25-e-production     { --sp-c: var(--c-production-tx); }
.c25-e-postproduction { --sp-c: var(--c-postprod-tx); }
.c25-e-livraison      { --sp-c: var(--c-livraison-tx); }

/* Le rang de liens vers les listes par étape. Discret : on ne
   remet pas neuf entrées de menu en bas de l'écran. */
.c25-listes {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
  margin: 14px 0 0; color: var(--n-tx-3); font-size: 12px;
}

/* =============================================================
   37. LA MISSION DU JOUR — UNE FICHE À LA FOIS
   9 septembre 2026

   Direction : « ma3andoch l7a9 ydouz l next client ila makamlach
   m3ah ». L'écran ne montre donc qu'une carte, et la file entière
   se lit d'un coup d'œil sur une jauge : on doit voir la fin,
   sinon on n'entre pas dedans.
   ============================================================= */
.sp-mission-jauge {
  display: flex; gap: 3px; flex-wrap: wrap; margin: 0 0 14px;
}
.sp-mission-jauge i {
  flex: 1 1 6px; min-width: 5px; height: 6px; border-radius: 3px;
  background: rgba(120,150,190,.16);
}
.sp-mission-jauge i.fait { background: var(--n-vert); }
.sp-mission-jauge i.ici  { background: var(--n-or); box-shadow: 0 0 10px rgba(242,185,64,.5); }

/* La carte de mission est seule à l'écran : elle peut respirer. */
.sp-mission { margin-top: 0; }

/* Ce qui s'est déjà dit avec lui. Trois lignes, en une seule
   rangée : c'est un rappel avant de décrocher, pas un dossier. */
.sp-mission-hist { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.sp-mission-trace {
  padding: 4px 10px; border-radius: 999px; font-size: 11.5px;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.02);
  color: var(--n-tx-2);
}

/* ── PASSER COÛTE UNE PHRASE

   Le champ est large et le bouton discret : l'ordre de lecture
   dit ce qu'on attend. Écrire d'abord, passer ensuite. */
.sp-mission-passer {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--n-bord);
}
.sp-mission-motif {
  flex: 1 1 320px; min-width: 0; padding: 9px 12px; border-radius: 9px;
  border: 1px solid var(--n-bord); background: #0B141E; color: var(--n-tx);
  font: inherit; font-size: 12.5px;
}
.sp-mission-motif::placeholder { color: var(--n-tx-3); }
.sp-mission-motif:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: 1px; }

/* =============================================================
   38. CERCLE 25 — LE DOSSIER, ET SON ESPACE
   9 septembre 2026

   La Direction : « badel lia had cercle 25 b hada li darty », et
   « mhm ykon zwin ou wa3r bzaf, y3tina experience f khedma ou f
   visuel ».

   ⚠ LES COUVERTURES SONT DE VRAIES IMAGES. `affiche()` rend la
   couverture du projet si elle existe, et en dessine une sinon —
   l'OS savait déjà le faire, on ne le refait pas. Ce qui est
   ajouté ici, c'est le TRAITEMENT : un cadre qui recadre en 16:9
   ou en 9:16, un voile bas pour que le texte tienne sur n'importe
   quelle image, et un agrandissement au survol.
   ============================================================= */

/* ── LE CADRE CINÉMA ──────────────────────────────────────── */
.c25-cadre {
  position: relative; display: block; overflow: hidden;
  border-radius: 12px; aspect-ratio: 16 / 9; isolation: isolate;
  background: linear-gradient(160deg, #16202C, #070C12);
}
.c25-cadre-9  { aspect-ratio: 9 / 16; }
.c25-cadre-43 { aspect-ratio: 4 / 3; }
.c25-cadre-mini { width: 132px; flex: none; }
.c25-cadre img,
.c25-cadre .affiche {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
  transition: transform 420ms var(--m-doux, cubic-bezier(.22,.61,.36,1)),
              filter 420ms var(--m-doux, cubic-bezier(.22,.61,.36,1));
}
/* Le voile bas : sans lui, le texte se pose sur n'importe quoi. */
.c25-voile {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: linear-gradient(to top, rgba(4,7,11,.94) 0%, rgba(4,7,11,.5) 34%, transparent 66%),
              radial-gradient(120% 100% at 50% 45%, transparent 42%, rgba(0,0,0,.42));
}
.c25-etape-puce, .c25-code {
  position: absolute; z-index: 3; top: 10px; left: 11px;
  padding: 4px 9px; border-radius: 7px;
  font-family: var(--f-mono); font-size: 9.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.94);
  background: rgba(5,8,13,.55); backdrop-filter: blur(7px);
  border: 1px solid rgba(255,255,255,.14);
}
.c25-retard {
  position: absolute; z-index: 3; top: 10px; right: 11px;
  padding: 4px 9px; border-radius: 7px;
  font-family: var(--f-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .1em;
  color: #FFC9C4; background: rgba(255,77,85,.22); backdrop-filter: blur(7px);
  border: 1px solid rgba(255,77,85,.45);
}
.c25-bande {
  position: absolute; z-index: 3; left: 0; right: 0; bottom: 0; height: 3px;
  background: var(--dep, var(--n-bord));
}

/* ── LE MUR DES DOSSIERS ──────────────────────────────────── */
.c25-mur { display: grid; grid-template-columns: repeat(auto-fill, minmax(228px, 1fr)); gap: 14px; }
.c25-mur-petit { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 11px; }
.c25-carte {
  display: block; width: 100%; padding: 0; text-align: left; color: inherit; font: inherit;
  cursor: pointer; overflow: hidden; border-radius: 14px;
  border: 1px solid var(--n-bord); background: rgba(17,26,37,.7);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  transition: transform .22s var(--m-doux), border-color .22s var(--m-doux), box-shadow .22s var(--m-doux);
}
.c25-carte:hover { transform: translateY(-4px); border-color: var(--n-bord-fort); box-shadow: 0 30px 56px -32px #000; }
/* ⚠ L'IMAGE GRANDIT, LA CARTE NE BOUGE PAS. Un `scale` sur la
   carte ferait sauter la grille entière au survol ; sur l'image,
   il ne déborde pas du cadre, qui est en `overflow:hidden`. */
.c25-carte:hover .c25-cadre img { transform: scale(1.07); filter: saturate(1.12) brightness(1.06); }
.c25-carte:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.c25-carte-bas { display: block; padding: 12px 14px; }
.c25-carte-bas b { display: block; font-size: 14.5px; font-weight: 600; letter-spacing: -.015em; }
.c25-carte-cli { display: block; margin-top: 3px; font-size: 12.5px; color: var(--n-tx-2); }
.c25-carte-qui { display: block; margin-top: 7px; font-family: var(--f-mono); font-size: 10.5px; color: var(--n-tx-3); }

/* ── LE FIL, L'EN-TÊTE, LES REPÈRES ───────────────────────── */
.c25-fil {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin-bottom: 14px;
  font-family: var(--f-mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--n-tx-3);
}
.c25-fil-l {
  padding: 5px 10px; border-radius: 8px; cursor: pointer; font: inherit; color: inherit;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.02);
  transition: color var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux);
}
.c25-fil-l:hover { color: var(--n-tx); border-color: var(--n-bord-fort); }
.c25-fil i { font-style: normal; opacity: .5; }
.c25-fil b { color: var(--n-or); }

.c25-dossier { position: relative; padding-bottom: 22px; margin-bottom: 16px; }
.c25-dossier::after {
  content: ""; position: absolute; left: 0; bottom: 0; width: 132px; height: 2px;
  background: linear-gradient(90deg, var(--n-or), transparent);
}
.c25-kick {
  margin: 0 0 6px; font-family: var(--f-mono); font-size: 11px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--n-or);
}
.c25-dossier h1 {
  margin: 0 0 12px; font-size: clamp(30px, 4.6vw, 42px); font-weight: 800;
  letter-spacing: -.04em; line-height: 1.03;
}
.c25-faits { display: flex; gap: 10px 22px; flex-wrap: wrap; align-items: center; font-size: 13.5px; color: var(--n-tx-2); }
.c25-faits b { color: var(--n-tx); font-weight: 600; }
.c25-faits i { font-style: normal; }
.c25-selecteur { margin-left: auto; }
.c25-select {
  padding: 9px 13px; border-radius: 10px; border: 1px solid var(--n-bord);
  background: #070C13; color: var(--n-tx); font: 600 13px var(--f-body); max-width: 320px;
}
.c25-select:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

.c25-reperes { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 14px; }
.c25-repere {
  display: flex; align-items: center; gap: 9px; padding: 9px 13px; border-radius: 11px;
  border: 1px solid var(--n-bord); border-left: 2px solid var(--tn, var(--n-bord));
  background: rgba(255,255,255,.022);
}
.c25-repere s {
  text-decoration: none; font-family: var(--f-mono); font-size: 9px; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-3);
}
.c25-repere b { font-size: 13.5px; font-weight: 600; letter-spacing: -.015em; color: var(--tn, var(--n-tx)); }
.c25-r-cyan { --tn: var(--n-cyan); } .c25-r-rouge { --tn: var(--n-rouge); }
.c25-r-or { --tn: var(--n-or); } .c25-r-vert { --tn: var(--n-vert); }

/* ── LA CHAÎNE ────────────────────────────────────────────── */
.c25-chaine { display: grid; grid-template-columns: repeat(5, 1fr); margin: 0 0 14px; }
@media (max-width: 860px) { .c25-chaine { grid-template-columns: repeat(2, 1fr); gap: 8px; } }
.c25-maillon {
  position: relative; text-align: left; cursor: pointer; font: inherit; color: inherit;
  padding: 15px 15px 15px 19px; border: 1px solid var(--n-bord); background: rgba(13,20,29,.7);
  transition: background var(--m-court) var(--m-doux);
}
.c25-maillon + .c25-maillon { border-left: 0; }
.c25-chaine .c25-maillon:first-child { border-radius: 14px 0 0 14px; }
.c25-chaine .c25-maillon:last-child { border-radius: 0 14px 14px 0; }
@media (max-width: 860px) {
  .c25-maillon,
  .c25-chaine .c25-maillon:first-child,
  .c25-chaine .c25-maillon:last-child { border-radius: 12px; border-left: 1px solid var(--n-bord); }
}
.c25-maillon:hover { background: rgba(20,30,43,.8); }
.c25-maillon:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: -2px; z-index: 3; }
.c25-maillon::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--dep, rgba(120,150,190,.18));
}
.c25-maillon .c25-num { font-family: var(--f-mono); font-size: 10px; font-weight: 700; letter-spacing: .14em; color: var(--n-tx-3); }
.c25-maillon .c25-mnom { display: block; margin-top: 7px; font-size: 14.5px; font-weight: 600; letter-spacing: -.015em; }
.c25-maillon .c25-etat { display: block; margin-top: 5px; font-size: 11.5px; color: var(--n-tx-3); }
.c25-m-fait .c25-num, .c25-m-fait .c25-etat { color: var(--n-vert); }
.c25-m-ici { background: rgba(242,185,64,.07); box-shadow: inset 0 1px 0 rgba(255,255,255,.05); }
.c25-m-ici .c25-num, .c25-m-ici .c25-etat { color: var(--n-or); }
.c25-m-ici .c25-mnom { color: #fff; }
/* Un seul élément respire à l'écran : celui qui dit « c'est ici ». */
.c25-m-ici::before { animation: os25-souffle 6s ease-in-out infinite; }
.c25-m-suite { opacity: .5; }
.c25-maillon[aria-selected="true"] {
  box-shadow: inset 0 0 0 1px rgba(139,92,246,.4);
  background: linear-gradient(180deg, rgba(42,29,77,.5), rgba(21,28,41,.5)); z-index: 2;
}

/* ── LA PORTE ─────────────────────────────────────────────── */
.c25-porte {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 17px 20px;
  border-radius: 14px; border: 1px solid var(--n-bord); background: rgba(13,20,29,.7); margin-bottom: 12px;
}
.c25-porte.prete { border-color: rgba(36,217,129,.34); background: rgba(36,217,129,.05); }
.c25-porte-txt { flex: 1; min-width: 240px; font-size: 13.5px; line-height: 1.6; color: var(--n-tx-2); }
.c25-porte-txt b { color: var(--n-tx); }
.c25-porte.prete .c25-porte-txt b { color: #8FE9BC; }

/* ── LES CHAMPS D'UNE ÉTAPE ───────────────────────────────── */
.c25-champs { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
.c25-champ {
  margin: 0; padding: 12px 14px; border-radius: 11px; border: 1px solid var(--n-bord);
  border-left: 2px solid rgba(36,217,129,.4); background: rgba(255,255,255,.022);
}
.c25-champ.c25-vide { border-left-color: var(--n-rouge); background: rgba(255,77,85,.04); }
.c25-champ dt {
  font-family: var(--f-mono); font-size: 9px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--n-tx-3);
}
.c25-champ dd { margin: 6px 0 0; font-size: 13px; line-height: 1.5; }
.c25-champ.c25-vide dd { color: #FFA9AE; font-style: italic; }

/* ── LE TABLEAU DE PRÉ-PRODUCTION ─────────────────────────── */
.c25-board { display: grid; grid-template-columns: repeat(auto-fit, minmax(244px, 1fr)); gap: 13px; align-items: start; }
.c25-colonne { border: 1px solid var(--n-bord); border-radius: 14px; background: rgba(9,14,21,.55); padding: 12px; }
.c25-col-tete { display: flex; align-items: center; gap: 9px; padding: 4px 6px 12px; }
.c25-col-tete b { font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--n-tx-2); }
.c25-col-pt { width: 7px; height: 7px; border-radius: 50%; background: var(--tn, var(--n-tx-3)); flex: none; }
.c25-col-n { margin-left: auto; font-family: var(--f-mono); font-size: 11px; color: var(--n-tx-3); }
.c25-c-violet { --tn: var(--n-violet); } .c25-c-cyan { --tn: var(--n-cyan); }
.c25-c-or { --tn: var(--n-or); } .c25-c-vert { --tn: var(--n-vert); }
.c25-fiche {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  border: 1px solid var(--n-bord); border-left: 2px solid var(--tn, var(--n-bord)); border-radius: 12px;
  background: rgba(17,26,37,.75); box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  padding: 13px 14px; margin-bottom: 9px;
  transition: transform .22s var(--m-doux), border-color .22s var(--m-doux), box-shadow .22s var(--m-doux);
}
.c25-fiche:hover { transform: translateY(-2px); border-color: var(--n-bord-fort); box-shadow: 0 20px 40px -30px #000; }
.c25-fiche:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.c25-fiche-vide { border-left-color: var(--n-rouge); }
.c25-fiche-tete { display: flex; align-items: center; gap: 9px; margin-bottom: 9px; }
.c25-fiche-tete b { font-size: 14px; font-weight: 600; letter-spacing: -.015em; flex: 1; }
.c25-p-ok { --sp-c: var(--n-vert); } .c25-p-vide { --sp-c: var(--n-rouge); }
.c25-doc { border-radius: 9px; padding: 11px 12px; background: rgba(255,255,255,.022); border: 1px solid rgba(120,150,190,.1); }
.c25-doc i { display: block; height: 5px; border-radius: 3px; background: rgba(135,146,165,.26); margin-bottom: 6px; }
.c25-doc i:nth-child(2) { width: 92%; }
.c25-doc i:nth-child(3) { width: 78%; }
.c25-doc i:last-child { margin-bottom: 0; width: 54%; }
.c25-doc-vide i { background: rgba(255,77,85,.16); }
.c25-doc-txt { margin: 9px 0 0; font-size: 12.5px; color: var(--n-tx-2); line-height: 1.55; }

/* ── LES VIDÉOS ───────────────────────────────────────────── */
.c25-videos { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 13px; }
.c25-video {
  display: block; width: 100%; padding: 0; text-align: left; color: inherit; font: inherit; cursor: pointer;
  border: 1px solid var(--n-bord); border-radius: 13px; overflow: hidden; background: rgba(17,26,37,.7);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  transition: transform .22s var(--m-doux), border-color .22s var(--m-doux), box-shadow .22s var(--m-doux);
}
.c25-video:hover { transform: translateY(-4px); border-color: var(--n-bord-fort); box-shadow: 0 28px 52px -30px #000; }
.c25-video:hover .c25-cadre img { transform: scale(1.07); filter: saturate(1.12) brightness(1.06); }
.c25-video:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.c25-video-bas { display: block; padding: 11px 13px; }
.c25-video-bas b { display: block; font-size: 13.5px; font-weight: 600; letter-spacing: -.015em; }
.c25-video-meta { display: block; margin-top: 6px; font-family: var(--f-mono); font-size: 10.5px; color: var(--n-tx-3); }

.c25-valider {
  display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 16px; align-items: start;
  border: 1px solid var(--n-bord); border-left: 2px solid var(--n-or); border-radius: 13px;
  background: rgba(17,26,37,.7); padding: 15px; margin-bottom: 11px;
}
@media (max-width: 620px) { .c25-valider { grid-template-columns: 1fr; } }
.c25-valider h3 { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -.025em; }
.c25-valider-meta { margin: 5px 0 12px; font-family: var(--f-mono); font-size: 10.5px; color: var(--n-tx-3); }
.c25-mot {
  padding: 12px 15px; border-radius: 11px; margin-bottom: 12px; border: 1px solid rgba(120,150,190,.12);
  background: rgba(255,255,255,.022); font-size: 13.5px; color: var(--n-tx-2); line-height: 1.6;
}
.c25-motifs { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 12px; }
.c25-motifs[hidden] { display: none; }
.c25-motif {
  padding: 7px 13px; border-radius: 999px; cursor: pointer; border: 1px solid var(--n-bord);
  background: transparent; color: var(--n-tx-2); font: 500 12.5px/1 var(--f-body);
  transition: border-color var(--m-court) var(--m-doux), color var(--m-court) var(--m-doux),
              background var(--m-court) var(--m-doux);
}
.c25-motif:hover { border-color: var(--n-bord-fort); color: var(--n-tx); }
.c25-motif[aria-pressed="true"] { border-color: rgba(255,77,85,.5); background: rgba(255,77,85,.12); color: #FFA9AE; }

/* ══════════ L'ESPACE ══════════ */
.c25-outils {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center; padding: 12px 14px;
  border: 1px solid var(--n-bord); border-radius: 14px; background: rgba(12,19,28,.8); margin-bottom: 12px;
}
.c25-outil {
  display: inline-flex; align-items: center; gap: 8px; padding: 9px 14px; border-radius: 10px;
  cursor: pointer; border: 1px solid var(--n-bord); background: var(--n-surface-h); color: var(--n-tx-2);
  font: 600 12.5px/1 var(--f-body);
  transition: border-color var(--m-court) var(--m-doux), color var(--m-court) var(--m-doux),
              background var(--m-court) var(--m-doux);
}
.c25-outil:hover { border-color: var(--n-bord-fort); color: var(--n-tx); background: rgba(255,255,255,.045); }
.c25-outil:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.c25-outil s { width: 9px; height: 9px; border-radius: 2px; background: var(--tn, var(--n-tx-3)); flex: none; text-decoration: none; }
.c25-o-or { --tn: var(--n-or); } .c25-o-cyan { --tn: var(--n-cyan); }
.c25-o-violet { --tn: var(--n-violet); } .c25-o-vert { --tn: var(--n-vert); }
.c25-outils-qui { margin-left: auto; font-family: var(--f-mono); font-size: 11px; color: var(--n-tx-3); }

.c25-legende { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; margin: 0 0 12px; font-size: 12px; color: var(--n-tx-3); }
.c25-legende span { display: inline-flex; align-items: center; gap: 7px; }
.c25-legende s { width: 9px; height: 9px; border-radius: 3px; text-decoration: none; flex: none; }
.c25-lg-os { background: rgba(18,217,255,.55); }
.c25-lg-main { background: rgba(242,185,64,.55); }

/* ⚠ LE MUR VIT DANS UNE FENÊTRE, ET C'EST CE QUI LE REND
   UTILISABLE SUR UN TÉLÉPHONE. Des objets posés à des
   coordonnées fixes dans une boîte en `overflow:hidden` sont hors
   de portée dès que l'écran est plus étroit qu'eux. Ici on
   déplace le mur au doigt et on le met à l'échelle : rien n'est
   inatteignable. */
.c25-toile {
  position: relative; height: min(70vh, 700px); overflow: hidden; touch-action: none; cursor: grab;
  border: 1px solid var(--n-bord); border-radius: 16px;
  background-color: #070C12;
  background-image: radial-gradient(rgba(120,150,190,.16) 1px, transparent 1px);
  background-size: calc(26px * var(--z, 1)) calc(26px * var(--z, 1));
  background-position: var(--px, 0px) var(--py, 0px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
}
.c25-toile.pan { cursor: grabbing; }
.c25-monde {
  position: absolute; left: 0; top: 0; width: 1120px; height: 760px; transform-origin: 0 0;
  transform: translate3d(var(--px, 0px), var(--py, 0px), 0) scale(var(--z, 1));
}
.c25-liens { position: absolute; left: 0; top: 0; width: 1120px; height: 760px; z-index: 1; pointer-events: none; }
.c25-lien { fill: none; stroke: rgba(120,150,190,.4); stroke-width: 1.5; stroke-dasharray: 6 7; }
.c25-zoom {
  position: absolute; right: 12px; bottom: 12px; z-index: 20; display: flex; gap: 6px;
  padding: 6px; border-radius: 12px; border: 1px solid var(--n-bord);
  background: rgba(8,13,20,.9); backdrop-filter: blur(8px);
}
.c25-zoom button {
  width: 34px; height: 34px; border-radius: 8px; border: 1px solid var(--n-bord);
  background: var(--n-surface-h); color: var(--n-tx); font: 700 15px/1 var(--f-body);
  cursor: pointer; display: grid; place-items: center;
}
.c25-zoom button.large { width: auto; padding: 0 12px; font-size: 11.5px; font-weight: 600; }
.c25-zoom button:hover { border-color: var(--n-bord-fort); background: rgba(255,255,255,.05); }
.c25-zoom button:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

.c25-objet {
  position: absolute; left: 0; top: 0; z-index: 2; cursor: grab; touch-action: none;
  border-radius: 12px; transform: translate3d(var(--x, 0px), var(--y, 0px), 0);
  transition: box-shadow var(--m-court) var(--m-doux);
}
.c25-objet:active { cursor: grabbing; }
.c25-objet.tenu { z-index: 9; box-shadow: 0 30px 60px -24px #000, 0 0 0 1px rgba(242,185,64,.45); }
.c25-objet:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 3px; }

/* La note : elle est de quelqu'un, et elle le dit. */
.c25-t-note {
  width: 190px; padding: 14px 15px 12px;
  background: linear-gradient(165deg, rgba(242,185,64,.22), rgba(242,185,64,.09));
  border: 1px solid rgba(242,185,64,.34); box-shadow: 0 18px 34px -22px #000;
}
.c25-t-note p { margin: 0; font-size: 13.5px; line-height: 1.5; color: #FBE7B8; }
.c25-t-photo { width: 178px; overflow: hidden; border: 1px solid var(--n-bord-fort); box-shadow: 0 20px 38px -24px #000; background: #070C12; }
.c25-t-doc {
  width: 200px; padding: 13px 14px; background: rgba(17,26,37,.94);
  border: 1px solid var(--n-bord); border-left: 2px solid var(--n-violet); box-shadow: 0 20px 38px -24px #000;
}
.c25-t-doc b { display: block; font-size: 13px; font-weight: 600; letter-spacing: -.01em; margin-bottom: 9px; }
.c25-t-croquis { width: 230px; padding: 12px; background: rgba(9,14,21,.94); border: 1px solid var(--n-bord); box-shadow: 0 20px 38px -24px #000; }
.c25-t-croquis svg { display: block; width: 100%; height: auto; }
.c25-sig { display: block; margin-top: 9px; font-family: var(--f-mono); font-size: 9.5px; color: var(--n-tx-3); }
.c25-t-note .c25-sig { color: rgba(242,185,64,.75); }
.c25-lg { display: block; padding: 8px 10px; font-family: var(--f-mono); font-size: 9.5px; color: var(--n-tx-3); }
.c25-t-croquis .c25-lg { padding: 9px 0 0; font-size: 11.5px; color: #9FE8B8; }

/* D'où vient cet objet — la question qu'on se pose devant un mur
   partagé, et à laquelle plus personne ne peut répondre après
   coup si on ne l'écrit pas au moment où on le pose. */
.c25-src {
  position: absolute; top: -7px; left: 10px; z-index: 5; padding: 2px 7px; border-radius: 6px;
  font-family: var(--f-mono); font-size: 8px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; background: #0B1119; border: 1px solid var(--tn); color: var(--tn);
}
.c25-src-os { --tn: #7EEAFF; }
.c25-src-main { --tn: #F4D89A; }

.c25-aide { margin: 12px 0 0; font-size: 12.5px; color: var(--n-tx-3); line-height: 1.65; max-width: 82ch; }
.c25-aide b { color: var(--n-tx-2); }

@media (prefers-reduced-motion: reduce) {
  .c25-carte, .c25-video, .c25-fiche, .c25-cadre img, .c25-objet, .c25-maillon {
    transition: none !important; animation: none !important;
  }
  .c25-carte:hover, .c25-video:hover, .c25-fiche:hover { transform: none; }
  .c25-carte:hover .c25-cadre img, .c25-video:hover .c25-cadre img { transform: none; }
}

/* =============================================================
   39. CERCLE 25 — LA LUMIÈRE ET LE MOUVEMENT
   9 septembre 2026

   La Direction : « design ou l UIX ou animation ou les pop up ou
   les effects light ou les flou ou les minuature cinematique mhm
   ykooon zwin ou waaa3r bzfff. Y3tina experience f khedma ou f
   visuel. »

   ── LA RÈGLE QUI TIENT TOUTE CETTE SECTION

   Une animation coûte de l'attention. Trois éléments qui bougent
   en même temps ne se lisent plus : ils se concurrencent, et la
   personne ne sait plus où regarder. Donc UNE SEULE chose bouge
   à la fois dans un même champ de vision, et chaque mouvement
   dit quelque chose de vrai :

     · l'ARRIVÉE en cascade dit l'ordre — les dossiers urgents
       sont en tête de grille, ils entrent en premier ;
     · le FLOU qui se lève dit que l'image finit d'arriver ;
     · le BALAYAGE de lumière au survol dit « celle-ci, tu la
       regardes » ;
     · le SOUFFLE sur l'étape en cours dit « c'est ici », et rien
       d'autre ne respire à l'écran.

   Ce qui n'est PAS ici : pas de rebond sur les cartes (une grille
   qui rebondit se lit comme une erreur), pas de rotation, pas de
   dégradé animé en fond. Ces effets-là se remarquent la première
   fois et fatiguent la centième.

   ── ⚠ LE COÛT, ET POURQUOI ON NE L'OUBLIE PAS ICI

   Le mur porte jusqu'à vingt-trois couvertures, chacune une vraie
   image. Animer un flou sur vingt-trois images en même temps fait
   tomber un téléphone à dix images par seconde.

   Deux garde-fous : le décalage est PLAFONNÉ — au-delà de la
   quinzième carte tout le monde entre ensemble, sinon la dernière
   arriverait une seconde et demie après la première — et le flou
   ne dure que le temps de l'entrée, après quoi la propriété
   revient à sa valeur par défaut et ne coûte plus rien. On
   n'anime jamais un flou en boucle.
   ============================================================= */

/* ── L'ARRIVÉE ────────────────────────────────────────────────
   Monte, se met au net, s'installe.

   ⚠ `backwards`, ET SURTOUT PAS `both`. La différence a l'air
   d'un détail ; elle casse deux choses.

   Une animation gagne contre une règle ordinaire dans la cascade.
   Avec `both`, l'image finale de la séquence — `transform: none`
   — reste appliquée POUR TOUJOURS après la fin. Donc :

     · `.c25-carte:hover { transform: translateY(-4px) }` ne
       ferait plus rien : la carte ne se soulèverait plus jamais
       au survol, une fois son entrée terminée ;
     · pire, un objet de l'Espace est POSITIONNÉ par son
       `transform: translate3d(var(--x), var(--y), 0)`. Un
       `transform: none` figé dessus empilerait les sept objets
       dans le coin haut-gauche du mur.

   `backwards` applique la première image pendant le délai — ce
   qui évite le clignotement que `both` était censé régler — puis
   rend l'élément à ses propres règles dès la fin. Et c'est pour
   la même raison que les objets de l'Espace ont leur propre
   séquence, `c25-poser`, qui ne touche PAS au `transform`. */
@keyframes c25-lever {
  from { opacity: 0; transform: translate3d(0, 18px, 0) scale(.984); filter: blur(7px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
/* Pour l'Espace : opacité et netteté seulement. Le placement
   des objets passe par `transform`, on n'y touche pas. */
@keyframes c25-poser {
  from { opacity: 0; filter: blur(6px); }
  to   { opacity: 1; filter: blur(0); }
}
@keyframes c25-fondu {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}
/* La barre d'étape se tire sous la couverture, de gauche à
   droite : le geste dit « voilà où en est ce dossier ». */
@keyframes c25-tirer {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes c25-tirer-h {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
/* Le balayage : une bande de lumière traverse la couverture une
   fois, au survol. Une seule passe — en boucle, ça devient une
   enseigne de magasin. */
@keyframes c25-balayage {
  from { transform: translate3d(-130%, 0, 0) rotate(14deg); }
  to   { transform: translate3d(230%, 0, 0) rotate(14deg); }
}
@keyframes c25-pop {
  from { opacity: 0; transform: translate3d(0, 22px, 0) scale(.94); }
  to   { opacity: 1; transform: none; }
}

.c25-carte, .c25-video {
  animation: c25-lever 560ms var(--m-ressort) backwards;
  animation-delay: var(--d, 0ms);
}
.c25-carte .c25-bande, .c25-video .c25-bande {
  transform-origin: 0 50%;
  animation: c25-tirer 640ms var(--m-vif) backwards;
  animation-delay: calc(var(--d, 0ms) + 220ms);
}

/* ── LE BALAYAGE DE LUMIÈRE ───────────────────────────────────
   Il vit sur la couverture, au-dessus de l'image et sous les
   étiquettes, et il ne part QUE si la carte est survolée ou
   atteinte au clavier. Une carte au repos ne consomme rien. */
.c25-cadre::after {
  content: ""; position: absolute; z-index: 2; top: -40%; bottom: -40%; left: 0; width: 42%;
  pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.16) 46%, rgba(255,255,255,.03) 72%, transparent);
  transform: translate3d(-130%, 0, 0) rotate(14deg);
}
.c25-carte:hover .c25-cadre::after,
.c25-video:hover .c25-cadre::after,
.c25-carte:focus-visible .c25-cadre::after,
.c25-video:focus-visible .c25-cadre::after {
  opacity: 1; animation: c25-balayage 880ms var(--m-doux) 1;
}

/* La couverture prend un peu de profondeur au survol : l'image
   avance, le voile s'ouvre légèrement pour la laisser respirer. */
.c25-voile { transition: opacity 420ms var(--m-doux); }
.c25-carte:hover .c25-voile, .c25-video:hover .c25-voile { opacity: .86; }

/* L'étiquette d'étape et le retard remontent d'un cheveu — assez
   pour qu'on sente que la vignette est vivante, pas assez pour
   qu'on le remarque consciemment. */
.c25-etape-puce, .c25-code, .c25-retard {
  transition: transform 320ms var(--m-ressort), border-color 320ms var(--m-doux);
}
.c25-carte:hover .c25-etape-puce, .c25-video:hover .c25-code { transform: translate3d(0, -2px, 0); }
.c25-carte:hover .c25-retard { transform: translate3d(0, -2px, 0); border-color: rgba(255,77,85,.7); }

/* ── LA CHAÎNE QUI SE CONSTRUIT ───────────────────────────────
   Les maillons franchis se remplissent l'un après l'autre, dans
   l'ordre où le studio les a réellement franchis. C'est la seule
   animation de l'écran qui raconte une chronologie. */
.c25-maillon { animation: c25-fondu 420ms var(--m-vif) backwards; animation-delay: var(--d, 0ms); }
.c25-maillon::before { transform-origin: 50% 0; }
.c25-m-fait::before {
  animation: c25-tirer-h 520ms var(--m-vif) backwards;
  animation-delay: calc(var(--d, 0ms) + 160ms);
}

/* ── LE CORPS QUI CHANGE ──────────────────────────────────────
   Passer de « L'Espace » à « La chaîne » reconstruit tout le bas
   de la page. Sans transition le contenu saute, et on perd une
   demi-seconde à retrouver où on en était. */
.c25-corps { animation: c25-fondu 340ms var(--m-vif) backwards; }

/* ── L'ESPACE ─────────────────────────────────────────────────
   Les objets se posent, puis les fils qui les relient
   apparaissent — dans cet ordre, parce qu'un fil qui arrive avant
   ses deux extrémités ne relie rien. */
.c25-objet {
  animation: c25-poser 500ms var(--m-doux) backwards; animation-delay: var(--d, 0ms);
  transition: box-shadow var(--m-court) var(--m-doux);
}
.c25-liens { animation: c25-fondu 600ms var(--m-doux) 520ms backwards; }
.c25-objet:hover { box-shadow: 0 22px 44px -26px #000, 0 0 0 1px rgba(120,150,190,.28); }

/* ── LA FENÊTRE D'APERÇU ────────────────────────
   Direction : « les pop up ». Elle sert à une chose précise :
   regarder un livrable sans quitter le dossier. Ouvrir la page du
   dossier pour lire une échéance et revenir, c'est deux
   chargements pour une ligne de texte.

   ⚠ ON NE RÉÉCRIT PAS UNE MODALE. L'OS en a déjà une — `modal()`
   dans `core/ui.js` — avec son voile, sa fermeture à Échap, son
   clic à côté et son animation d'entrée. Une seconde
   implémentation, c'est un second endroit où la touche Échap
   finit par ne plus marcher. On lui donne juste un contenu.

   ⚠ ET ELLE NE REMPLACE PAS LA PAGE DU DOSSIER. Tout ce qui
   ENGAGE — franchir une porte, valider, demander une correction —
   reste là où sont les contrôles et le journal. Cette fenêtre
   montre, et propose d'aller là-bas. Elle n'écrit rien. */
.c25-apercu { animation: c25-pop 380ms var(--m-ressort) backwards; }
.c25-apercu .c25-cadre { margin-bottom: 15px; }
.c25-ap-kick {
  margin: 0 0 5px; font-family: var(--f-mono); font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--n-or);
}
.c25-ap-titre { margin: 0 0 13px; font-size: 19px; font-weight: 700; letter-spacing: -.03em; }
.c25-ap-faits {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 9px; margin: 0 0 14px;
}
.c25-ap-fait {
  padding: 10px 12px; border-radius: 10px; border: 1px solid var(--n-bord);
  border-left: 2px solid var(--tn, var(--n-bord)); background: rgba(255,255,255,.022);
}
.c25-ap-fait s {
  display: block; text-decoration: none; font-family: var(--f-mono); font-size: 9px;
  font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-3);
}
.c25-ap-fait b { display: block; margin-top: 5px; font-size: 13.5px; font-weight: 600; letter-spacing: -.015em; }
.c25-ap-cyan { --tn: var(--n-cyan); } .c25-ap-or { --tn: var(--n-or); }
.c25-ap-vert { --tn: var(--n-vert); } .c25-ap-rouge { --tn: var(--n-rouge); }
.c25-ap-note {
  margin: 0; padding: 12px 14px; border-radius: 11px;
  border: 1px solid rgba(120,150,190,.12); background: rgba(255,255,255,.022);
  font-size: 12.5px; line-height: 1.6; color: var(--n-tx-3);
}

/* ── ET TOUT S'ARRÊTE SI LA PERSONNE L'A DEMANDÉ ──────────────
   Ce réglage n'est pas un confort : pour une partie des gens, une
   image qui glisse déclenche une nausée. On coupe le mouvement et
   on garde l'état final — jamais l'inverse, sinon la page reste
   invisible. */
@media (prefers-reduced-motion: reduce) {
  .c25-carte, .c25-video, .c25-objet, .c25-maillon, .c25-corps, .c25-liens,
  .c25-carte .c25-bande, .c25-video .c25-bande, .c25-m-fait::before,
  .c25-apercu {
    animation: none !important; transition: none !important;
  }
  .c25-cadre::after { display: none; }
}

/* =============================================================
   40. CERCLE 25 EST L'ÉCRAN DES PROJETS
   9 septembre 2026

   La Direction, devant l'écran « Projets » : « had projet haka rah
   hia cercle. Khass normalement haka tkon, machi dik cercle li
   drty. Khass haka tkon b commercial / pré-prod / prod / post-prod
   / livraison ta7t mn cercle. Ou 9ad fiha la pré-prod, mab9awch
   m9adin, tal3in bzaf hda ba3diathom. Ou ykon hadchi animé kter ou
   effects light kter ou quality kter. »

   Trois choses dans ce message, et la première est la plus
   importante : l'écran qu'il voulait EXISTAIT DÉJÀ. Le mur de
   couvertures écrit la veille était un deuxième écran pour le même
   besoin — donc un endroit de plus à tenir à jour, et deux
   réponses différentes à « où en est le studio ». `#/cercle` mène
   maintenant à cet écran-là ; le mur ne survit que comme filet, si
   l'on arrive sur une fiche sans identifiant.

   ── LA PRÉ-PRODUCTION ÉTAIT ILLISIBLE, ET C'EST UNE HISTOIRE DE
      LARGEUR

   Douze dossiers en pré-production, dans une grille dont la
   colonne minimale valait 280 px : sur un écran de bureau, six
   cartes par rangée. Une couverture 16:9 dans 280 px fait 157 px
   de haut — une vignette de contact, pas une affiche. Et le titre,
   le client, le responsable, l'échéance et ce qui bloque
   s'empilaient dessous dans la même largeur.

   La colonne passe à 336 px : quatre par rangée au lieu de six,
   l'affiche reprend un tiers de surface, et les trois lignes de
   texte cessent de se casser au milieu d'un mot. On perd deux
   dossiers par rangée ; on gagne de pouvoir les lire.
   ============================================================= */

.galerie {
  grid-template-columns: repeat(auto-fill, minmax(336px, 1fr));
  gap: 18px;
}
@media (max-width: 760px) {
  .galerie { grid-template-columns: 1fr; gap: 14px; }
}

/* ⚠ `backwards`, PAS `both` — ET CE N'EST PAS COSMÉTIQUE.

   `sys-carte-entre` finit sur `transform: none`. Avec un
   remplissage `both`, cette dernière image reste appliquée POUR
   TOUJOURS, et une animation gagne contre une règle ordinaire dans
   la cascade. Résultat : `.gal-carte:hover { transform:
   translateY(-6px) }` ne pouvait plus rien, et la carte ne se
   soulevait jamais — le survol changeait l'ombre et la bordure,
   mais la carte restait collée. Personne ne l'avait vu parce que
   le reste du survol, lui, marchait.

   `backwards` tient la première image pendant le délai — c'est
   tout ce dont la cascade d'entrée a besoin — puis rend la carte à
   ses propres règles dès la fin. */
.gal-carte { animation-fill-mode: backwards; }

/* ── LA LUMIÈRE QUI PASSE SUR L'AFFICHE ───────────────────────
   Une bande claire traverse la couverture, une fois, quand on
   survole. Elle est au-dessus du voile (`.gal-visuel::after`) mais
   sous le badge de phase, et elle ne coûte rien tant que personne
   ne survole : sans `:hover`, aucune animation ne tourne. */
.gal-visuel::before {
  content: ""; position: absolute; z-index: 2; top: -40%; bottom: -40%; left: 0; width: 40%;
  pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.18) 46%, rgba(255,255,255,.04) 72%, transparent);
  transform: translate3d(-130%, 0, 0) rotate(14deg);
}
.gal-carte:hover .gal-visuel::before,
.gal-carte:focus-visible .gal-visuel::before {
  opacity: 1; animation: c25-balayage 900ms var(--m-doux) 1;
}

/* ── LA COULEUR DU DÉPARTEMENT S'ALLUME ───────────────────────
   Chaque carte porte déjà `--dep`, la couleur de son département.
   Au survol, c'est cette couleur qui monte — un halo, pas un
   blanc générique : on reconnaît une carte de post-production à sa
   lumière avant d'avoir lu son étiquette. */
.gal-carte {
  position: relative;
  transition: transform var(--m-moyen) var(--m-ressort),
              border-color var(--m-moyen) var(--m-doux),
              box-shadow var(--m-moyen) var(--m-doux);
}
.gal-carte:hover {
  border-color: color-mix(in srgb, var(--dep, var(--n-cyan)) 46%, transparent);
  box-shadow: 0 34px 64px -34px #000,
              0 0 0 1px color-mix(in srgb, var(--dep, var(--n-cyan)) 26%, transparent),
              0 12px 46px -26px color-mix(in srgb, var(--dep, var(--n-cyan)) 55%, transparent);
}
/* Un filet de couleur en haut de la carte, qui se tire au survol.
   Il dit le département sans prendre une ligne de texte. */
.gal-carte::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; z-index: 4;
  background: linear-gradient(90deg, var(--dep, var(--n-cyan)), transparent 78%);
  transform: scaleX(0); transform-origin: 0 50%; opacity: .9;
  transition: transform 520ms var(--m-vif);
}
.gal-carte:hover::before, .gal-carte:focus-visible::before { transform: scaleX(1); }

.gal-phase, .gal-alerte {
  transition: transform 320ms var(--m-ressort), border-color 320ms var(--m-doux);
}
.gal-carte:hover .gal-phase, .gal-carte:hover .gal-alerte { transform: translate3d(0, -2px, 0); }

/* ── LES FILTRES D'ÉTAPE ──────────────────────────────────────
   Ce sont eux que la Direction a nommés : commercial, pré-prod,
   prod, post-prod, livraison. Celui qui est actif s'allume de la
   couleur de son département — c'est le seul repère qui dit dans
   quelle moitié du studio on regarde. */
/* Le survol des puces est déjà réglé plus haut (section 21) ;
   on n'ajoute ici que la couleur de l'étape retenue. */
.chip.is-on {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--dep, var(--n-or)) 34%, transparent),
              0 8px 24px -14px color-mix(in srgb, var(--dep, var(--n-or)) 70%, transparent);
}

/* ── LA FILMOTHÈQUE ───────────────────────────────────────────
   Le rail garde son inertie native ; on ne lui ajoute qu'un
   arrêt plus franc sur l'affiche survolée. */
.filmo-case { transition: transform var(--m-moyen) var(--m-ressort), opacity var(--m-moyen) var(--m-doux); }
.filmo-piste:hover .filmo-case:not(:hover) { opacity: .82; }

@media (prefers-reduced-motion: reduce) {
  .gal-carte, .gal-carte::before, .gal-phase, .gal-alerte, .filmo-case {
    animation: none !important; transition: none !important;
  }
  .gal-visuel::before { display: none; }
  .gal-carte::before { transform: scaleX(1); }
  .filmo-piste:hover .filmo-case:not(:hover) { opacity: 1; }
}

/* =============================================================
   41. LA LUMIÈRE DES DEUX MOTEURS
   9 septembre 2026

   Direction : « zid quality dial cercle ou spider, zid f
   l'animation ou effects ou lights ».

   ── CE QUI SÉPARE UN EFFET D'UNE DÉCORATION

   SPIDER et CERCLE ne se regardent pas pareil. CERCLE est fait
   d'affiches : on y cherche une image, donc la lumière sert à
   faire ressortir une couverture. SPIDER est fait de chiffres :
   on y cherche un nombre, donc la lumière doit servir à faire
   ressortir LE nombre, pas la boîte autour.

   D'où la règle tenue partout dans cette section : **la lumière
   prend la couleur de ce qu'elle éclaire.** Une tuile en retard
   s'allume en rouge, une tuile du jour en or, une carte de
   post-production dans le cyan de son département. Un halo blanc
   générique aurait été plus facile à écrire et n'aurait rien
   appris à personne.

   ── ET CE QUI RESTE INTERDIT

   Rien ne tourne en boucle, sauf UNE chose à l'écran : le repère
   qui dit « c'est ici ». Deux respirations simultanées, et
   l'œil ne sait plus laquelle compte. Aucune animation ne dure
   plus de 900 ms. Aucun flou n'est animé en permanence — il ne
   sert qu'à l'entrée, puis la propriété est rendue.

   ⚠ LES CASCADES SONT ÉCRITES EN `nth-child`, PAS EN JAVASCRIPT.
   C'est le procédé que la feuille utilise déjà pour la galerie
   (neon-systeme, ligne 1066) : le décalage appartient à la
   présentation, et le rendre à JavaScript obligerait à toucher
   `spider.js` — 102 Ko de logique commerciale — pour une question
   de millisecondes.
   ============================================================= */

/* ⚠ MESURÉ EN LIGNE : SEPT TUILES SUR NEUF N'ONT PAS DE COULEUR.

   `--sp-tn` n'est posé que par `.sp-t-urgent`, `.sp-t-jour`,
   `.sp-t-ok` et `.sp-t-info`. Les autres tuiles — « 396 traités »,
   « 7 aujourd'hui » — n'en ont aucune, et une lumière tirée de
   `--sp-tn` y valait donc `transparent` : rien du tout. Sur
   l'écran réel, l'effet ne se voyait que deux fois sur neuf.

   On sépare donc LA COULEUR DU CHIFFRE de LA COULEUR DE SA
   LUMIÈRE. `--sp-tn` continue de teindre le nombre — et une tuile
   sans ton garde son nombre en blanc, ce qui est juste : il n'a
   rien d'urgent à dire. `--sp-lum` prend le relais pour l'éclat,
   avec le violet de SPIDER par défaut. Résultat : tout l'écran
   porte une lumière, et celles qui ont un ton portent LE LEUR. */
.sp-tuile, .sp-maillon, .sp-carte-action { --sp-lum: var(--sp-tn, rgba(139,92,246,.62)); }

@keyframes os25-arrive {
  from { opacity: 0; transform: translate3d(0, 12px, 0); }
  to   { opacity: 1; transform: none; }
}
/* ⚠ UNE RESPIRATION DORÉE, ET PAS CELLE QUI EXISTE DÉJÀ.
   `os25-souffle` bat en cyan — c'est la couleur de CERCLE. La
   pastille « ici » de la mission est en or depuis toujours ; lui
   coller le souffle cyan aurait changé sa couleur au milieu de
   son battement, deux fois par seconde. */
@keyframes os25-souffle-or {
  0%, 100% { box-shadow: 0 0 0 0 rgba(242,185,64,.34), 0 0 10px -2px rgba(242,185,64,.55); }
  50%      { box-shadow: 0 0 0 5px rgba(242,185,64,0),  0 0 22px -2px rgba(242,185,64,.95); }
}

/* La glissade d'une feuille qui monte du bas de l'écran. */
@keyframes os25-feuille {
  from { opacity: 0; transform: translate3d(0, 34px, 0); }
  to   { opacity: 1; transform: none; }
}

/* =============================================================
   41.1 SPIDER — LES CHIFFRES PORTENT LEUR LUMIÈRE
   ============================================================= */

/* ── LES TUILES DU MATIN ──────────────────────────────────────
   Six tuiles, six retards de 55 ms : la dernière entre un tiers
   de seconde après la première, ce qui se lit comme un ordre et
   non comme une lenteur. */
.sp-tuiles > .sp-tuile { animation: os25-arrive 420ms var(--m-vif) backwards; }
.sp-tuiles > .sp-tuile:nth-child(1) { animation-delay:   0ms; }
.sp-tuiles > .sp-tuile:nth-child(2) { animation-delay:  55ms; }
.sp-tuiles > .sp-tuile:nth-child(3) { animation-delay: 110ms; }
.sp-tuiles > .sp-tuile:nth-child(4) { animation-delay: 165ms; }
.sp-tuiles > .sp-tuile:nth-child(5) { animation-delay: 220ms; }
.sp-tuiles > .sp-tuile:nth-child(n+6) { animation-delay: 275ms; }

/* Le rail de couleur se tire du haut vers le bas, juste après
   que la tuile soit posée. */
.sp-tuile::after {
  transform-origin: 50% 0;
  animation: c25-tirer-h 480ms var(--m-vif) 180ms backwards;
  transition: width var(--m-court) var(--m-doux), box-shadow var(--m-court) var(--m-doux);
}

/* ⚠ LE HALO EST SUR LE CHIFFRE, PAS SUR LA TUILE. C'est le
   nombre qu'on vient lire — « 10 en retard » — et c'est donc lui
   qui doit être la chose la plus lumineuse de la boîte. Un halo
   sur la bordure aurait éclairé le contenant. */
.sp-tuile b {
  text-shadow: 0 0 26px color-mix(in srgb, var(--sp-lum) 42%, transparent);
  transition: text-shadow var(--m-moyen) var(--m-doux);
}
.sp-tuile:hover b { text-shadow: 0 0 34px color-mix(in srgb, var(--sp-lum) 72%, transparent); }
.sp-tuile:hover {
  border-color: color-mix(in srgb, var(--sp-tn, var(--n-bord)) 38%, transparent);
  box-shadow: 0 18px 38px -26px #000,
              0 0 34px -20px color-mix(in srgb, var(--sp-lum) 82%, transparent);
}
/* Le rail d'une tuile sans ton reste gris au repos — il ne
   prétend pas dire quelque chose. C'est au survol qu'il s'allume,
   parce qu'à ce moment-là c'est la tuile qu'on regarde. */
.sp-tuile:hover::after {
  width: 3px;
  background: var(--sp-tn, rgba(139,92,246,.55));
  box-shadow: 0 0 14px color-mix(in srgb, var(--sp-lum) 78%, transparent);
}
/* Une bande de lumière traverse la tuile au survol — une passe,
   et seulement tant que le curseur est dessus. */
.sp-tuile::before {
  content: ""; position: absolute; z-index: 0; top: -40%; bottom: -40%; left: 0; width: 44%;
  pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.10) 48%, transparent);
  transform: translate3d(-130%, 0, 0) rotate(14deg);
}
.sp-tuile:hover::before { opacity: 1; animation: c25-balayage 820ms var(--m-doux) 1; }
.sp-tuile b, .sp-tuile span, .sp-tuile small { position: relative; z-index: 1; }

/* ── LA CHAÎNE COMMERCIALE ────────────────────────────────────
   Six maillons qui se posent de gauche à droite : c'est l'ordre
   du parcours, du signal à la signature. */
.sp-chaine > .sp-maillon { animation: os25-arrive 400ms var(--m-vif) backwards; }
.sp-chaine > .sp-maillon:nth-child(1) { animation-delay:   0ms; }
.sp-chaine > .sp-maillon:nth-child(2) { animation-delay:  62ms; }
.sp-chaine > .sp-maillon:nth-child(3) { animation-delay: 124ms; }
.sp-chaine > .sp-maillon:nth-child(4) { animation-delay: 186ms; }
.sp-chaine > .sp-maillon:nth-child(5) { animation-delay: 248ms; }
.sp-chaine > .sp-maillon:nth-child(n+6) { animation-delay: 310ms; }

.sp-maillon b {
  text-shadow: 0 0 24px color-mix(in srgb, var(--sp-lum) 38%, transparent);
  transition: text-shadow var(--m-moyen) var(--m-doux);
}
.sp-maillon:hover b { text-shadow: 0 0 32px color-mix(in srgb, var(--sp-lum) 70%, transparent); }
/* La flèche qui relie deux maillons avance d'un cheveu quand on
   survole celui de gauche : le lien devient un mouvement. */
.sp-maillon::after {
  transition: border-color var(--m-court) var(--m-doux), transform var(--m-court) var(--m-doux);
}
.sp-maillon:hover::after {
  border-color: rgba(139,92,246,.75);
  transform: rotate(45deg) translate3d(2px, -2px, 0);
}
.sp-maillon:hover {
  border-color: color-mix(in srgb, var(--sp-tn, var(--n-bord)) 34%, transparent);
  box-shadow: 0 16px 34px -26px #000,
              0 0 30px -20px color-mix(in srgb, var(--sp-lum) 72%, transparent);
}

/* ── LES CARTES, ET LEUR FILET VIOLET ─────────────────────────
   SPIDER est violet comme CERCLE est cyan : c'est le repère qui
   dit dans lequel des deux moteurs on se trouve. */
.sp-cartes > .sp-carte { animation: os25-arrive 420ms var(--m-vif) backwards; }
.sp-cartes > .sp-carte:nth-child(1) { animation-delay:   0ms; }
.sp-cartes > .sp-carte:nth-child(2) { animation-delay:  70ms; }
.sp-cartes > .sp-carte:nth-child(3) { animation-delay: 140ms; }
.sp-cartes > .sp-carte:nth-child(n+4) { animation-delay: 210ms; }

.sp-carte { position: relative; overflow: hidden; }
.sp-carte::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; z-index: 3;
  background: linear-gradient(90deg, var(--n-violet, #8B5CF6), transparent 78%);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 520ms var(--m-vif);
}
.sp-carte:hover::before, .sp-carte:focus-within::before { transform: scaleX(1); }
.sp-carte:hover {
  box-shadow: 0 24px 48px -30px #000, 0 0 34px -22px rgba(139,92,246,.7);
}

/* La carte d'action porte déjà la couleur de son urgence sur son
   bord gauche ; au survol, ce bord s'allume au lieu de rester un
   trait mat. */
.sp-carte-action { transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease,
                               border-left-color .18s ease; }
.sp-carte-action:hover {
  border-left-color: var(--sp-tn, rgba(139,92,246,.5));
  box-shadow: 0 22px 46px -30px #000,
              -3px 0 22px -12px color-mix(in srgb, var(--sp-lum) 85%, transparent);
}

/* ── LES ONGLETS ──────────────────────────────────────────────
   L'onglet retenu s'allume en violet et pose un trait sous lui.
   Le trait grandit depuis le centre : il désigne, il ne glisse
   pas d'un onglet à l'autre — le contenu, lui, a déjà changé. */
.sp-vue { position: relative; }
.sp-vue::after {
  content: ""; position: absolute; left: 14px; right: 14px; bottom: 5px; height: 2px;
  border-radius: 2px; background: linear-gradient(90deg, transparent, #A78BFA, transparent);
  transform: scaleX(0); transform-origin: 50% 50%;
  transition: transform 380ms var(--m-ressort);
}
.sp-vue.on::after { transform: scaleX(1); }
.sp-vue.on { box-shadow: inset 0 0 0 1px rgba(139,92,246,.36), 0 8px 26px -16px rgba(139,92,246,.8); }

/* ── LA FEUILLE QUI MONTE DU BAS ──────────────────────────────
   La fiche d'un prospect arrive par le bas de l'écran, comme une
   feuille qu'on tire. Le fond derrière elle se floute : ce qui
   n'est plus le sujet cesse d'être lisible, et l'attention n'a
   qu'un endroit où aller. */
.sp-fond {
  backdrop-filter: blur(8px);
  animation: c25-fondu 220ms var(--m-doux) backwards;
}
.sp-fiche { animation: os25-feuille 440ms var(--m-ressort) backwards; }

/* ── LES CANAUX ───────────────────────────────────────────────
   WhatsApp en vert, le téléphone en cyan : la couleur du canal,
   pas une couleur d'interface. */
.sp-canal { transition: transform var(--m-court) var(--m-doux), box-shadow var(--m-court) var(--m-doux),
                        border-color var(--m-court) var(--m-doux); }
.sp-canal-wa:hover, .sp-canal-tel:hover { transform: translate3d(0, -2px, 0); }
.sp-canal-wa:hover  { box-shadow: 0 10px 26px -16px rgba(36,217,129,.9); }
.sp-canal-tel:hover { box-shadow: 0 10px 26px -16px rgba(18,217,255,.85); }

/* ── LA MISSION DU JOUR ───────────────────────────────────────
   ⚠ C'EST LA SEULE CHOSE QUI RESPIRE EN CONTINU DANS SPIDER.
   La pastille « ici » de la jauge dit où la personne en est dans
   sa liste du matin. Si autre chose respirait à côté, elle ne
   serait plus le point qu'on cherche. */
.sp-mission-jauge i { transition: background var(--m-court) var(--m-doux), box-shadow var(--m-court) var(--m-doux); }
.sp-mission-jauge i.ici { animation: os25-souffle-or 6s ease-in-out infinite; }

/* =============================================================
   41.2 CERCLE — L'AFFICHE PREND LA LUMIÈRE
   ============================================================= */

/* ── LE RAIL DE LA FILMOTHÈQUE S'EFFACE À SES BORDS ───────────
   Le rail déborde volontairement de la page pour dire « ça
   continue ». Une affiche coupée net au pixel près dit plutôt
   « c'est cassé ». Le masque la fait fondre sur les vingt
   derniers pixels : la coupure devient un fondu de cinéma. */
.filmo-piste {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 22px, #000 calc(100% - 34px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 22px, #000 calc(100% - 34px), transparent 100%);
}
@media (max-width: 760px) {
  .filmo-piste {
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
            mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 24px), transparent 100%);
  }
}

/* ── LES REPÈRES DE LA FICHE ──────────────────────────────────
   Étape, échéance, ce qui bloque, avancement : quatre repères qui
   se posent dans cet ordre, celui dans lequel on les lit. */
.c25-reperes > .c25-repere { animation: os25-arrive 380ms var(--m-vif) backwards; }
.c25-reperes > .c25-repere:nth-child(1) { animation-delay:  60ms; }
.c25-reperes > .c25-repere:nth-child(2) { animation-delay: 120ms; }
.c25-reperes > .c25-repere:nth-child(3) { animation-delay: 180ms; }
.c25-reperes > .c25-repere:nth-child(n+4) { animation-delay: 240ms; }
.c25-repere { transition: border-color var(--m-court) var(--m-doux), box-shadow var(--m-court) var(--m-doux); }
.c25-repere:hover {
  border-left-color: var(--tn, var(--n-bord));
  box-shadow: -3px 0 20px -12px color-mix(in srgb, var(--tn, transparent) 85%, transparent);
}
/* Le titre du dossier et son filet d'or arrivent avant le reste. */
.c25-dossier h1 { animation: os25-arrive 460ms var(--m-ressort) backwards; }
.c25-dossier::after {
  transform-origin: 0 50%;
  animation: c25-tirer 620ms var(--m-vif) 200ms backwards;
}

/* ── LE TABLEAU PAR DÉPARTEMENT ───────────────────────────────
   Une colonne par étape. L'en-tête porte la pastille de son
   département ; on lui donne la lumière qui va avec, pour qu'on
   repère une colonne à sa couleur avant d'avoir lu son nom. */
.board-col-head .sw {
  box-shadow: 0 0 12px color-mix(in srgb, var(--dep, transparent) 85%, transparent);
}
.board-card { transition: transform var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux),
                          box-shadow var(--m-court) var(--m-doux); }
.board-card:hover {
  transform: translate3d(0, -2px, 0);
  box-shadow: -3px 0 22px -12px color-mix(in srgb, var(--dep, transparent) 85%, transparent),
              0 16px 32px -24px #000;
}

/* =============================================================
   41.3 ET RIEN DE TOUT CELA POUR QUI A DEMANDÉ LE CALME

   `prefers-reduced-motion` n'est pas un goût : c'est une consigne
   médicale pour une partie des gens. On coupe le mouvement et on
   garde l'état final — jamais l'inverse, sinon la page reste
   vide.
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  .sp-tuiles > .sp-tuile, .sp-chaine > .sp-maillon, .sp-cartes > .sp-carte,
  .sp-tuile::after, .sp-carte::before, .sp-vue::after, .sp-fond, .sp-fiche,
  .sp-mission-jauge i.ici, .sp-canal, .sp-carte-action,
  .c25-reperes > .c25-repere, .c25-dossier h1, .c25-dossier::after {
    animation: none !important; transition: none !important;
  }
  .sp-tuile::before { display: none; }
  .sp-tuile::after, .c25-dossier::after { transform: none; }
  .sp-vue.on::after { transform: scaleX(1); }
}

/* =============================================================
   42. LA VUE CERCLE ÉTAIT CASSÉE, ET LE RESTE N'AVAIT PAS LE
       TRAITEMENT DU TABLEAU DE BORD
   9 septembre 2026

   Direction, capture d'écran à l'appui : « 9ad had l pré-production
   db », et « zid f quality, rado premium b light ou les effects
   b7al deashbord, avec les animations ou les flou ».

   ── ⚠ LE DÉFAUT : DOUZE CARTES ÉCRASÉES À DIX-HUIT PIXELS

   Mesuré en direct sur la colonne Pré-production :

       .voie-carte  →  hauteur 18 px, overflow: hidden
       .voie-visuel →  hauteur 188 px
       .voie-info   →  hauteur 136 px

   Une carte de 18 px de haut contenant 324 px de contenu. À
   l'écran : douze bandes d'image de la hauteur d'un trait, sans
   titre, sans client, sans échéance. Illisibles, et pour cause —
   il n'y avait rien à lire.

   La cause est une règle par défaut de flexbox que personne
   n'écrit et que tout le monde subit. `.board-col-body` est une
   colonne flex avec une hauteur bornée (`max-height: calc(100dvh
   - 320px)`). Un enfant flex vaut `flex-shrink: 1` par défaut :
   quand la somme des enfants dépasse le conteneur, ils RÉTRÉCISSENT
   au lieu de le faire défiler. Une carte, ça tient : la colonne
   Production, qui n'en avait qu'une, s'affichait parfaitement.
   Douze cartes, et chacune reçoit un douzième de la place.

   C'est aussi pour ça que le défaut était invisible en
   développement : il faut douze dossiers dans la même étape pour
   le déclencher, et il n'apparaît que dans la vue Cercle.

   `flex: 0 0 auto` rend à chaque carte sa hauteur naturelle. Le
   `overflow-y: auto` déjà posé sur la colonne fait alors son
   travail : ça défile, comme prévu depuis le début.
   ============================================================= */

.board-col-body > * { flex: 0 0 auto; }

/* La colonne s'élargit : à 260 px, une couverture forcée à 188 px
   de haut par la feuille du tableau de bord était étirée hors de
   ses proportions. On rend le 16/9 à l'image et de la place au
   texte. */
.board-col { flex: 0 0 300px; }
@media (max-width: 700px) { .board-col { flex: 0 0 82%; } }
.board-col-body .voie-visuel {
  height: auto !important;
  aspect-ratio: 16 / 9;
  border-radius: 10px; overflow: hidden;
}

/* ⚠ ET LA COLONNE DIT QU'ELLE CONTINUE. Douze cartes dans une
   colonne qui défile, coupées net en bas, se lisent comme « il y
   en a douze ». Le fondu dit « il y en a plus » — la même raison
   que le rail de la filmothèque. */
.board-col-body {
  -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
          mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent 100%);
  scrollbar-width: thin;
}

/* ── LE VERRE DU TABLEAU DE BORD ──────────────────────────────
   Direction : « b7al deashbord ». Ce qui donne au tableau de bord
   son air premium n'est pas une couleur : c'est un empilement —
   un fond translucide, un flou derrière, un liseré clair en haut
   qui imite un bord biseauté, et une ombre portée large et très
   diffuse. On prend le même empilement, on ne l'invente pas une
   deuxième fois. */
.board-col {
  background: linear-gradient(168deg, rgba(18,27,39,.86), rgba(8,13,20,.92));
  backdrop-filter: blur(14px);
  box-shadow: 0 30px 60px -40px #000, inset 0 1px 0 rgba(255,255,255,.05);
}
/* Le halo du département derrière l'en-tête de colonne : on
   reconnaît la post-production à sa couleur avant d'avoir lu son
   nom. */
.board-col-head {
  position: relative;
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--dep) 14%, transparent), transparent);
}
.board-col-head::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--dep) 70%, transparent), transparent 70%);
}

/* Les cartes de la colonne prennent le traitement des cartes de
   l'accueil : le même relief, la même levée au survol, la couleur
   de leur département dans l'ombre. */
.board-col-body .voie-carte {
  border-radius: 14px !important;
  padding: 8px !important;
  background: linear-gradient(168deg, rgba(16,25,36,.94), rgba(9,14,21,.96)) !important;
  border: 1px solid rgba(120,150,190,.15) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.04);
  transition: transform var(--m-moyen) var(--m-ressort),
              border-color var(--m-moyen) var(--m-doux),
              box-shadow var(--m-moyen) var(--m-doux);
  animation: os25-arrive 420ms var(--m-vif) backwards;
}
.board-col-body > *:nth-child(1) { animation-delay:   0ms; }
.board-col-body > *:nth-child(2) { animation-delay:  50ms; }
.board-col-body > *:nth-child(3) { animation-delay: 100ms; }
.board-col-body > *:nth-child(4) { animation-delay: 150ms; }
.board-col-body > *:nth-child(n+5) { animation-delay: 200ms; }

.board-col-body .voie-carte:hover {
  transform: translate3d(0, -6px, 0);
  border-color: color-mix(in srgb, var(--dep, var(--n-cyan)) 46%, transparent) !important;
  box-shadow: 0 30px 56px -30px #000,
              0 0 34px -20px color-mix(in srgb, var(--dep, var(--n-cyan)) 75%, transparent);
}
/* La couverture avance dans son cadre, elle ne pousse pas la
   carte : la colonne ne doit pas sauter au survol. */
.board-col-body .voie-visuel .affiche {
  transition: transform 460ms var(--m-doux), filter 460ms var(--m-doux);
}
.board-col-body .voie-carte:hover .voie-visuel .affiche {
  transform: scale(1.06); filter: saturate(1.1) brightness(1.06);
}
/* Le balayage de lumière, comme sur les affiches de la galerie. */
.board-col-body .voie-visuel::before {
  content: ""; position: absolute; z-index: 2; top: -40%; bottom: -40%; left: 0; width: 42%;
  pointer-events: none; opacity: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.16) 46%, transparent);
  transform: translate3d(-130%, 0, 0) rotate(14deg);
}
.board-col-body .voie-carte:hover .voie-visuel::before {
  opacity: 1; animation: c25-balayage 880ms var(--m-doux) 1;
}
/* ⚠ SCOPÉ À LA COLONNE. `.voie-info` sert aussi aux cartes de
   l'accueil, que la Direction ne veut pas voir bouger. */
.board-col-body .voie-info { padding: 10px 6px 6px; gap: 3px; }
.board-col-body .voie-info > b { font-size: 14px; letter-spacing: -.015em; }

/* ── LE VERRE, AUSSI SUR LA GALERIE ET SPIDER ─────────────────
   Le même empilement, appliqué là où l'on passe la journée. */
.gal-carte {
  background: linear-gradient(168deg, rgba(18,27,39,.9), rgba(8,13,20,.95));
  backdrop-filter: blur(12px);
  box-shadow: 0 26px 52px -34px #000, inset 0 1px 0 rgba(255,255,255,.045);
}
.sp-tuile, .sp-carte, .sp-maillon, .sp-carte-action {
  background: linear-gradient(168deg, rgba(19,28,41,.86), rgba(9,14,21,.92));
  backdrop-filter: blur(12px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.045);
}
.sp-vues { backdrop-filter: blur(12px); }

@media (prefers-reduced-motion: reduce) {
  .board-col-body .voie-carte { animation: none !important; transition: none !important; }
  .board-col-body .voie-visuel::before { display: none; }
}

/* ── LE NOM DU CLIENT DEVIENT LA PORTE VERS LE COMMERCIAL ─────
   Il garde la graisse et la couleur du sur-titre : ce n'est pas
   un bouton de plus, c'est le même mot qui conduit ailleurs. Le
   soulignement n'apparaît qu'au survol — sinon la ligne de
   sur-titre se met à ressembler à un menu. */
.c25-kick-lien {
  color: inherit; text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--n-or) 34%, transparent);
  transition: color var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux),
              text-shadow var(--m-court) var(--m-doux);
}
.c25-kick-lien:hover {
  color: #FFD98A;
  border-bottom-color: var(--n-or);
  text-shadow: 0 0 18px color-mix(in srgb, var(--n-or) 60%, transparent);
}
.c25-kick-lien:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 3px; border-radius: 3px; }

/* =============================================================
   43. UN CRAN PLUS PETIT, ET UN ÉCRAN DE TÉLÉPHONE QUI TIENT
   9 septembre 2026

   Direction : « sagher l ktaba chwiya f OS kamel, sgharha. Ou
   katbaan f telephone mchaarji bzaf ou mkharbe9. L OS khasso
   ysghar ou y recadra mzian ou yt9ad. »

   Deux demandes, et la seconde est la vraie.

   ── 1. LE TEXTE D'UN CRAN PLUS PETIT

   La section 21 avait déjà descendu le corps à 13 px. On descend
   d'un cran de plus, mais PAR LES JETONS, pas écran par écran :
   `--fs-11` à `--fs-36` sont définis une fois et lus partout, donc
   les redéfinir ici descend tout l'OS d'un coup — les tableaux,
   les boutons, les panneaux, les formulaires.

   ⚠ ON NE DESCEND PAS LE CORPS SOUS 12 PX. En dessous, un texte
   courant cesse d'être lu et commence à être déchiffré. Ce qui
   fait gagner de la place ici, ce ne sont pas les 12 px du corps :
   ce sont les TITRES, qui étaient à 48 px.

   ── 2. LE TÉLÉPHONE — CE QUI ÉTAIT VRAIMENT CASSÉ

   Relevé dans la feuille, pas deviné :

     · `master-v2.css` impose au titre de page
       `clamp(30px, 3vw, 48px) !important`. Sur un écran de 390 px,
       3 vw ne vaut que 11,7 px, donc la borne basse gagne : le
       titre reste à 30 PX SUR UN TÉLÉPHONE. Un mot par ligne.

     · Sept grilles à nombre de colonnes FIXE n'avaient aucune
       règle sous 760 px : `.dash` (12 colonnes), `.mini-grille` et
       `.mois-grille` (7), `.universe-kpis` et `.sp-entonnoir` (4),
       `.etat-grille` et `.sp-mesures` (3). Douze colonnes dans
       390 px, ce sont des colonnes de 32 px.

     · Les jetons de texte descendent `--fs-16` sous 16 px. Sur
       iOS, un champ de saisie sous 16 px fait ZOOMER la page à la
       mise au point — l'écran part de travers dès qu'on touche un
       champ, et il faut le repincer pour revenir. C'est
       exactement « mkharbe9 », et ça n'a rien à voir avec le
       design : c'est une règle du navigateur.

   Les cinq onglets de SPIDER, les rails et le mur du Cercle sont
   traités aussi — mais ce sont les trois points ci-dessus qui
   font la différence entre un écran serré et un écran cassé.
   ============================================================= */

/* ── 43.1 LES JETONS DE TEXTE, D'UN CRAN ─────────────────────── */
:root {
  --fs-11: 10.5px;  --fs-12: 11px;   --fs-13: 12px;   --fs-14: 13px;
  --fs-16: 14.5px;  --fs-18: 16.5px; --fs-22: 18.5px; --fs-28: 22px;  --fs-36: 28px;
}
body { font-size: 12px; }

/* ⚠ LE TITRE DE PAGE ÉTAIT LE PLUS GROS POSTE. `master-v2.css` le
   pose en `!important` ; on ne peut le corriger qu'avec la même
   arme, depuis une feuille chargée après. De 48 px à 34 px au
   maximum : la page gagne une ligne et demie sans qu'on cesse de
   voir où l'on est. */
.main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1 {
  font-size: clamp(23px, 2.1vw, 34px) !important;
}
.page-head h1, .page-head > b:first-child { font-size: 25px; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-head h3 { font-size: 12.5px !important; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-head { min-height: 50px; padding: 11px 15px !important; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-body { padding: 14px 15px !important; }

/* Les tableaux : deux lignes de plus par écran. */
.table th { height: 40px !important; }
.table td { padding-block: 10px !important; }

/* Les grands nombres des deux moteurs suivent le même cran. */
.sp-tuile b { font-size: 25px; }
.sp-maillon b { font-size: 22px; }
.gal-titre { font-size: 14.5px; }
.c25-dossier h1 { font-size: clamp(24px, 3.4vw, 34px); }
.c25-carte-bas b { font-size: 13.5px; }

/* =============================================================
   43.2 LE TÉLÉPHONE
   ============================================================= */
@media (max-width: 560px) {

  /* ⚠ D'ABORD : PLUS RIEN NE DÉBORDE EN LARGEUR. Une page qui
     défile latéralement sur un téléphone donne l'impression que
     tout est cassé, même quand une seule grille dépasse.
     `clip` plutôt que `hidden` : `hidden` sur un ancêtre casse
     `position: sticky` des en-têtes de tableau. */
  .main { overflow-x: clip; }
  .page, .panel, .panel-body { min-width: 0; }

  /* ⚠ ET LE CHAMP DE SAISIE REPASSE À 16 PX. Ce n'est pas un
     choix de taille : sous 16 px, iOS zoome la page dès qu'on
     touche un champ. */
  input, select, textarea, .input, .select, .textarea {
    font-size: 16px !important;
  }

  /* Le titre de page tient sur deux lignes, pas sur cinq. */
  .main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1 {
    font-size: clamp(20px, 6.4vw, 26px) !important;
  }
  .page-head h1, .page-head > b:first-child { font-size: 21px; }
  .c25-dossier h1 { font-size: 24px; }

  /* La page et les panneaux se resserrent : sur 390 px, chaque
     pixel de marge est un mot qu'on ne lit pas. */
  .main > .page:not(.dashboard-home):not(.ps-root) { padding: 12px 12px 96px !important; }
  .main > .page:not(.dashboard-home):not(.ps-root) .panel-head { padding: 10px 12px !important; min-height: 44px; }
  .main > .page:not(.dashboard-home):not(.ps-root) .panel-body { padding: 10px 12px 12px !important; }

  /* ── LES GRILLES À NOMBRE DE COLONNES FIXE ──
     Aucune de celles-ci n'avait de règle sous 760 px. */
  .dash { grid-template-columns: 1fr !important; }
  .etat-grille, .sp-mesures, .universe-kpis, .sp-entonnoir, .sp-tuiles {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .c25-champs, .c25-board, .c25-videos, .galerie, .sp-cartes {
    grid-template-columns: 1fr !important;
  }
  /* Les calendriers gardent leurs sept colonnes — une semaine en
     a sept — mais leurs cases cessent d'imposer une largeur. */
  .mois-grille, .mini-grille { grid-template-columns: repeat(7, minmax(0, 1fr)); }
  .mois-grille > *, .mini-grille > * { min-width: 0; font-size: 10.5px; }

  /* ── LES ONGLETS SPIDER ──
     Cinq onglets sur une ligne de 390 px donnent 78 px chacun,
     donc du texte coupé. Ils passent à deux par rangée. */
  .sp-vue { flex: 1 1 44%; min-width: 0; padding: 9px 10px; font-size: 12px; }

  /* ── LES RAILS ET LE MUR ── */
  .filmo-case { flex: 0 0 82vw; }
  .board-col { flex: 0 0 86%; }
  .c25-toile { height: min(58vh, 480px); }
  .c25-outils { padding: 10px; gap: 6px; }
  .c25-outil { padding: 8px 11px; font-size: 12px; }
  .c25-outils-qui { margin-left: 0; width: 100%; }

  /* ── CE QU'ON TOUCHE AVEC UN DOIGT ──
     Un bouton de 32 px se rate une fois sur trois. Quarante-quatre
     pixels, c'est la hauteur d'un doigt, et c'est la seule chose
     de cette section qui GRANDIT au lieu de rétrécir. */
  .btn, .icon-btn, .chip, .sp-vue { min-height: 44px; }
  .icon-btn { min-width: 44px; }
}

/* Les très petits écrans — un iPhone SE fait 375 px, un Android
   d'entrée de gamme 360. */
@media (max-width: 380px) {
  .etat-grille, .sp-mesures, .universe-kpis, .sp-entonnoir, .sp-tuiles {
    grid-template-columns: 1fr !important;
  }
  .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .sp-vue { flex: 1 1 100%; }
  .main > .page:not(.dashboard-home):not(.ps-root) { padding: 10px 9px 96px !important; }
}

/* =============================================================
   44. LES FENÊTRES D'APERÇU, ET CE QUI LES REND PREMIUM
   9 septembre 2026

   Direction : « zid l quality ou les pop up f cercle ou spider ».

   ── À QUOI SERT UNE FENÊTRE D'APERÇU

   Elle répond à une question qu'un écran de liste pose sans y
   répondre : « lequel ? ». Devant vingt-trois couvertures ou
   derrière un nombre — « 10 sans commercial » — la réponse
   coûtait un changement d'écran, un retour, et la perte du filtre
   et de la position. L'aperçu la pose PAR-DESSUS : on regarde, on
   décide, Échap, et on est exactement là où on était.

   ⚠ ELLES NE MONTRENT RIEN DE CACHÉ, ET C'EST VOULU. Une fenêtre
   qui révélerait des informations qu'on ne voit nulle part
   ailleurs ferait de l'écran une devinette. Elles montrent en
   GRAND ce qu'une carte de 330 px ne peut pas montrer.

   ⚠ ET ELLES N'ÉCRIVENT RIEN. Franchir une porte, valider,
   appeler, noter : tout cela vit dans le dossier ou dans la fiche,
   avec les contrôles et le journal. Une deuxième façon d'écrire,
   c'est une deuxième règle qui finit par ne plus dire la même
   chose que la première.

   ── LE VERRE DE LA FENÊTRE

   La modale de l'OS était un bloc opaque posé sur un voile gris.
   Elle prend ici l'empilement du tableau de bord — voile flouté,
   fond en dégradé, liseré clair en haut, ombre large — plus un
   filet d'or qui se tire au moment de l'ouverture. C'est le même
   traitement partout : toutes les fenêtres de l'OS en profitent,
   pas seulement les deux nouvelles.
   ============================================================= */

/* ── LE VOILE ET LA BOÎTE ─────────────────────────────────────── */
.modal-scrim {
  background: rgba(3, 6, 10, .74);
  backdrop-filter: blur(10px) saturate(.9);
}
.modal {
  position: relative;
  border-radius: 20px;
  border: 1px solid var(--n-bord-fort);
  background: linear-gradient(168deg, rgba(19, 28, 40, .97), rgba(8, 13, 20, .98));
  box-shadow: 0 70px 130px -50px #000, inset 0 1px 0 rgba(255, 255, 255, .055);
  overflow: hidden;
}
/* Le filet d'or se tire en haut de la fenêtre à l'ouverture : le
   même geste que la barre d'étape sous une couverture. */
.modal::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 2px; z-index: 5;
  background: linear-gradient(90deg, var(--n-or), transparent 72%);
  transform-origin: 0 50%;
  animation: c25-tirer 720ms var(--m-vif) 120ms backwards;
}
.modal-head { padding: 15px 18px 12px; }
.modal-head h3 { font-size: 15px; font-weight: 700; letter-spacing: -.02em; }
.modal-foot { padding: 13px 18px; gap: 9px; }

/* ── L'ŒIL POSÉ SUR UNE AFFICHE ───────────────────────────────
   Il ne se montre qu'au survol de la carte : au repos, le mur
   reste un mur d'affiches, pas une planche de boutons. Au doigt,
   il n'y a pas de survol — il reste donc visible sous 900 px,
   sinon il serait inatteignable sur un téléphone. */
.gal-oeil {
  position: absolute; z-index: 4; right: 9px; bottom: 9px;
  width: 32px; height: 32px; display: grid; place-items: center;
  border-radius: 9px; cursor: pointer;
  border: 1px solid rgba(255, 255, 255, .18);
  background: rgba(5, 8, 13, .6); backdrop-filter: blur(8px);
  color: #fff; opacity: 0; transform: translate3d(0, 5px, 0);
  transition: opacity 240ms var(--m-doux), transform 240ms var(--m-ressort),
              background 240ms var(--m-doux), border-color 240ms var(--m-doux);
}
.gal-carte:hover .gal-oeil, .gal-carte:focus-within .gal-oeil,
.voie-carte:hover .gal-oeil, .voie-carte:focus-within .gal-oeil,
.gal-oeil:focus-visible { opacity: 1; transform: none; }
.gal-oeil:hover {
  background: rgba(5, 8, 13, .9);
  border-color: color-mix(in srgb, var(--dep, var(--n-cyan)) 60%, transparent);
  box-shadow: 0 0 22px -6px color-mix(in srgb, var(--dep, var(--n-cyan)) 80%, transparent);
}
.gal-oeil:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
@media (max-width: 900px), (hover: none) {
  .gal-oeil { opacity: 1; transform: none; }
}

/* ── LE CONTENU D'UN APERÇU DE DOSSIER ────────────────────────── */
.ap-boite { animation: c25-pop 380ms var(--m-ressort) backwards; }
.ap-cadre {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: 13px; margin-bottom: 14px; isolation: isolate;
  background: linear-gradient(160deg, #16202C, #070C12);
}
.ap-cadre .affiche, .ap-cadre img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block;
}
.ap-cadre::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(5,8,13,.5) 0%, transparent 40%,
                                       transparent 60%, rgba(5,8,13,.72) 100%);
}
.ap-kick {
  margin: 0 0 4px; font-family: var(--f-mono); font-size: 10px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--n-or);
}
.ap-titre { margin: 0 0 13px; font-size: 19px; font-weight: 700; letter-spacing: -.03em; }
.ap-faits {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(142px, 1fr));
  gap: 9px; margin: 0 0 13px;
}
.ap-fait {
  padding: 10px 12px; border-radius: 10px; border: 1px solid var(--n-bord);
  border-left: 2px solid var(--tn, var(--n-bord)); background: rgba(255, 255, 255, .022);
}
.ap-fait s {
  display: block; text-decoration: none; font-family: var(--f-mono); font-size: 9px;
  font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-3);
}
.ap-fait b { display: block; margin-top: 5px; font-size: 13px; font-weight: 600; letter-spacing: -.015em; }
.ap-cyan { --tn: var(--n-cyan); } .ap-or { --tn: var(--n-or); }
.ap-vert { --tn: var(--n-vert); } .ap-rouge { --tn: var(--n-rouge); }
.ap-barre { margin: 0 0 12px; }
.ap-note {
  margin: 0; padding: 11px 13px; border-radius: 10px;
  border: 1px solid rgba(120, 150, 190, .12); background: rgba(255, 255, 255, .022);
  font-size: 12.5px; line-height: 1.55; color: var(--n-tx-2);
}
.ap-note:empty { display: none; }

/* ── LA LISTE DERRIÈRE UNE TUILE DE SPIDER ────────────────────── */
.ap-liste { display: flex; flex-direction: column; gap: 6px; }
.ap-ligne {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
  grid-template-areas: "nom meta qui" "nom meta silence";
  align-items: center; gap: 2px 12px;
  width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--n-bord); border-left: 2px solid rgba(139, 92, 246, .45);
  background: rgba(255, 255, 255, .022);
  transition: transform var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux);
}
.ap-ligne:hover {
  transform: translate3d(0, -1px, 0);
  border-color: rgba(139, 92, 246, .5);
  box-shadow: -3px 0 20px -12px rgba(139, 92, 246, .9);
}
.ap-ligne:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.ap-l-nom { grid-area: nom; font-size: 13.5px; font-weight: 600; letter-spacing: -.015em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-l-meta { grid-area: meta; font-size: 11.5px; color: var(--n-tx-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-l-qui { grid-area: qui; justify-self: end; font-family: var(--f-mono); font-size: 10.5px; color: var(--n-tx-2); }
.ap-l-silence { grid-area: silence; justify-self: end; font-family: var(--f-mono); font-size: 10px; color: var(--n-tx-3); }
.ap-reste { margin: 12px 0 0; font-size: 12px; color: var(--n-tx-3); }
@media (max-width: 560px) {
  .ap-ligne { grid-template-columns: 1fr auto; grid-template-areas: "nom qui" "meta silence"; }
}

/* ── LA TUILE QUI S'OUVRE ─────────────────────────────────────
   Elle doit se distinguer d'une tuile ordinaire AVANT le clic,
   sinon on ne l'essaie jamais. Une loupe discrète en haut à
   droite, qui s'allume au survol — et le curseur qui change. */
.sp-tuile-ouvrable {
  display: block; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
}
.sp-loupe {
  position: absolute; top: 11px; right: 11px; z-index: 3;
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 7px;
  color: var(--n-tx-3); background: rgba(255, 255, 255, .03);
  border: 1px solid rgba(120, 150, 190, .12);
  transition: color var(--m-court) var(--m-doux), background var(--m-court) var(--m-doux),
              border-color var(--m-court) var(--m-doux), transform var(--m-court) var(--m-ressort);
}
.sp-tuile-ouvrable:hover .sp-loupe,
.sp-tuile-ouvrable:focus-visible .sp-loupe {
  color: var(--sp-tn, #C4B5FD);
  background: rgba(255, 255, 255, .06);
  border-color: color-mix(in srgb, var(--sp-lum) 45%, transparent);
  transform: translate3d(0, -1px, 0);
}
.sp-tuile-ouvrable:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .modal::before, .ap-boite { animation: none !important; }
  .modal::before { transform: none; }
  .gal-oeil, .ap-ligne, .sp-loupe { transition: none !important; opacity: 1; transform: none; }
}

/* =============================================================
   45. L'ÉNERGIE SUR TOUTE PAGE, ET UN CRAN DE TEXTE DE PLUS
   9 septembre 2026

   Direction : « zid kter f la quality ou zid saghaar les textes f
   l'OS kaml bach yb9a ybaan premium. Ou zid mzl plus d'effects :
   ay page dkhalty liha ykono fiha les effects ou les animations,
   comme ça donne l'énergie l'équipe ykhadmo bih, maykonch
   statique. »

   ── POURQUOI LES ÉCRANS RESTAIENT STATIQUES

   Les sections 39 à 44 ont traité SPIDER et CERCLE — deux écrans
   sur quarante-neuf. Congés, Factures, Salaires, Documents,
   Collaborateurs, Présence : rien. Et c'est là que l'équipe passe
   ses journées.

   ⚠ ET LE PREMIER DIAGNOSTIC ÉTAIT FAUX — LA MESURE L'A DIT.

   J'ai d'abord écrit que ces pages n'avaient AUCUNE animation, et
   j'ai posé une cascade d'entrée sur `.list-row` et sur
   `.tbl tbody tr`. Mesuré en direct sur Collaborateurs, la ligne
   répondait `animation-name: fondu` — pas la mienne.

   `components.css` ligne 560 pose déjà la cascade des lignes de
   tableau, et ligne 488 celle des lignes de liste. Elles étaient
   là depuis le début. Ma règle sur `.tbl tbody tr` REMPLAÇAIT une
   cascade de six paliers par une de quatorze, pour rien ; celle
   sur `.list-row` ne s'appliquait même pas, `.stack-list >
   .list-row` étant plus spécifique.

   Les deux sont retirées. Ce qui manquait vraiment n'était pas
   l'ARRIVÉE — elle existait — mais la LUMIÈRE : au survol, une
   ligne ne recevait qu'un aplat gris, un badge ne rayonnait pas,
   un chiffre clé n'avait pas de filet, un avatar ne s'allumait
   pas, un écran vide restait mort. C'est cela, et cela seul, que
   la suite ajoute.

   Cette section ne vise donc AUCUN écran en particulier. Elle
   traite les quatre briques — donc les quarante-neuf pages d'un
   coup, y compris celles qui n'existent pas encore.

   ── ⚠ CE QU'ON NE FAIT PAS, ET POURQUOI

   Une ligne de tableau n'est pas une affiche. Elle est lue par
   dizaines, à la verticale, souvent en cherchant une valeur
   précise. Donc : pas de zoom, pas de rebond, pas de déplacement
   horizontal — un tableau dont les lignes bougent devient
   impossible à parcourir du regard. Ce qu'elles reçoivent, c'est
   une ARRIVÉE (une fois, à l'affichage) et une LUMIÈRE au survol
   (le temps qu'on est dessus). Rien qui tourne en boucle.

   La cascade est PLAFONNÉE À QUATORZE lignes : au-delà, tout
   arrive ensemble. Sans ce plafond, la 120ᵉ ligne d'un pipeline
   entrerait trois secondes après la première.
   ============================================================= */

/* =============================================================
   45.1 LE TEXTE, UN CRAN DE PLUS
   ============================================================= */
:root {
  --fs-11: 10px;    --fs-12: 10.5px; --fs-13: 11.5px; --fs-14: 12.5px;
  --fs-16: 13.5px;  --fs-18: 15.5px; --fs-22: 17.5px; --fs-28: 21px;  --fs-36: 26px;
}
/* ⚠ 11,5 PX EST LE PLANCHER, ET IL EST TENU EXPRÈS. En dessous,
   un texte courant cesse d'être lu et commence à être déchiffré —
   et une équipe qui déchiffre son OS huit heures par jour finit
   par ne plus le lire du tout. La densité vient d'ailleurs : des
   titres, des marges et des hauteurs de ligne. */
body { font-size: 11.5px; }

.main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1 {
  font-size: clamp(21px, 1.9vw, 30px) !important;
}
.page-head h1, .page-head > b:first-child { font-size: 22px; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-head h3 { font-size: 11.5px !important; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-head { min-height: 46px; padding: 10px 14px !important; }
.main > .page:not(.dashboard-home):not(.ps-root) .panel-body { padding: 12px 14px !important; }
.main > .page:not(.dashboard-home):not(.ps-root) { padding: 20px 24px 44px !important; }
.table th { height: 36px !important; font-size: 10px !important; }
.table td { padding-block: 9px !important; }
.tbl tbody td { font-size: 11.5px; }
.sp-tuile b { font-size: 23px; }
.sp-maillon b { font-size: 20px; }
.gal-titre { font-size: 13.5px; }
.c25-dossier h1 { font-size: clamp(22px, 3vw, 31px); }

/* =============================================================
   45.2 LES QUATRE BRIQUES QUI PORTENT TOUT L'OS
   ============================================================= */

@keyframes os25-flotte {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -6px, 0); }
}

/* ── LA LIGNE DE LISTE ────────────────────────────────────────
   Elle arrive, puis son bord gauche s'allume quand on passe
   dessus. Le bord, pas le fond : sur une liste dense, un fond qui
   change fait clignoter tout le bloc au moindre mouvement de
   souris, tandis qu'un filet de deux pixels désigne sans crier. */
.list-row {
  position: relative;
  transition: background var(--m-court) var(--m-doux),
              box-shadow var(--m-court) var(--m-doux),
              border-color var(--m-court) var(--m-doux);
}
.list-row::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 2px;
  border-radius: 2px; background: var(--dep, var(--n-cyan));
  transform: scaleY(0); transform-origin: 50% 50%; opacity: .9;
  transition: transform 260ms var(--m-ressort);
}
.list-row:hover::before, .list-row:focus-within::before { transform: scaleY(1); }
.list-row:hover {
  box-shadow: -10px 0 26px -20px color-mix(in srgb, var(--dep, var(--n-cyan)) 90%, transparent);
}

/* ── LA LIGNE DE TABLEAU ──────────────────────────────────────
   Même principe, en plus discret encore : un tableau se parcourt
   à la verticale, et tout ce qui déborde de la ligne gêne cette
   lecture. */
.tbl tbody tr:hover td:first-child {
  box-shadow: inset 2px 0 0 var(--dep, var(--n-cyan));
}
.tbl tbody td { transition: color var(--m-court) var(--m-doux); }
.tbl tbody tr:hover td { color: var(--n-tx); }

/* ── L'ÉTIQUETTE ──────────────────────────────────────────────
   Un badge porte déjà sa couleur. Au survol de la ligne qui le
   contient, il la fait rayonner : c'est le repère qu'on cherche
   quand on parcourt une colonne de statuts. */
.badge, .pill {
  transition: box-shadow var(--m-court) var(--m-doux),
              border-color var(--m-court) var(--m-doux),
              transform var(--m-court) var(--m-ressort);
}
.list-row:hover .badge, .tbl tbody tr:hover .badge,
.badge:hover, .pill:hover {
  box-shadow: 0 0 18px -6px currentColor;
}

/* ── LE CHIFFRE CLÉ ───────────────────────────────────────────
   Les `.kpi` sont sur presque toutes les pages de direction. Ils
   reçoivent le filet du haut, comme les cartes du Cercle, et un
   halo sur le nombre lui-même — jamais sur la boîte. */
/* ⚠ PAS DE `overflow: hidden` SUR `.kpi` — LA SECTION 23 L'INTERDIT
   NOMMÉMENT, et pour une bonne raison : ces cartes laissent
   volontairement déborder une orbite, une pastille posée sur un
   bord, une ombre interne. Le filet est donc RENTRÉ de dix pixels
   à chaque extrémité : il ne touche jamais les angles arrondis, et
   il n'y a rien à rogner. */
.kpi { position: relative; }
.kpi::before {
  content: ""; position: absolute; top: 0; left: 10px; right: 10px; height: 2px; z-index: 3;
  background: linear-gradient(90deg, var(--dep, var(--n-or)), transparent 76%);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 520ms var(--m-vif);
}
.kpi:hover::before { transform: scaleX(1); }
.kpi b, .kpi .v {
  transition: text-shadow var(--m-moyen) var(--m-doux);
}
.kpi:hover b, .kpi:hover .v {
  text-shadow: 0 0 26px color-mix(in srgb, var(--dep, var(--n-or)) 62%, transparent);
}

/* ⚠ PAS DE REFLET SUR `.btn-primary` : IL EXISTE DEPUIS LE DÉBUT.

   J'allais en écrire un. `neon-systeme.css` ligne 546 et
   `neon.css` ligne 763 en posent déjà un, sur `::after`, avec
   `overflow: hidden` et `isolation: isolate`. Le mien aurait
   REMPLACÉ le leur — un effet identique, en moins bon, et un
   `z-index` en conflit avec l'isolation qui fait passer le reflet
   sous le texte.

   C'est la deuxième fois dans la même journée que je m'apprêtais à
   rajouter à côté de ce qui marchait déjà, au lieu de le brancher
   (l'autre : la lumière du curseur, qui existait et à laquelle il
   manquait six sélecteurs). La règle qui en sort : avant d'écrire
   un effet, chercher s'il est déjà là. */

/* ── LE CHAMP QUI PREND LE FOCUS ──────────────────────────────
   L'anneau ne se pose pas : il s'ouvre. C'est le seul retour
   qu'on a quand on tabule à l'aveugle dans un formulaire. */
.input, .select, .textarea {
  transition: border-color 200ms var(--m-doux), box-shadow 260ms var(--m-ressort),
              background 200ms var(--m-doux);
}
.input:focus, .select:focus, .textarea:focus,
.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  box-shadow: 0 0 0 3px rgba(37, 139, 255, .16), 0 0 22px -8px rgba(37, 139, 255, .8);
}

/* ⚠ PAS DE REFLET SUR `.progress` : IL EXISTE DÉJÀ AILLEURS.
   La section 25 en pose un sur `.barre > i`, `.jauge i`,
   `.eq-jauge i` et `.ll-charge i`. En ajouter un second sur le
   conteneur aurait demandé `overflow: hidden` — ce qui aurait
   rogné la lueur que `.tech-cockpit .progress > i` projette hors
   de sa barre. Un effet qui en casse un autre n'est pas un gain. */

/* ── L'AVATAR ─────────────────────────────────────────────────
   Il s'allume quand on survole la ligne : sur les écrans
   d'équipe, c'est le visage qu'on cherche, pas le nom. */
.avatar { transition: box-shadow var(--m-court) var(--m-doux), transform var(--m-court) var(--m-ressort); }
.list-row:hover .avatar, .tbl tbody tr:hover .avatar, .avatar:hover {
  transform: scale(1.06);
  box-shadow: 0 0 0 2px rgba(255,255,255,.09), 0 0 20px -6px var(--n-cyan);
}

/* ── L'ÉCRAN VIDE ─────────────────────────────────────────────
   Un écran qui n'a rien à montrer n'est pas une panne. Son icône
   flotte très lentement — six secondes par cycle — pour que le
   vide ait l'air d'attendre plutôt que d'être cassé. */
.empty .ico { animation: os25-flotte 6s ease-in-out infinite; }

/* ── LE SUR-TITRE ─────────────────────────────────────────────
   Un tiret de couleur devant, qui se tire à l'arrivée de la page.
   Trois pixels de haut ; c'est tout ce qu'il faut pour qu'un
   sur-titre cesse d'être une ligne grise. */
.eyebrow { position: relative; display: inline-flex; align-items: center; gap: 8px; }
.eyebrow::before {
  content: ""; width: 14px; height: 2px; border-radius: 2px; flex: none;
  background: var(--dep, var(--n-or));
  transform: scaleX(0); transform-origin: 0 50%;
  animation: c25-tirer 620ms var(--m-vif) 180ms backwards;
}

@media (prefers-reduced-motion: reduce) {
  .list-row, .tbl tbody tr, .list-row::before, .badge, .pill, .kpi::before,
  .avatar, .empty .ico, .eyebrow::before,
  .input, .select, .textarea {
    animation: none !important; transition: none !important;
  }
  .list-row::before { transform: scaleY(1); }
  .kpi::before, .eyebrow::before { transform: scaleX(1); }
}

/* =============================================================
   46. L'ONDE AU CONTACT, ET DEUX RESPIRATIONS
   9 septembre 2026

   Direction : « zid animer kter ».

   ⚠ AVANT D'ÉCRIRE, J'AI CHERCHÉ CE QUI EXISTAIT DÉJÀ — parce que
   trois fois aujourd'hui j'ai failli remplacer du bon code par du
   moins bon. Résultat de la recherche :

     · le reflet du bouton principal      → existe (neon-systeme 546)
     · la cascade des lignes de tableau   → existe (components 560)
     · le trait de lumière au changement
       de page                            → existe (section 25.1)
     · l'anneau doré au clic d'un bouton  → existe (section 23, mais
       il pulse au CENTRE et ne sert qu'aux boutons)
     · le repère doré du menu actif       → existe (shell 79)

   Ce qui manquait vraiment : l'onde qui part DU POINT TOUCHÉ. Et
   c'est le retour le plus important qui restait, parce que c'est
   le seul que le doigt reçoit. Au survol, une souris prépare le
   clic ; un doigt n'a rien avant que l'écran ne change. S'il
   change en 400 ms, ces 400 ms sont muettes, et on tape deux fois.
   ============================================================= */

.onde {
  position: absolute; inset: 0; z-index: 0;
  border-radius: inherit; overflow: hidden; pointer-events: none;
}
/* ⚠ LE DISQUE EST DANS UN CONTENEUR QUI LE ROGNE, ET NON L'INVERSE.
   Poser `overflow: hidden` sur la carte elle-même aurait rogné son
   orbite, ses pastilles de bord et ses ombres internes — la
   section 23 l'interdit nommément. Le conteneur de l'onde hérite
   du rayon et se rogne tout seul : la carte n'est pas touchée. */
.onde > i {
  position: absolute; left: var(--rx, 50%); top: var(--ry, 50%);
  width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.42), rgba(255,255,255,0) 70%);
  transform: scale(0);
  animation: os25-onde-clic 640ms var(--m-doux) forwards;
}
@keyframes os25-onde-clic {
  from { transform: scale(0);  opacity: .9; }
  to   { transform: scale(30); opacity: 0; }
}

/* ── LE SIGLE DU STUDIO ───────────────────────────────────────
   Douze secondes par cycle. C'est assez lent pour qu'on ne le
   remarque jamais en travaillant, et assez présent pour qu'un
   écran laissé ouvert ne ressemble pas à une capture d'écran.

   ⚠ IL EST DANS LE MENU, PAS DANS LE CONTENU. La règle « une
   seule chose respire » vaut par champ de vision : le repère
   « c'est ici » respire dans le contenu, le sigle respire dans la
   colonne de gauche. Les deux ne se disputent jamais l'œil. */
@keyframes os25-sigle {
  0%, 100% { filter: drop-shadow(0 0 14px rgba(242,185,64,.16)); }
  50%      { filter: drop-shadow(0 0 26px rgba(242,185,64,.34)); }
}
.brand-logo { animation: os25-sigle 12s ease-in-out infinite; }

/* ── L'ICÔNE DU MENU ACTIF ────────────────────────────────────
   Elle fait un pas en avant au moment où l'écran change. C'est ce
   qui relie le clic dans la colonne au contenu qui arrive à
   droite : sans lui, les deux moitiés de l'écran bougent sans
   avoir l'air de se parler. */
@keyframes os25-icone-active {
  0%   { transform: scale(.82); }
  55%  { transform: scale(1.16); }
  100% { transform: scale(1); }
}
.nav-item.is-active .ico { animation: os25-icone-active 480ms var(--m-ressort) 1; }

@media (prefers-reduced-motion: reduce) {
  .onde { display: none; }
  .brand-logo, .nav-item.is-active .ico { animation: none !important; }
}

/* =============================================================
   47. LE TEXTE POSÉ SUR UNE COUVERTURE
   9 septembre 2026

   Direction : « zid saghar chwiya, ghi texte li f couverture ».

   Seulement celui-là. Les titres sous les cartes, les tableaux et
   le corps de texte ne bougent pas — ils sont au plancher de
   11,5 px depuis la section 45.

   ── POURQUOI CES ÉTIQUETTES PARAISSAIENT GROSSES

   Elles n'avaient pas suivi. Le corps du texte est passé de 13 à
   12 puis à 11,5 px ; « Pré-production » et « 18 J DE RETARD »
   sont restées à 11 px avec 5 px de rembourrage vertical et 10 px
   de rembourrage latéral. Une pastille aussi haute que le titre
   du dossier qu'elle qualifie, posée sur une affiche de 200 px,
   finit par disputer l'image au lieu de la commenter.

   ⚠ ET ON NE DESCEND PAS PLUS BAS QUE 9,5 PX ICI. Ces étiquettes
   sont en majuscules sur une image : l'œil les lit d'un coup ou
   pas du tout. Sous ce seuil, « POST-PRODUCTION » sur une photo
   claire cesse d'être lisible, et le voile derrière ne suffit
   plus à la sauver.
   ============================================================= */

/* La pastille d'étape et l'alerte de retard, dans la galerie, la
   filmothèque, le tableau et la fenêtre d'aperçu. */
.gal-phase {
  padding: 3px 8px; gap: 5px;
  font-size: 9.5px; letter-spacing: .04em;
}
.gal-phase .point-sig { transform: scale(.86); }
.gal-alerte {
  padding: 3px 8px;
  font-size: 9.5px; letter-spacing: .04em;
}

/* Les mêmes, côté CERCLE : le code du livrable, l'étape et le
   retard posés sur la couverture d'un dossier. */
.c25-etape-puce, .c25-code {
  padding: 3px 7px; border-radius: 6px;
  font-size: 8.5px; letter-spacing: .1em;
}
.c25-retard {
  padding: 3px 7px; border-radius: 6px;
  font-size: 8.5px; letter-spacing: .09em;
}

/* Dans la fenêtre d'aperçu, la couverture fait le double : les
   étiquettes peuvent y reprendre un demi-point sans écraser
   l'image. */
.ap-cadre .gal-phase, .ap-cadre .gal-alerte { font-size: 10px; padding: 4px 9px; }

/* =============================================================
   48. LA COUVERTURE D'ACCUEIL, ET LES ANNEAUX QUI VIVENT
   9 septembre 2026

   Direction, cinq captures à l'appui :
     S1 · le rond « 02 » des étapes — qu'il tourne
     S2 · le cadran « 5 % » — qu'il tourne, avec une lumière
          douce au milieu, « b7ala life »
     S3 · le titre du projet prioritaire — plus grand
     S4 · le bloc en dessous — plus petit
     S5 · « Bonsoir Achraf » — au milieu, et plus petit

   ── ⚠ CE QUE J'AI TROUVÉ AVANT D'ÉCRIRE (S1 ET S2)

   Les anneaux TOURNENT DÉJÀ. `.anneau-boite::before` est une
   couronne pointillée à 22 s, `::after` un arc conique à 7 s,
   `.scene-cadran::before` un cercle à 14 s et `::after` un halo
   coloré à 44 s en sens inverse. Rien n'était immobile.

   Si la Direction demande « qu'ils tournent », c'est qu'à ces
   vitesses-là le mouvement ne se LIT pas : 22 secondes par tour,
   c'est un dixième de degré par image. On accélère donc la
   couronne (22 s → 15 s) au lieu d'en ajouter une cinquième, et
   surtout on ajoute ce qui manquait vraiment et qui était nommé
   dans la demande : LA LUMIÈRE AU CENTRE. Le cadran avait des
   anneaux autour et un trou noir au milieu.

   Pour S1, la couronne existait aussi — mais seulement sur
   l'étape en cours, et c'était voulu : « la rotation dit c'est
   ici ». La Direction la veut sur toutes. On la met sur toutes,
   en gardant la hiérarchie : l'étape en cours tourne vite et
   nettement, les autres lentement et à peine. L'information « où
   en est-on » survit, et tout bouge.
   ============================================================= */

/* ── S2 · LA LUMIÈRE AU CŒUR DU CADRAN ────────────────────────
   Une respiration lente derrière le chiffre. Elle est POSÉE SOUS
   le texte (`z-index: -1` sur un centre déjà positionné), sinon
   elle laverait le « 5 % » qu'elle est censée mettre en valeur. */
@keyframes os25-coeur {
  0%, 100% { opacity: .38; transform: scale(.94); }
  50%      { opacity: .72; transform: scale(1.04); }
}
.anneau-centre::before {
  content: ""; position: absolute; inset: 14%; z-index: -1; border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle,
    color-mix(in srgb, var(--dep, var(--n-cyan)) 34%, transparent) 0%,
    transparent 68%);
  animation: os25-coeur 5.5s ease-in-out infinite;
}
/* Le cadran du hero est le plus grand : sa lumière porte plus
   loin et respire un peu plus lentement. */
.scene-cadran .anneau-centre::before {
  inset: 6%;
  animation-duration: 7s;
  background: radial-gradient(circle, rgba(242,185,64,.3) 0%, rgba(18,217,255,.14) 42%, transparent 72%);
}
/* La couronne pointillée devient perceptible. */
.anneau-boite::before { animation-duration: 15s; }
.scene-cadran::before { animation-duration: 11s; }

/* ── S1 · TOUTES LES ÉTAPES TOURNENT ──────────────────────────
   La couronne n'était que sur l'étape en cours. Elle passe sur
   toutes — mais l'étape en cours garde l'avantage : deux fois
   plus rapide, deux fois plus visible. */
.c25-rond { position: relative; }
.c25-rond::before {
  content: ""; position: absolute; inset: -7px; border-radius: 50%;
  border: 1px dashed currentColor; opacity: .22;
  animation: os25-orbite 26s linear infinite;
  pointer-events: none;
}
.c25-jalon.ici .c25-rond::before { opacity: .5; animation-duration: 12s; }
/* Et une lumière au creux du rond — pas un pseudo-élément de
   plus : une ombre interne suffit, et elle n'ajoute aucun enfant
   dans un conteneur centré en flex, où une boîte vide de plus
   décalerait le chiffre. */
.c25-jalon .c25-rond {
  box-shadow: inset 0 0 12px -4px color-mix(in srgb, currentColor 55%, transparent);
}

/* ── S3 · LE TITRE DU PROJET PRIORITAIRE ──────────────────────
   « Le titre ykon kbir kter mn haka. » Il était retombé à 30 px
   quand le corps de texte est passé à 11,5 px : le titre d'une
   couverture pleine largeur ne suit pas le corps, il suit
   l'image. */
.dashboard-home .scene-titre,
.hero-solo .scene-titre,
.hero-scene .scene-titre {
  font-size: clamp(40px, 4.2vw, 68px) !important;
  line-height: .98 !important;
  letter-spacing: -.045em !important;
}

/* ── S4 · ET TOUT CE QUI EST DESSOUS SE RESSERRE ──────────────
   Le type de projet, la phrase d'action, les pastilles, le
   bouton et les vignettes : c'est la légende de l'image, pas son
   sujet. */
.scene-type { font-size: 11px !important; letter-spacing: .12em !important; }
.scene-phrase { font-size: 15px !important; margin-top: 4px !important; }
.scene-eyebrow { font-size: 9.5px !important; }
.scene-badge {
  font-size: 11px !important; padding: 6px 13px !important;
}
.scene-actions .btn-hero {
  font-size: 13px !important; padding: 11px 20px !important; min-height: 44px !important;
}
.scene-vignette { width: 78px !important; }
.scene-suite { gap: 9px !important; }

/* ── S5 · « BONSOIR ACHRAF » AU MILIEU ────────────────────────
   Elle était calée à gauche, sur `left: 48px; right: 200px` —
   les 200 px de droite réservaient la place du cadran. En la
   centrant sur toute la largeur, elle reste à distance du cadran
   (elle mesure environ 600 px au milieu de 1 400) et la
   couverture retrouve un axe. */
.dashboard-home .hero-coiffe > .command-head {
  left: 0 !important;
  right: 0 !important;
  padding: 0 24px !important;
  justify-content: center !important;
  text-align: center;
}
/* ⚠ MESURÉ : MA PREMIÈRE VALEUR L'AGRANDISSAIT AU LIEU DE LA
   RÉDUIRE. `clamp(20px, 1.7vw, 27px)` donnait 24,5 px sur un
   écran de 1 440, alors que la salutation en faisait 19,4 avant
   que j'y touche — la Direction demandait « tssghar chwiya ». La
   borne intermédiaire est ce qui compte : c'est elle qui gagne à
   cette largeur, pas les bornes. */
.hero-coiffe > .command-head .command-identity h1 {
  font-size: clamp(15px, 1.15vw, 20px) !important;
}
/* Sous 1 100 px, le cadran et la salutation se disputeraient la
   même bande : elle repasse à gauche, où elle a de la place. */
@media (max-width: 1100px) {
  .dashboard-home .hero-coiffe > .command-head {
    justify-content: start !important;
    text-align: left;
    padding: 0 20px !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  .anneau-centre::before, .c25-rond::before { animation: none !important; }
}

/* =============================================================
   49. LE TRANSFERT EN LOT, ET LA COUVERTURE QUI RESPIRE
   9 septembre 2026

   Direction : « possible n selectionnes bzaf dial les clients
   bach nbadel l commercial au cas de absence dial chi
   commercial ? » — oui, et c'est la partie utile de ce lot.
   Puis : « la couverture tros chargé, ziid saghar Bonjour Achraf
   ou ziid saghar les elements li ta7t texte. Khasso ykon lfar9 :
   tab9a tsswira twila, tal3a tal lfou9. »

   Une seule idée pour la couverture : L'IMAGE EST LE SUJET, LE
   TEXTE EST LA LÉGENDE. Elle gagne 100 px de haut, tout ce qui
   n'est pas le titre du projet perd un cran, et la salutation
   redescend encore — c'est un bonjour, pas un titre.
   ============================================================= */

/* ── LA BARRE DE TRANSFERT ────────────────────────────────────
   Elle n'existe que lorsqu'au moins une ligne est cochée : une
   barre d'actions affichée en permanence sur un tableau qu'on
   consulte plus souvent qu'on ne le modifie devient du décor. */
.sp-transfert {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 11px; padding: 10px 13px;
  border: 1px solid rgba(139, 92, 246, .34); border-radius: 12px;
  background: linear-gradient(100deg, rgba(139, 92, 246, .12), rgba(12, 19, 28, .92) 46%);
  box-shadow: 0 14px 34px -24px #000, inset 0 1px 0 rgba(255, 255, 255, .05);
  animation: os25-arrive 320ms var(--m-ressort) backwards;
}
.sp-transfert[hidden] { display: none; }
.sp-tr-n { font-size: 12.5px; font-weight: 700; letter-spacing: -.01em; color: #DDD1FF; }
.sp-tr-choix {
  padding: 8px 11px; border-radius: 9px; border: 1px solid var(--n-bord);
  background: #09111A; color: var(--n-tx); font: 600 12px var(--f-body); min-width: 190px;
}
.sp-tr-choix:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

/* La colonne des cases : étroite, et la case elle-même agrandie —
   on la vise au doigt autant qu'à la souris. */
.sp-tr-case { width: 38px; text-align: center; }
.sp-table-sel input[type="checkbox"] {
  width: 16px; height: 16px; cursor: pointer;
  accent-color: var(--n-violet, #8B5CF6);
}
/* Une ligne cochée se voit sans avoir à chercher sa case. */
.sp-table-sel tbody tr:has(input:checked) {
  background: rgba(139, 92, 246, .09);
}
.sp-table-sel tbody tr:has(input:checked) td:first-child {
  box-shadow: inset 2px 0 0 var(--n-violet, #8B5CF6);
}

/* ── LA COUVERTURE : PLUS D'IMAGE, MOINS DE TEXTE ─────────────
   Cent pixels de plus en hauteur. C'est la seule chose de cette
   section qui grandit. */
.dashboard-home .hero-scene {
  min-height: clamp(430px, 48vh, 580px) !important;
}

/* La salutation : c'est un bonjour, pas un titre. */
.hero-coiffe > .command-head .command-identity h1 {
  font-size: clamp(14px, 1vw, 18px) !important;
}
.hero-coiffe > .command-head .command-identity p { font-size: 10.5px !important; }
.hero-coiffe > .command-head .command-kicker { font-size: 9px !important; }
.hero-coiffe > .command-head .db-date { font-size: 11px !important; padding: 7px 13px !important; }
.hero-coiffe > .command-head > .avatar { width: 38px !important; height: 38px !important; }

/* Tout ce qui est sous le titre descend d'un cran de plus. Le
   titre du projet, lui, ne bouge pas : c'est lui le sujet. */
.scene-type { font-size: 10px !important; }
.scene-phrase { font-size: 13.5px !important; }
.scene-eyebrow { font-size: 9px !important; }
.scene-badge { font-size: 10.5px !important; padding: 5px 11px !important; }
.scene-actions .btn-hero,
.scene-actions .btn { font-size: 12.5px !important; padding: 10px 17px !important; min-height: 42px !important; }
.scene-vignette { width: 66px !important; }
.scene-suite { gap: 8px !important; }
.hero-solo .scene-corps { padding: 26px 34px 62px !important; }

/* =============================================================
   50. LA COUVERTURE : LA PHOTO PREND TOUTE LA PLACE, ET PLUS
       RIEN NE SE CHEVAUCHE
   9 septembre 2026

   Direction, trois captures : « chouf l Maalouma kifach mza7ma…
   chouf l Coach Amal hta howa kifach mza7em. Ta9der tkabar blassa
   dial tsswira, kabarha bach yb9a kolchi mzian. La photo tla3 tal
   lfou9, ou lktaba tji fou9 la photo. Dir hadchi ma tb9ach
   takhrba9 lia hna. Ou zid saghar kolchi ou kabar la photo. »

   ── ⚠ LE CHEVAUCHEMENT VIENT DE MOI, ET IL A DEUX CAUSES

   1. J'ai centré la salutation (section 48). Elle est en position
      absolue sur la couverture, à 30 px du haut. Tant qu'elle
      était calée à GAUCHE avec `right: 200px`, elle occupait une
      bande que le titre, plus bas, ne croisait pas. Centrée, elle
      est venue se poser pile au-dessus du titre du projet.

   2. Et surtout : `.dashboard-home .hero-scene { min-height:
      430px }`, écrit à la section 49, a la même spécificité que
      `.hero-solo .hero-scene { min-height: clamp(580px, 74vh,
      820px) }` — mais il est écrit APRÈS. Il a donc RÉTRÉCI la
      couverture pleine largeur de 580 à 430 px. Le titre s'est
      retrouvé à l'étroit, « MAALOUMA OUALFA » est passé sur deux
      lignes, et les deux lignes sont montées dans la salutation.

   J'ai fabriqué le problème en croyant agrandir l'image. La
   correction n'est donc pas un rustinage : la couverture pleine
   largeur reprend sa hauteur — et davantage, comme demandé — et
   le texte reçoit une BANDE RÉSERVÉE sous la salutation, qu'il ne
   peut plus franchir.
   ============================================================= */

/* ── LA PHOTO ─────────────────────────────────────────────────
   Pleine largeur, elle monte de 430 à 620 px minimum, jusqu'à
   900 sur un grand écran. C'est le seul élément de cette section
   qui grandit — tout le reste rétrécit. */
.hero-solo .hero-scene {
  min-height: clamp(620px, 78vh, 900px) !important;
}

/* ── LA BANDE RÉSERVÉE ────────────────────────────────────────
   124 px en haut : la salutation occupe de 26 à ~96 px, le titre
   commence après. Ce n'est pas un réglage à l'œil — c'est la
   hauteur mesurée du bloc salutation plus une marge de sécurité.

   Et le texte s'élargit : à 52 % de la largeur, « MAALOUMA
   OUALFA » ne tenait pas sur une ligne et passait à deux, ce qui
   est précisément ce qui l'a fait monter. */
.hero-solo .scene-corps {
  /* ⚠ MESURÉ : À 64 %, « MAALOUMA OUALFA » PASSAIT ENCORE SUR
     DEUX LIGNES. La couverture pleine largeur fait environ
     980 px ici, donc 64 % ne laissaient que 539 px de texte,
     quand ce nom-là en demande 640. À 78 %, les six projets de
     l'affiche tiennent sur une ligne — vérifié un par un. Le
     paragraphe, lui, reste bridé à 54 caractères plus bas : une
     ligne de texte courant longue de 700 px ne se lit plus. */
  max-width: min(1020px, 78%) !important;
  padding: 124px 44px 54px !important;
}
.dashboard-home .hero-coiffe > .command-head { top: 26px !important; }

/* ── ET TOUT LE RESTE RÉTRÉCIT ────────────────────────────────
   « Ghi saghar dakchi. » Le titre du projet ne bouge pas : c'est
   lui qu'on vient lire. Ce qui l'entoure devient une légende. */
.scene-eyebrow { font-size: 8.5px !important; letter-spacing: .18em !important; }
.scene-type { font-size: 9.5px !important; letter-spacing: .14em !important; }
.scene-phrase {
  font-size: 12px !important; line-height: 1.45 !important;
  max-width: 54ch !important; margin-top: 8px !important;
}
.scene-badge { font-size: 9.5px !important; padding: 4px 10px !important; }
.scene-actions { gap: 8px !important; }
.scene-actions .btn-hero,
.scene-actions .btn {
  font-size: 11.5px !important; padding: 9px 15px !important; min-height: 38px !important;
}
.scene-vignette { width: 48px !important; }
.scene-suite { gap: 6px !important; }

/* ⚠ SAUF AU DOIGT. Un bouton de 38 px se rate sur un téléphone —
   la règle des 44 px de la section 43 reprend la main ici, parce
   que cette section-ci est écrite après elle. */
@media (max-width: 560px) {
  .scene-actions .btn-hero,
  .scene-actions .btn { min-height: 44px !important; font-size: 12.5px !important; }
  /* Sur un écran étroit, la salutation est déjà repassée à gauche
     (section 48) : la bande réservée n'a plus lieu d'être aussi
     haute, et chaque pixel compte. */
  .hero-solo .scene-corps { padding: 88px 18px 44px !important; max-width: 100% !important; }
  .hero-solo .hero-scene { min-height: clamp(520px, 70vh, 680px) !important; }
}

/* =============================================================
   51. LE BAS DE L'ACCUEIL — INDICATEURS, MOT DU JOUR, AGENDA
   9 septembre 2026

   Direction : « l'agenda diha a droite ou tla3 lina l'agenda
   reel, machi ghir textes, nchofo agenda du mois… l'indicateur
   yjiw a gauche ou y animaw chwiya… hadak l msg de "créer" ykon
   ki3ti l kola wahd un msg du jour… fach kital3o les msgs
   katwali flou, katrja3 m9ada, automatique, kola 5 s… ou hada
   fach ykon 100 % khas tab9a t clignote bel lkhder. »
   ============================================================= */

/* ── LE CADRAN PLEIN CLIGNOTE ─────────────────────────────────
   ⚠ C'EST LA DEUXIÈME CHOSE QUI RESPIRE EN CONTINU DANS L'OS, ET
   ELLE EST JUSTIFIÉE : un dossier à 100 % est un dossier qu'on
   peut livrer AUJOURD'HUI. À côté d'un dossier à 97 %, il ne se
   distinguait par rien. Le vert et le battement disent « celui-là
   est prêt, prends-le ».

   Il bat lentement — deux secondes et demie — pour appeler sans
   harceler. */
@keyframes os25-plein {
  0%, 100% { filter: drop-shadow(0 0 6px rgba(36, 217, 129, .45)); opacity: .95; }
  50%      { filter: drop-shadow(0 0 22px rgba(36, 217, 129, .95)); opacity: 1; }
}
.anneau.an-plein .an-arc { stroke: #24D981 !important; }
.anneau.an-plein { animation: os25-plein 2.5s ease-in-out infinite; }
.anneau-boite:has(.an-plein) .anneau-centre b { color: #8FE9BC; }

/* ── LES INDICATEURS, À GAUCHE, ET QUI ARRIVENT ───────────────
   « y animaw chwiya » : les quatre tuiles se posent l'une après
   l'autre. Le halo et le filet sont déjà là (section 45). */
.db-kpis > *, .kpi-grille > * { animation: os25-arrive 400ms var(--m-vif) backwards; }
.db-kpis > *:nth-child(2), .kpi-grille > *:nth-child(2) { animation-delay: 70ms; }
.db-kpis > *:nth-child(3), .kpi-grille > *:nth-child(3) { animation-delay: 140ms; }
.db-kpis > *:nth-child(4), .kpi-grille > *:nth-child(4) { animation-delay: 210ms; }

/* ── LE MOT DU JOUR ───────────────────────────────────────────
   Le flou est court — 260 ms de sortie, 260 ms de retour — et il
   ne porte que le texte, jamais le fond ni le sigle : flouter un
   panneau entier toutes les cinq secondes ferait vibrer tout le
   bas de l'écran. */
.mot-jour { position: relative; overflow: hidden; }
.mot-corps {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; justify-content: center;
  gap: 10px; padding: 30px 30px 54px; min-height: 210px;
  transition: filter 260ms var(--m-doux), opacity 260ms var(--m-doux),
              transform 260ms var(--m-doux);
}
.mot-corps.mot-flou { filter: blur(9px); opacity: .12; transform: translate3d(0, -5px, 0); }
.mot-kick {
  margin: 0; font-family: var(--f-mono); font-size: 9px; font-weight: 700;
  letter-spacing: .22em; text-transform: uppercase; color: var(--n-or);
}
.mot-texte {
  margin: 0; font-size: 16.5px; font-weight: 600; line-height: 1.45;
  letter-spacing: -.02em; color: var(--n-tx); max-width: 34ch;
  text-wrap: balance;
}

/* ── L'AGENDA DU MOIS ─────────────────────────────────────────
   Sept colonnes, lundi en tête. Les cases n'ont pas de largeur
   fixe : elles se partagent la place, donc la grille tient dans
   la colonne comme sur un téléphone. */
.db-agenda .panel-body { padding-top: 8px; }
.ag-entete, .ag-grille {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px;
}
.ag-entete {
  margin-bottom: 6px;
  font-family: var(--f-mono); font-size: 9px; font-weight: 700;
  letter-spacing: .12em; color: var(--n-tx-3); text-align: center;
}
.ag-case {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 2px 5px; min-height: 40px; cursor: pointer;
  border: 1px solid transparent; border-radius: 9px; background: transparent;
  color: var(--n-tx-2); font: inherit;
  transition: background var(--m-court) var(--m-doux), border-color var(--m-court) var(--m-doux),
              color var(--m-court) var(--m-doux);
}
.ag-case.ag-hors { cursor: default; }
.ag-n { font-family: var(--f-mono); font-size: 11px; font-variant-numeric: tabular-nums; }
.ag-pts { display: flex; gap: 2px; }
.ag-pts i { width: 4px; height: 4px; border-radius: 50%; background: currentColor; }
.ag-case.ag-plein { color: var(--n-tx); }
.ag-case:hover { background: rgba(255, 255, 255, .04); border-color: var(--n-bord); }
.ag-case.ag-today { border-color: rgba(242, 185, 64, .45); color: var(--n-or); }
.ag-case.ag-on {
  background: rgba(18, 217, 255, .1);
  border-color: rgba(18, 217, 255, .45);
  color: #fff;
  box-shadow: 0 0 18px -8px rgba(18, 217, 255, .9);
}
.ag-case:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

.ag-detail {
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--n-bord);
  display: flex; flex-direction: column; gap: 6px;
  animation: os25-arrive 300ms var(--m-vif) backwards;
}
.ag-item { display: flex; align-items: center; gap: 9px; font-size: 12px; }
.ag-h { flex: none; width: 38px; font-size: 10.5px; color: var(--n-tx-3); }
.ag-t { min-width: 0; }
.ag-vide { margin: 2px 0 0; font-size: 12px; }

@media (prefers-reduced-motion: reduce) {
  .anneau.an-plein, .db-kpis > *, .kpi-grille > *, .ag-detail { animation: none !important; }
  .mot-corps { transition: none !important; }
  .mot-corps.mot-flou { filter: none; opacity: 1; transform: none; }
}

/* =============================================================
   52. LA COUVERTURE — REMISE D'APLOMB
   9 septembre 2026

   Direction : « ma9aditihach zwina… raja3 Achraf a gauche, ou
   saghar la photo chwiya, ou dok les boutons dial la date li hda
   Achraf dihom a gauche lfou9, ou douk les slides dial la photos
   sagharhom chwiya ou dihom a droite lta7t. »

   ── ⚠ CE QUE J'AVAIS CASSÉ, ET C'EST LA MÊME ERREUR DEUX FOIS

   J'ai centré la salutation à la section 48 parce qu'on me
   demandait de la mettre « au milieu ». Elle s'est retrouvée
   suspendue au-dessus du vide, au centre d'une image de 620 px,
   sans rien pour l'accrocher — et le titre du projet est resté en
   bas à gauche. Deux blocs de texte, deux coins opposés, aucun
   axe commun : une composition n'a pas de centre parce qu'on a
   centré un de ses éléments.

   Et les vignettes : `master-v2.css` leur pose
   `left: 42px; right: 30px`, donc elles s'étalaient sur toute la
   largeur et leur contenu se rangeait à gauche, sous le texte.
   Trois choses empilées dans le coin bas-gauche, et deux coins
   vides à droite.

   ── LA COMPOSITION, MAINTENANT

       ┌──────────────────────────────────────────────┐
       │ salutation · chaîne · date        cadran %   │
       │                                              │
       │ PROJET PRIORITAIRE                           │
       │ D-CAP                                        │
       │ publicité · action · pastilles · boutons     │
       │                                   vignettes  │
       └──────────────────────────────────────────────┘

   Quatre coins occupés, un seul axe de lecture à gauche, et
   l'image respire au milieu. C'est tout ce qu'il fallait.
   ============================================================= */

/* ── LA SALUTATION REVIENT À GAUCHE, AVEC SES BOUTONS ─────────
   La chaîne BORN—SPIDER—CERCLE et la date sont ses voisines dans
   la même grille : elles la suivent sans qu'on ait à les
   déplacer une par une. */
.dashboard-home .hero-coiffe > .command-head {
  left: 40px !important;
  right: auto !important;
  top: 24px !important;
  padding: 0 !important;
  justify-content: start !important;
  text-align: left;
}

/* ── LA PHOTO REDESCEND D'UN CRAN ────────────────────────────
   620 px, c'était une affiche de cinéma pour un écran de
   travail : il fallait faire défiler pour atteindre le Cercle.
   520 px laissent l'image dominer sans avaler la page. */
.hero-solo .hero-scene {
  min-height: clamp(480px, 58vh, 620px) !important;
}

/* Le bloc de texte n'a plus besoin de sa bande de sécurité : la
   salutation n'est plus au-dessus de lui, elle est à côté, en
   haut. Il retrouve un aplomb normal et l'image reprend l'espace
   que la bande lui prenait. */
.hero-solo .scene-corps {
  padding: 34px 44px 58px !important;
}

/* ── LES VIGNETTES : EN BAS À DROITE, ET PLUS PETITES ─────────
   ⚠ `left: auto` EST LA LIGNE QUI COMPTE. Tant que `left` et
   `right` sont posés tous les deux, la boîte est ÉTIRÉE d'un
   bord à l'autre et son contenu se range à gauche — la mettre
   « à droite » en ne touchant qu'à `right` n'aurait rien changé
   du tout. */
.scene-suite {
  left: auto !important;
  right: 26px !important;
  bottom: 20px !important;
  width: auto !important;
}
.scene-vignette { width: 48px !important; height: 32px !important; }
.scene-suite .scene-fleche { width: 30px !important; height: 30px !important; }

@media (max-width: 760px) {
  /* Sur un téléphone, le coin bas-droit est déjà pris par le
     bouton de l'assistant : les vignettes repassent en dessous du
     texte, sur toute la largeur. */
  .scene-suite {
    left: 16px !important; right: 16px !important; bottom: 14px !important;
  }
  .hero-solo .scene-corps { padding: 26px 18px 74px !important; }
}

/* =============================================================
   53. LA CITATION TIENT LA JOURNÉE, LE PLANNING DÉFILE,
       ET LES LUMIÈRES NE SE COUPENT PLUS
   9 septembre 2026

   Direction : « le citation yb9aw, nhar kaml citation du jour
   tkon 3and l'équipe kamla. Ou l'agenda hia li fiha les msgs dial
   l planning, kidozo kola 5 s ou kimchiw. Ou lights li kidoz f
   couverture makamlinch, fihom bugs, kit9at3o — khali light ydouz
   hta f titre bohdo ou t'anime bchwiya. Ou dik 100 % majatch
   zwina : dirha katch3al ou katfa bel vert. »
   ============================================================= */

/* ── ⚠ LA LAME DE LUMIÈRE NE PASSAIT QU'UNE FOIS ──────────────
   Elle était écrite `animation: os25-lame 1400ms … 1` : UNE
   passe, au chargement, puis plus rien. Le commentaire d'origine
   disait « l'élément est recréé à chaque rendu de la scène » —
   sauf que le carrousel ne remplace que le CORPS de la scène, pas
   le voile. Donc au premier projet la lumière passait, et aux
   cinq suivants elle ne repassait jamais. Vue une fois puis
   disparue : c'est exactement ça, « kit9at3o ».

   Elle boucle maintenant, lentement. La reprise est invisible
   parce que les deux extrémités de la course placent la bande
   claire HORS du cadre : à 55 % elle est déjà sortie à gauche, et
   elle y reste jusqu'à la fin du cycle. Le saut de fin de boucle
   se produit donc pendant que rien n'est visible. */
.hero-scene .scene-voile::after {
  animation: os25-lame 9s var(--m-doux) infinite !important;
}
@keyframes os25-lame {
  0%   { background-position: 200% 0; }
  55%  { background-position: -100% 0; }
  100% { background-position: -100% 0; }
}

/* ── UNE LUMIÈRE RIEN QUE POUR LE TITRE ───────────────────────
   Sept secondes par passage, décalée de trois secondes sur celle
   de la couverture : les deux ne se croisent jamais au même
   endroit, sinon on verrait une seule grosse lueur au lieu de
   deux gestes.

   ⚠ `plus-lighter` PLUTÔT QU'UN DÉGRADÉ SUR LE TEXTE. Découper la
   lumière dans les lettres (`background-clip: text`) obligerait à
   passer la couleur du titre en `transparent` — et le titre
   perdrait son ombre portée, celle qui le rend lisible sur une
   photo claire. Ici on AJOUTE de la lumière par-dessus, sans
   toucher ni à la couleur ni à l'ombre.

   Et pas de `overflow: hidden` : sur un titre de 60 px, il
   rognerait les jambages des lettres. La bande est un dégradé
   doux qui déborde sans bord visible. */
.scene-titre { position: relative; }
.scene-titre::after {
  content: ""; position: absolute; inset: -10px -24px; z-index: 1;
  pointer-events: none;
  background: linear-gradient(100deg,
    transparent 40%, rgba(255,255,255,.26) 50%, transparent 60%);
  background-size: 280% 100%;
  mix-blend-mode: plus-lighter;
  animation: os25-lame-titre 7s var(--m-doux) 3s infinite;
}
@keyframes os25-lame-titre {
  0%   { background-position: 190% 0; }
  48%  { background-position: -90% 0; }
  100% { background-position: -90% 0; }
}

/* ── LE 100 % S'ALLUME ET S'ÉTEINT ───────────────────────────
   La version d'avant ne faisait varier qu'une ombre portée — de
   loin, ça ne se voyait pas. C'est l'ARC lui-même qui s'allume et
   s'éteint maintenant, en vert, pendant que la boîte garde une
   lueur verte fixe pour qu'il reste quelque chose entre deux
   battements. */
.anneau.an-plein { animation: none !important; }
.anneau.an-plein .an-arc {
  stroke: #24D981 !important;
  animation: os25-allume-eteint 1.9s ease-in-out infinite;
}
@keyframes os25-allume-eteint {
  0%, 100% { opacity: .18; }
  50%      { opacity: 1; }
}
.anneau-boite:has(.an-plein) {
  filter: drop-shadow(0 0 16px rgba(36, 217, 129, .45));
}

/* ── LE BANDEAU DU PLANNING, DANS L'AGENDA ───────────────────
   Il sort par la gauche, la ligne change hors champ, il revient
   par la droite. On ne voit jamais le remplacement — seulement un
   défilement. */
.ag-fil {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 12px; padding: 9px 12px;
  border: 1px solid var(--n-bord); border-left: 2px solid var(--n-cyan);
  border-radius: 10px; background: rgba(18, 217, 255, .05);
  font-size: 11.5px; overflow: hidden;
}
.ag-fil-t {
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--n-tx);
  transition: transform 300ms var(--m-doux), opacity 300ms var(--m-doux);
}
.ag-fil-sort .ag-fil-t  { transform: translate3d(-22px, 0, 0); opacity: 0; }
.ag-fil-entre .ag-fil-t { transform: translate3d(22px, 0, 0); opacity: 0; transition: none; }

/* La citation ne tourne plus : elle n'a plus besoin d'un flou de
   transition, seulement de place pour être lue. */
.mot-corps { min-height: 190px; }
.mot-texte { font-size: 17px; }

@media (prefers-reduced-motion: reduce) {
  .hero-scene .scene-voile::after,
  .scene-titre::after,
  .anneau.an-plein .an-arc { animation: none !important; }
  .scene-titre::after { display: none; }
  .anneau.an-plein .an-arc { opacity: 1; }
  .ag-fil-t { transition: none !important; }
}

/* Le repère qui conduit à SPIDER : même forme que ses voisins,
   violet parce que c'est la couleur de l'autre moteur, et un
   soulignement qui n'apparaît qu'au survol — un repère n'est pas
   un bouton. */
.c25-r-violet { --tn: var(--n-violet); }
.c25-repere-lien { text-decoration: none; cursor: pointer; }
.c25-repere-lien b { border-bottom: 1px solid transparent; transition: border-color var(--m-court) var(--m-doux); }
.c25-repere-lien:hover b { border-bottom-color: currentColor; }
.c25-repere-lien:hover {
  border-left-color: var(--n-violet);
  box-shadow: -3px 0 22px -12px rgba(139, 92, 246, .95);
}
.c25-repere-lien:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

/* =============================================================
   54. MOINS DE GRAS, ET LA LUMIÈRE DANS LES LETTRES
   9 septembre 2026

   Direction : « kayn bzaf dial les textes f gras, visuellement
   majawch zwinin — rja3hom normal ou light. Ou les effects light
   li kidouz mn taht mn titre 7aydo, mazwinch : ana hdart 3la
   titre nit ykon kiouz fih dou. »
   ============================================================= */

/* ── LE GRAS N'EST PLUS LE RÉGLAGE PAR DÉFAUT ────────────────
   ⚠ UN SEUL LEVIER, ET IL EST BIEN CHOISI. `<b>` sert partout
   dans cet OS à porter une VALEUR — un nom, un compte, une date.
   Le navigateur lui donne 700 d'office, donc chaque valeur de
   chaque ligne de chaque tableau criait aussi fort qu'un titre :
   sur un écran dense, tout est gras, donc plus rien ne ressort.

   La balise passe à 500. Ce n'est pas une perte de hiérarchie —
   c'est elle qui revient : les quelques éléments qui DOIVENT
   crier portent déjà un poids explicite dans leur propre règle
   (`.kpi b`, `.sp-tuile b`, `.scene-titre`…), et un sélecteur de
   classe bat un sélecteur de balise. Ils gardent donc leur gras,
   et ils sont désormais les seuls à l'avoir. */
b, strong { font-weight: 500; }

/* Les libellés de structure descendent d'un cran : ils situent,
   ils ne s'annoncent pas. */
.eyebrow { font-weight: 600; }
.panel-head h3 { font-weight: 600 !important; }
.badge, .pill, .chip { font-weight: 500; }
.gal-titre, .ap-l-nom, .sp-ent, .mot-texte { font-weight: 500; }
.tbl thead th { font-weight: 600; }

/* Ce qui doit rester fort le reste : les grands nombres et les
   titres. On le redit ici pour que la règle soit lisible d'un
   seul endroit plutôt que déduite de la cascade. */
.kpi b, .kpi .v, .sp-tuile b, .sp-maillon b, .universe-kpi b,
.scene-titre, .page-head h1, .c25-dossier h1, .porte-chiffre b { font-weight: 800; }
.ag-n, .mono, .sp-num { font-weight: 500; }

/* ── LA LUMIÈRE PASSE DANS LES LETTRES ───────────────────────
   La bande qui tournait AUTOUR du titre est retirée : elle
   éclairait le fond, pas le mot.

   ⚠ LE CALQUE EST UNE COPIE EXACTE DU TITRE, POSÉE DESSUS. Il
   porte le même texte (`attr(data-titre)`), la même police et la
   même graisse — donc il se superpose au pixel près. Sa couleur
   est transparente et son fond est découpé dans le texte : seule
   la bande claire se voit, et elle se voit DANS les lettres.

   Le `h2` en dessous n'a pas bougé : couleur pleine, ombre
   portée, lisible sur n'importe quelle photo. */
/* ⚠ TROIS VERROUS, PARCE QU'UN TITRE INVISIBLE EST PIRE QUE PAS
   D'EFFET DU TOUT.

   Direction, dans la foulée : « rad lbal, titre radom baydin dial
   l couverture ». Le calque est transparent PARTOUT SAUF sous la
   bande de lumière — mais il se pose sur le titre, et tout ce qui
   se pose sur un titre peut le masquer si une seule des
   conditions n'est pas réunie. Donc :

     1. `[data-titre]` — pas d'attribut, pas de calque. Les
        `.scene-titre` d'autres écrans ne sont jamais touchés.
     2. `@supports` — si le navigateur ne sait pas découper un
        fond dans du texte, le dégradé remplirait la boîte
        ENTIÈRE par-dessus le titre. Sans le support, pas de
        calque du tout.
     3. Le calque n'a AUCUNE couleur de fond propre et son texte
        est transparent : même mal placé, il ne peut rien cacher —
        il ne peut qu'ajouter de la lumière.

   Le `h2` en dessous garde sa couleur pleine et son ombre : c'est
   lui qu'on lit, en toutes circonstances. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .scene-titre[data-titre]::after {
    content: attr(data-titre);
    position: absolute; inset: 0; z-index: 1;
    pointer-events: none;
    font: inherit; letter-spacing: inherit; line-height: inherit;
    white-space: pre-wrap;
    background-color: transparent;
    background-image: linear-gradient(100deg,
      transparent 40%, rgba(255,255,255,.7) 50%, transparent 60%);
    background-size: 260% 100%;
    background-repeat: no-repeat;
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    animation: os25-lame-titre 6s var(--m-doux) 2s infinite;
  }
}

@keyframes os25-lame-titre {
  0%   { background-position: 180% 0; }
  46%  { background-position: -80% 0; }
  100% { background-position: -80% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .scene-titre[data-titre]::after { display: none; }
}

/* =============================================================
   55. L'ÉCRAN ÉQUIPE À QUATRE ONGLETS
   9 septembre 2026

   Quatre écrans rassemblés en un. La barre d'onglets est celle de
   SPIDER — `.sp-vues` — et c'est voulu : un OS qui invente une
   barre d'onglets par écran oblige à réapprendre le même geste
   trois fois.
   ============================================================= */
.equipe-une .sp-vues { margin-bottom: 16px; }
.equipe-une .sp-vue { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.equipe-une .sp-vue .ico { opacity: .8; }

/* La vue chargée perd son statut de page : plus de marge de page,
   plus d'animation d'entrée de page — elle est un contenu, pas un
   écran. */
.eq-vue { padding: 0 !important; max-width: none !important; animation: none !important; }
.eq-vue > .page-head { display: none; }
.eq-corps { animation: c25-fondu 340ms var(--m-vif) backwards; }
.eq-attente { padding: 44px 0; opacity: .7; }

/* ============================================================================
   56 — ÉCRIRE DEPUIS L'OS
   10 septembre 2026

   Trois habits pour un seul geste nouveau : le bouton « Écrire »
   de la fiche SPIDER, celui du dossier CERCLE, et la fenêtre qui
   s'ouvre derrière les deux.

   ⚠ CES DEUX BOUTONS SONT DES `<button>`, PAS DES `<a>`. Ils
   ouvrent une fenêtre, ils ne mènent nulle part — un lien aurait
   proposé « ouvrir dans un nouvel onglet » sur un clic droit, et
   ce menu n'aurait rien fait. Mais `.sp-canal` a été écrit pour
   des liens : sans les trois lignes de remise à zéro ci-dessous,
   le navigateur y remet sa police système, son fond gris et son
   texte centré, et le troisième canal ne ressemble plus aux deux
   autres.
   ========================================================================== */

.sp-canal-mail {
  font: inherit; text-align: left; cursor: pointer;
  color: inherit; appearance: none;
}
.sp-canal-mail b { color: #C9B6FF; }
.sp-canal-mail:hover {
  transform: translateY(-2px); border-color: rgba(167,139,250,.5);
  box-shadow: 0 0 0 3px rgba(167,139,250,.1);
}

/* Le bouton du dossier : discret dans la ligne des faits, il
   s'allume au survol comme les autres objets du Cercle. */
.c25-ecrire {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.028);
  color: var(--n-tx-2); font: 500 12.5px var(--f-body);
  transition: transform .16s ease, border-color .16s ease,
              box-shadow .16s ease, color .16s ease;
}
.c25-ecrire .ico { opacity: .8; }
.c25-ecrire:hover {
  transform: translateY(-1px); color: var(--n-tx);
  border-color: rgba(18,217,255,.45);
  box-shadow: 0 0 0 3px rgba(18,217,255,.09);
}
.c25-ecrire:active { transform: translateY(0); }

/* La fenêtre. Le message est la pièce principale : il occupe la
   place, l'objet et l'adresse tiennent sur une ligne chacun. */
.ecr-corps { display: flex; flex-direction: column; gap: 2px; }
.ecr-corps .field { margin-bottom: 12px; }
.ecr-corps textarea { min-height: 190px; line-height: 1.6; }
.ecr-corps .hint { margin: 2px 0 0; line-height: 1.55; }
.ecr-corps .hint.attention { color: #FFC48A; }
.ecr-secours { margin-top: 10px !important; }

@media (max-width: 560px) {
  .ecr-corps textarea { min-height: 140px; }
  .c25-ecrire { padding: 6px 11px; font-size: 12px; }
}

/* ============================================================================
   57 — LES ALERTES VIVANTES
   10 septembre 2026

   Direction : « 3la chkal inDrive : fach kital3o douk les msgs, les
   réponses dial les drivers ybdaw ytal3o à gauche fou9 l'écran,
   animé, ou fihom lights katch3al. Même avec les commerciaux :
   katla3 ghir sghira à droite dial l'écran, tkon à l'instant. »

   ⚠ LA SCÈNE NE PREND AUCUN CLIC. `pointer-events: none` sur le
   cadre, `auto` sur les cartes seulement. Sans ça, deux bandes
   invisibles couvriraient toute la hauteur de l'écran et
   avaleraient les clics du menu et de la page — un défaut
   invisible qui rend l'OS inutilisable sans qu'on comprenne
   pourquoi.

   ⚠ ET ELLE PASSE SOUS LES FENÊTRES. z-index 65 : au-dessus de
   l'en-tête (40) et du menu (50), sous les modales (70) et les
   messages (80). Une carte d'alerte par-dessus une confirmation
   couvrirait le bouton qu'elle vient de demander de cliquer.
   ========================================================================== */

.al-scene {
  position: fixed; inset: 0; z-index: 65;
  pointer-events: none;
}
.al-rail {
  position: absolute; display: flex; flex-direction: column; gap: 10px;
  width: min(340px, calc(100vw - 32px));
}
/* À gauche, sous l'en-tête, décalé du menu : ce qui vient d'arriver. */
/* ⚠ LE RAIL SUIT LE MENU, MÊME REPLIÉ. `--sidebar-w` est la
   largeur réelle du menu ; repliée, la coque passe à
   `--sidebar-w-collapsed` et le rail doit suivre, sinon les
   cartes flottent au-dessus de la page au lieu de la longer. */
.al-rail-g { top: 74px; left: calc(var(--sidebar-w) + 22px); }
.app[data-nav="collapsed"] .al-rail-g { left: calc(var(--sidebar-w-collapsed) + 22px); }
/* À droite, plus bas : ce qu'on peut faire. Séparées par tout
   l'écran, on ne confond jamais « on t'informe » et « on t'attend ». */
.al-rail-d { top: 132px; right: 22px; align-items: flex-end; }

@media (max-width: 1100px) {
  .al-rail-g { left: 16px; top: 66px; }
  .al-rail-d { right: 16px; top: 220px; }
}
@media (max-width: 620px) {
  .al-rail { width: calc(100vw - 24px); }
  .al-rail-g { left: 12px; }
  .al-rail-d { right: 12px; top: auto; bottom: 84px; align-items: stretch; }
}

.al-carte {
  pointer-events: auto;
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 26px 1fr 22px;
  align-items: start; gap: 10px;
  padding: 11px 12px 11px 11px;
  border-radius: 13px;
  border: 1px solid var(--n-bord);
  background: linear-gradient(180deg, rgba(14,20,30,.94), rgba(9,13,20,.96));
  box-shadow: 0 14px 34px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.02) inset;
  backdrop-filter: blur(9px);
  animation: al-entre .42s var(--m-doux) backwards;
}

/* ⚠ `backwards`, JAMAIS `both`. Avec `both`, la dernière image de
   l'animation est gelée pour toujours et bat les déclarations
   ordinaires : le `:hover` ci-dessous ne pourrait plus déplacer la
   carte d'un pixel. Ça nous est arrivé sur les affiches du Cercle,
   le 9 septembre. */
@keyframes al-entre {
  from { opacity: 0; transform: translateX(-26px) scale(.96); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
.al-r-d { animation-name: al-entre-d; }
@keyframes al-entre-d {
  from { opacity: 0; transform: translateX(26px) scale(.96); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
.al-sort { animation: al-part .26s ease forwards; }
@keyframes al-part {
  to { opacity: 0; transform: translateY(-8px) scale(.97); filter: blur(4px); }
}

.al-carte:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 55%, transparent);
  box-shadow: 0 18px 40px rgba(0,0,0,.55),
              0 0 0 3px color-mix(in srgb, var(--al-ton, var(--n-cyan)) 12%, transparent);
}

/* LA LUMIÈRE QUI PASSE. C'est ce que la Direction appelle « lights
   katch3al » : une lame claire traverse la carte à son arrivée,
   puis toutes les six secondes. Elle ne clignote pas — un
   clignotement fatigue et finit par être masqué mentalement. */
.al-carte::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 38%,
              color-mix(in srgb, var(--al-ton, var(--n-cyan)) 26%, transparent) 50%,
              transparent 62%);
  background-size: 240% 100%; background-repeat: no-repeat;
  animation: al-lame 6s var(--m-doux) .5s infinite;
}
@keyframes al-lame {
  0%   { background-position: 190% 0; }
  22%  { background-position: -90% 0; }
  100% { background-position: -90% 0; }
}

/* Le filet coloré à gauche : la nature de l'alerte se lit avant le
   texte. C'est lui qui fait la différence entre « on t'informe » et
   « ça brûle », à deux mètres de l'écran. */
.al-carte::after {
  content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 2px;
  border-radius: 2px;
  background: var(--al-ton, var(--n-cyan));
  box-shadow: 0 0 12px color-mix(in srgb, var(--al-ton, var(--n-cyan)) 70%, transparent);
}

.al-ok     { --al-ton: #55E6A5; }
.al-info   { --al-ton: #12D9FF; }
.al-or     { --al-ton: #E7C468; }
.al-warn   { --al-ton: #FFA94D; }
.al-danger { --al-ton: #FF6B6B; }

.al-oeil {
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 8px;
  color: var(--al-ton, var(--n-cyan));
  background: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 12%, transparent);
  animation: al-coeur 3.4s var(--m-doux) infinite;
}
@keyframes al-coeur {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--al-ton, var(--n-cyan)) 30%, transparent); }
  50%      { box-shadow: 0 0 0 5px transparent; }
}

.al-corps { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.al-titre  { font: 500 12.5px/1.3 var(--f-body); color: var(--n-tx); letter-spacing: -.01em; }
.al-detail { font-size: 11.5px; line-height: 1.45; color: var(--n-tx-3);
             display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
             overflow: hidden; }

.al-fermer {
  display: grid; place-items: center; width: 22px; height: 22px;
  border-radius: 7px; border: 0; cursor: pointer;
  background: transparent; color: var(--n-tx-3);
  transition: color .15s ease, background .15s ease;
}
.al-fermer:hover { color: var(--n-tx); background: rgba(255,255,255,.07); }

.al-geste {
  grid-column: 1 / -1; margin-top: 8px;
  padding: 7px 12px; border-radius: 9px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--al-ton, var(--n-cyan)) 42%, transparent);
  background: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 11%, transparent);
  color: var(--n-tx); font: 500 12px var(--f-body);
  transition: background .16s ease, transform .16s ease, box-shadow .16s ease;
}
.al-geste:hover {
  background: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 20%, transparent);
  transform: translateY(-1px);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--al-ton, var(--n-cyan)) 10%, transparent);
}
.al-geste:disabled { opacity: .55; cursor: default; transform: none; }

/* ⚠ ET SI LA PERSONNE A DEMANDÉ MOINS DE MOUVEMENT, ON SE TIENT
   TRANQUILLE. Les cartes restent, elles arrivent simplement sans
   glisser et sans lame de lumière. */
@media (prefers-reduced-motion: reduce) {
  .al-carte, .al-carte::before, .al-oeil { animation: none; }
  .al-sort { opacity: 0; }
}

/* ============================================================================
   58 — LA REVUE : ON REGARDE, ON DÉCIDE, ON PASSE À LA SUIVANTE
   10 septembre 2026

   Direction : « ykon fihom nichan nchof la vidéo ou ndir Go ou la
   modifier, machi ou voir le projet — bach des fois nvalide mnhom
   direct, fach kikono plusieurs vidéos ou plusieurs designs. »

   ⚠ LA VIDÉO PREND TOUTE LA PLACE, ET LE RESTE TIENT DESSOUS.
   Une fenêtre de décision où il faut faire défiler pour voir ce
   qu'on décide, c'est une fenêtre où on décide sans avoir vu.
   ========================================================================== */

.rv { display: flex; flex-direction: column; gap: 14px; }

.rv-scene {
  position: relative; width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 14px; overflow: hidden;
  border: 1px solid var(--n-bord);
  background: #05080D;
  box-shadow: 0 20px 50px rgba(0,0,0,.5) inset, 0 0 0 1px rgba(255,255,255,.02) inset;
}
.rv-cadre { width: 100%; height: 100%; border: 0; display: block; }

/* Pas de lecteur : on dit pourquoi, et on propose l'issue. Un
   rectangle noir sans explication laisse croire à une panne. */
.rv-vide {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 26px; text-align: center;
}
.rv-vide .ico { color: var(--n-tx-3); opacity: .7; }
.rv-vide p { max-width: 46ch; margin: 0; font-size: 12.5px; line-height: 1.6; color: var(--n-tx-3); }

.rv-tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rv-titre { font: 500 15px var(--f-body); color: var(--n-tx); letter-spacing: -.01em; }

.rv-etat {
  padding: 3px 9px; border-radius: 999px;
  font: 500 10.5px var(--f-mono, var(--f-body)); letter-spacing: .06em; text-transform: uppercase;
  border: 1px solid currentColor;
}
.rv-e-valide   { color: #55E6A5; }
.rv-e-en_cours { color: #FFA94D; }
.rv-e-master   { color: #E7C468; }

/* Le compteur file à droite : « 2 / 5 » répond à la seule question
   qu'on se pose en revue — combien il en reste. */
.rv-compteur {
  margin-left: auto;
  font: 500 12px var(--f-body); color: var(--n-tx-3);
  font-variant-numeric: tabular-nums;
}

.rv-note {
  padding: 11px 13px; border-radius: 11px;
  border: 1px solid var(--n-bord); background: rgba(255,169,77,.05);
  border-left: 2px solid #FFA94D;
}
.rv-note p { margin: 4px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--n-tx-2); }

/* ⚠ LES FLÈCHES À GAUCHE, LES DÉCISIONS À DROITE, ET DE L'AIR
   ENTRE LES DEUX. Passer au livrable suivant et valider celui-ci
   sont deux gestes très différents ; côte à côte, on se trompe. */
.rv-pied { display: flex; align-items: center; gap: 14px; width: 100%; flex-wrap: wrap; }
.rv-fleches { display: flex; gap: 6px; }
.rv-fleche {
  display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: 9px; cursor: pointer;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.03);
  color: var(--n-tx-2);
  transition: color .15s ease, border-color .15s ease, transform .15s ease;
}
.rv-fleche:hover:not(:disabled) { color: var(--n-tx); border-color: rgba(18,217,255,.45); transform: translateY(-1px); }
.rv-fleche:disabled { opacity: .35; cursor: default; }

.rv-gestes { display: flex; gap: 8px; margin-left: auto; flex-wrap: wrap; align-items: center; }

@media (max-width: 620px) {
  .rv-pied { flex-direction: column; align-items: stretch; }
  .rv-gestes { margin-left: 0; }
  .rv-gestes .btn { flex: 1 1 auto; justify-content: center; }
}

/* ── LES DEUX GESTES D'UNE CARTE D'ALERTE ─────────────────────
   « Regarder » puis « Voir dans SPIDER » : le premier est celui
   qu'on veut, le second celui qu'on peut. On les distingue par le
   poids, pas par la couleur — deux couleurs vives dans une carte
   de 340 px et plus rien ne ressort. */
.al-gestes { grid-column: 1 / -1; display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.al-gestes .al-geste { margin-top: 0; flex: 1 1 auto; }
.al-geste.al-fort {
  background: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 22%, transparent);
  border-color: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 62%, transparent);
}
.al-geste.al-fort:hover {
  background: color-mix(in srgb, var(--al-ton, var(--n-cyan)) 32%, transparent);
}

/* Le bouton Drive du dossier. Quand l'adresse est connue c'est un
   lien ordinaire ; quand elle manque, il le DIT — ambré, pas rouge.
   Le rouge veut dire « cassé » ; ici rien n'est cassé, il manque
   juste un collage que personne n'a encore fait. */
.c25-ecrire-manque {
  border-color: rgba(231,196,104,.42);
  color: #E7C468;
}
.c25-ecrire-manque:hover {
  color: #F3DDA0;
  border-color: rgba(231,196,104,.7);
  box-shadow: 0 0 0 3px rgba(231,196,104,.1);
}
a.c25-ecrire { text-decoration: none; }

/* Le nom de version tient sur peu de caractères — « V2 », « MASTER » —
   et le lien en demande beaucoup. Sans largeur fixe sur le premier,
   les deux se partagent l'espace à parts égales et le lien devient
   illisible. */
.w-120 { flex: 0 0 120px; }
.w-120 .input { width: 100%; }
@media (max-width: 560px) { .w-120 { flex: 1 1 100%; } }

/* ============================================================================
   59 — LE DÉPÔT DIRECT DANS DRIVE
   10 septembre 2026

   ⚠ LA BARRE D'AVANCEMENT N'EST PAS UNE DÉCORATION. Une vidéo de
   studio pèse un gigaoctet ; sans elle, l'écran ne bouge plus
   pendant deux minutes et le monteur relance l'envoi en croyant
   que c'est bloqué — deux fichiers dans Drive, et un doute sur
   lequel est le bon.
   ========================================================================== */

.dep-zone { padding: 12px; border-radius: 12px;
  border: 1px dashed var(--n-bord); background: rgba(255,255,255,.018); }

.dep-barre {
  height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(255,255,255,.07);
}
.dep-barre > i {
  display: block; height: 100%; width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--n-cyan), #55E6A5);
  box-shadow: 0 0 10px color-mix(in srgb, var(--n-cyan) 60%, transparent);
  transition: width .25s ease;
}

/* ============================================================================
   60 — SPIDER · L'ÉQUIPE : LA PÉRIODE ET LE DÉTAIL DES APPELS
   10 septembre 2026

   Direction : « filtre 1 jour to 30 jours personnalisé… f l bas
   dial la page ykono les noms dial l'équipe ou kanchofo hdahom le
   temps réel… nchof les commentaires bach nverifie la journée ».
   ========================================================================== */

.sp-periode {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.sp-periode .input[type="date"] { width: auto; min-width: 148px; }
.sp-periode-sep { font-size: 11.5px; color: var(--n-tx-3); }

/* La liste d'appels : une grille, pas un tableau. Un tableau
   impose des colonnes de largeur égale ; ici l'heure tient en six
   caractères et le commentaire en prend cinquante. */
.sp-appels {
  display: flex; flex-direction: column; gap: 1px;
  margin-top: 10px; border-radius: 10px; overflow: hidden;
  border: 1px solid var(--n-bord);
}
.sp-appel-l {
  display: grid; align-items: baseline; gap: 10px;
  grid-template-columns: 84px minmax(120px, 1.1fr) 96px 84px minmax(160px, 2fr);
  padding: 9px 12px;
  background: rgba(255,255,255,.018);
  font-size: 12px; line-height: 1.5;
}
.sp-appel-l:nth-child(odd) { background: rgba(255,255,255,.035); }
.sp-appel-h   { color: var(--n-tx-3); font-variant-numeric: tabular-nums; }
.sp-appel-qui { color: var(--n-tx); font-weight: 500; }
.sp-appel-r   { justify-self: start; }
.sp-appel-t   { color: var(--n-tx-3); font-variant-numeric: tabular-nums; }
/* ⚠ LE COMMENTAIRE N'EST PAS TRONQUÉ À UNE LIGNE. C'est lui qu'on
   vient lire ; le couper à mi-phrase obligerait à ouvrir la fiche
   pour chaque appel — exactement ce qu'on cherche à éviter. */
.sp-appel-c   { color: var(--n-tx-2); }

@media (max-width: 900px) {
  .sp-appel-l { grid-template-columns: 76px 1fr; }
  .sp-appel-r, .sp-appel-t { grid-column: 2; justify-self: start; }
  .sp-appel-c { grid-column: 1 / -1; padding-top: 2px; }
}


/* ============================================================
   31.9  L'EQUIPE EN DIRECT — 10 septembre 2026

   Direction : « b7al une carte machi 9owat » — une carte, pas
   une liste. La liste precedente alignait des noms et des
   compteurs vides ; on lisait dix lignes sans rien apprendre.

   Une carte par personne : l'etat en haut a droite, l'appel en
   cours en bandeau, les chiffres en tuiles, le detail replie.
   ============================================================ */
.sp-cartes:has(.sp-col) {
  grid-template-columns: repeat(auto-fit, minmax(336px, 1fr));
}
.sp-col { display: flex; flex-direction: column; gap: 10px; }
.sp-col-tete { display: flex; align-items: center; gap: 11px; }
.sp-col-tete b { display: block; font-size: 15px; letter-spacing: -.02em; }
.sp-col-sous { margin: 0; font-size: 12px; color: var(--n-tx-3); line-height: 1.45; }

/* Le bord gauche dit l'etat sans qu'on ait a lire. */
.sp-col-vert   { border-left: 3px solid var(--n-vert); }
.sp-col-orange { border-left: 3px solid var(--n-or); }
.sp-col-close  { border-left: 3px solid rgba(120,150,190,.35); }
.sp-col-gris   { border-left: 3px solid rgba(120,150,190,.16); }

.sp-etat {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  padding: 4px 9px; border-radius: 999px; font-size: 10.5px;
  font-family: var(--f-mono); letter-spacing: .06em; text-transform: uppercase;
  border: 1px solid rgba(120,150,190,.18); background: rgba(255,255,255,.03);
  color: var(--n-tx-3);
}
.sp-etat i { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.sp-etat-vert   { color: var(--n-vert); border-color: rgba(52,211,153,.32); background: rgba(52,211,153,.09); }
.sp-etat-orange { color: var(--n-or);   border-color: rgba(245,180,60,.30);  background: rgba(245,180,60,.08); }
.sp-etat-close  { color: var(--n-tx-2); }

/* Le point vert respire : c'est la seule chose de cet ecran qui
   change toute seule, et on doit le voir du fond de la piece. */
.sp-etat-vert i { animation: sp-pouls 2.4s ease-in-out infinite; }
@keyframes sp-pouls {
  0%, 100% { box-shadow: 0 0 0 0 rgba(52,211,153,.55); }
  50%      { box-shadow: 0 0 0 5px rgba(52,211,153,0); }
}

/* L'appel en cours. */
.sp-tel {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 11px; border-radius: 10px;
  border: 1px solid rgba(52,211,153,.28); background: rgba(52,211,153,.08);
  font-size: 12.5px; color: var(--n-tx-1);
}
.sp-tel-ico { color: var(--n-vert); display: inline-flex; flex: none; }
.sp-tel-cpt {
  font-family: var(--f-mono); font-size: 15px; font-variant-numeric: tabular-nums;
  color: var(--n-vert); letter-spacing: -.02em; flex: none;
}
.sp-tel-vieux {
  border-color: rgba(245,180,60,.28); background: rgba(245,180,60,.07);
  align-items: flex-start; line-height: 1.45;
}
.sp-tel-vieux .sp-tel-ico { color: var(--n-or); }

/* ── LE POINT DE 17:30 */
.sp-point {
  border: 1px solid var(--n-bord); border-radius: 12px;
  background: rgba(17,26,37,.55); padding: 14px 16px;
  display: flex; flex-direction: column; gap: 10px;
}
.sp-point-l {
  margin: 0; display: grid; grid-template-columns: 150px 1fr;
  gap: 6px 14px; font-size: 12.5px; align-items: baseline;
}
.sp-point-l dt {
  color: var(--n-tx-3); font-family: var(--f-mono);
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
}
.sp-point-l dd { margin: 0; color: var(--n-tx-1); line-height: 1.5; }

@media (max-width: 700px) {
  .sp-cartes:has(.sp-col) { grid-template-columns: 1fr; }
  .sp-point-l { grid-template-columns: 1fr; gap: 2px 0; }
  .sp-point-l dd { margin-bottom: 8px; }
  .sp-col-tete { flex-wrap: wrap; }
}

/* A l'impression, le point de 17:30 est le document : le reste
   de l'ecran n'a rien a faire sur la feuille. */
@media print {
  .sp-periode, .sp-vue, .sp-appels, .sp-onglets, .btn { display: none !important; }
  .sp-point { break-inside: avoid; border-color: #999; background: #fff; }
  .sp-point-l dt, .sp-point-l dd, .sp-point b { color: #000 !important; }
}


/* ============================================================
   31.10  LE CHIFFRAGE DU DEVIS — 10 septembre 2026

   Sept colonnes : designation, precision, quantite, jours, prix
   unitaire, total de la ligne, et la croix pour retirer. Le
   total de chaque ligne est CALCULE, jamais saisi — il est donc
   affiche, pas mis dans un champ. C'est ce qui garantit qu'un
   devis ne peut pas porter un total faux.
   ============================================================ */
.sp-chiffrage {
  margin-top: 16px; padding-top: 16px;
  border-top: 1px solid var(--n-bord);
  display: flex; flex-direction: column; gap: 12px;
}
.sp-lignes-corps { display: flex; flex-direction: column; gap: 8px; }
.sp-ligne {
  display: grid; align-items: center; gap: 8px;
  grid-template-columns: minmax(150px, 2fr) minmax(110px, 1.4fr) 68px 68px 116px 116px 34px;
}
.sp-ligne-tete {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--n-tx-3); padding-bottom: 2px;
}
.sp-ligne .input { width: 100%; }
.sp-l-n, .sp-l-pu { text-align: right; font-variant-numeric: tabular-nums; }
.sp-l-total {
  text-align: right; font-variant-numeric: tabular-nums;
  font-size: 13px; color: var(--n-tx-1); font-weight: 600;
}
.sp-l-x { padding: 0; width: 30px; height: 30px; line-height: 1; font-size: 17px; }
.sp-l-lab { display: inline-flex; align-items: center; gap: 7px; }
.sp-l-lab > span {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--n-tx-3);
}

.sp-totaux {
  display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap;
}
.sp-totaux > div {
  min-width: 148px; padding: 10px 13px; border-radius: 10px;
  border: 1px solid rgba(120,150,190,.12); background: rgba(255,255,255,.022);
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
}
.sp-totaux span {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--n-tx-3);
}
.sp-t-v { font-size: 15px; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.sp-t-fort { background: #000; border-color: rgba(255,255,255,.16); }
.sp-t-ttc { color: #fff; }

@media (max-width: 860px) {
  .sp-ligne-tete { display: none; }
  .sp-ligne {
    grid-template-columns: 1fr 1fr 1fr; gap: 6px;
    padding: 10px; border-radius: 10px;
    border: 1px solid rgba(120,150,190,.12); background: rgba(255,255,255,.018);
  }
  .sp-l-des, .sp-l-det { grid-column: 1 / -1; }
  .sp-l-total { grid-column: 1 / 3; text-align: left; }
  .sp-totaux > div { flex: 1 1 100%; }
}


/* ============================================================
   32.  LES TABLEAUX DE LA FICHE TECHNIQUE — 11 septembre 2026

   Direction : « ou zid les tableau ». Un planning de tournage,
   une liste de materiel, une repartition d'equipe : ca s'ecrit
   en colonnes.

   Le cadre defile TOUT SEUL. Six colonnes sur un telephone
   feraient defiler la page de cote, et tout l'ecran deviendrait
   bancal — c'est la regle de cet OS, jamais de defilement
   horizontal sur le corps.
   ============================================================ */
.tdos { display: flex; flex-direction: column; gap: 14px; }
.tdos-carte {
  border: 1px solid var(--n-bord); border-radius: 12px;
  background: rgba(255,255,255,.018); padding: 13px 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.tdos-tete { display: flex; align-items: center; gap: 10px; }
.tdos-tete b { font-size: 14px; letter-spacing: -.01em; }
.tdos-titre { flex: 1 1 auto; font-weight: 600; }
.tdos-x { flex: none; }

.tdos-cadre { overflow-x: auto; border-radius: 9px; }
.tdos-table { width: 100%; border-collapse: separate; border-spacing: 0; min-width: 420px; }
.tdos-table th, .tdos-table td {
  padding: 4px; vertical-align: middle;
  border-bottom: 1px solid rgba(120,150,190,.10);
}
.tdos-table th {
  text-align: left; font-weight: 600;
  background: rgba(255,255,255,.026);
}
.tdos-table th > span, .tdos-table td > span {
  display: block; padding: 6px 8px; font-size: 12.5px; line-height: 1.4;
}
.tdos-table th > span { color: var(--n-tx-3); font-size: 11px;
  font-family: var(--f-mono); letter-spacing: .06em; text-transform: uppercase; }
.tdos-table .input { width: 100%; min-width: 92px; }
.tdos-col { font-weight: 600; }
.tdos-bout { width: 34px; }

/* La croix qui retire une ligne ou une colonne. Discrete tant
   qu'on ne la vise pas : c'est un geste destructif, il ne doit
   pas attirer l'oeil a chaque cellule. */
.tdos-mini {
  width: 24px; height: 24px; border-radius: 6px; padding: 0;
  border: 1px solid transparent; background: transparent;
  color: var(--n-tx-3); font-size: 15px; line-height: 1; cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.tdos-mini:hover, .tdos-mini:focus-visible {
  background: rgba(239,68,68,.12); border-color: rgba(239,68,68,.32); color: #FCA5A5;
}
.tdos-table th .tdos-mini { margin-left: 4px; }

.tdos-pied { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }

@media (max-width: 700px) {
  .tdos-tete { flex-wrap: wrap; }
  .tdos-titre { flex: 1 1 100%; }
}

/* A l'impression, un tableau ne se coupe pas en deux pages. */
@media print {
  .tdos-mini, .tdos-pied, .tdos-x { display: none !important; }
  .tdos-carte { break-inside: avoid; border-color: #999; }
  .tdos-table th, .tdos-table td { border-bottom: 1px solid #bbb; }
}


/* ============================================================
   33.  CE QUI A ETE ETEINT — 11 septembre 2026

   Direction : « ila 7ayd chwiya makhassoch yt3awd ». Une alerte
   ecartee ne revient plus. Mais eteindre ne doit pas vouloir dire
   oublier : cette ligne dit combien de situations sont masquees
   et permet de toutes les rappeler.

   Elle n'apparait QUE quand les deux rails sont vides. Un rappel
   permanent redeviendrait une alerte de plus — exactement ce
   qu'on vient de retirer.
   ============================================================ */
.al-masquees {
  pointer-events: auto;
  border: 1px dashed rgba(120,150,190,.26);
  background: rgba(17,26,37,.55);
  color: var(--n-tx-3);
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 11px;
  font-family: var(--f-mono);
  letter-spacing: .05em;
  cursor: pointer;
  opacity: .5;
  transition: opacity .2s ease, color .2s ease, border-color .2s ease;
  animation: os25-arrive 380ms var(--m-vif) backwards;
}
.al-masquees:hover, .al-masquees:focus-visible {
  opacity: 1; color: var(--n-tx-1); border-color: rgba(120,150,190,.5);
}

@media print { .al-masquees { display: none !important; } }


/* ============================================================
   34.  LA BARRE DE PORTE, EN HAUT DU DOSSIER — 11 sept. 2026

   Direction : « mzal matal3atch l bouton ». Il etait au fond de
   l'onglet « La chaine », a cinq clics du projet. Il est
   maintenant sous le titre, sur les trois onglets.

   Quand elle n'est pas prete, elle reste discrete : c'est une
   consigne, pas une alarme. Quand elle est prete, le vert la
   fait remarquer, parce qu'a ce moment-la un geste est attendu.
   ============================================================ */
.c25-porte { margin-top: 14px; }
.c25-porte.prete { box-shadow: 0 0 0 1px rgba(36,217,129,.10) inset; }
.c25-porte .btn { flex: none; }

/* Un dossier clos ne propose rien : il constate. */
.c25-porte-livree {
  border-color: rgba(120,150,190,.18);
  background: rgba(255,255,255,.02);
}
.c25-porte-livree .c25-porte-txt b { color: var(--n-tx-2); }

@media (max-width: 700px) {
  .c25-porte { padding: 14px 15px; gap: 11px; }
  .c25-porte .btn { width: 100%; }
}


/* ============================================================
   35.  CE QUI VIENT DE SPIDER — 11 septembre 2026

   L'etape Commercial est sortie du CERCLE : elle demandait six
   champs deja saisis dans SPIDER. Ce bloc les rappelle en tete de
   la pre-production, en LECTURE — pour preparer un plateau il
   faut savoir ce que le client a demande et pour quel budget.

   Il est volontairement discret : c'est un rappel, pas un
   formulaire. Rien ne s'y clique sauf le lien vers SPIDER.
   ============================================================ */
.venu-spider {
  margin: 0 0 18px; padding: 13px 15px; border-radius: 12px;
  border: 1px solid rgba(212,169,79,.22);
  background: rgba(212,169,79,.05);
  display: flex; flex-direction: column; gap: 10px;
}
.venu-spider .eyebrow { color: #D4A94F; }
.venu-spider .sp-point-l { grid-template-columns: 168px 1fr; font-size: 12.5px; }
.venu-spider .sp-point-l dt { color: rgba(212,169,79,.75); }

@media (max-width: 700px) {
  .venu-spider .sp-point-l { grid-template-columns: 1fr; gap: 2px 0; }
  .venu-spider .sp-point-l dd { margin-bottom: 8px; }
}


/* ============================================================
   36.  LES DEUX BOUTS DE LA CHAINE — 11 septembre 2026

   SPIDER ouvre le dossier quand le client a signe, et le reprend
   quand le film est pret. Une ligne = un dossier qui attend un
   geste du commercial.
   ============================================================ */
.sp-pj {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: 11px;
  border: 1px solid var(--n-bord); background: rgba(255,255,255,.022);
  transition: border-color .18s ease, background .18s ease;
}
.sp-pj:hover { border-color: rgba(120,150,190,.3); background: rgba(255,255,255,.035); }
.sp-pj b { display: block; font-size: 13.5px; letter-spacing: -.01em; }
.sp-pj .btn { flex: none; }

@media (max-width: 720px) {
  .sp-pj > div.grow { flex: 1 1 100%; }
  .sp-pj .btn { flex: 1 1 auto; }
}


/* ============================================================
   37.  LES DEUX PONTS — 11 septembre 2026

   Direction : « botons fiha Go to BORN mn SPIDER l CERCLE, ou
   boton mn CERCLE l SPIDER : Go to livraison ».

   Ce ne sont pas des boutons ordinaires : ils font passer un
   dossier d'un monde a l'autre. Ils le montrent — une fleche qui
   avance quand la main s'approche.
   ============================================================ */
.sp-pont, .c25-pont { position: relative; }
.sp-pont svg, .c25-pont svg { transition: transform .2s var(--m-vif); }
.sp-pont:hover svg, .c25-pont:hover svg { transform: translateX(3px) translateY(-2px); }

.c25-pont {
  border-color: rgba(212,169,79,.3);
  color: #E7C878;
}
.c25-pont:hover, .c25-pont:focus-visible {
  background: rgba(212,169,79,.1); border-color: rgba(212,169,79,.5);
}

@media (prefers-reduced-motion: reduce) {
  .sp-pont svg, .c25-pont svg { transition: none; }
  .sp-pont:hover svg, .c25-pont:hover svg { transform: none; }
}


/* ============================================================
   38.  CE QUE CE DOSSIER COMPORTE — 12 septembre 2026

   Direction : « kan cocheew l fou9 : wach kayn scenario, wach
   decoupage... ay haja t cochat, t7al ».

   Des cases qui ressemblent a des cases : eteintes elles
   proposent, allumees elles engagent. Une case figee (champ deja
   rempli) ne se decoche pas — decocher masquerait un texte ecrit.
   ============================================================ */
.prep-decl {
  margin: 0 0 18px; padding: 13px 15px; border-radius: 12px;
  border: 1px solid rgba(139,92,246,.20);
  background: rgba(139,92,246,.045);
  display: flex; flex-direction: column; gap: 10px;
}
.prep-decl .eyebrow { color: #C9B4FF; }

.prep-case {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid rgba(120,150,190,.18);
  background: rgba(255,255,255,.025);
  color: var(--n-tx-3); font-size: 12.5px; cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.prep-case:hover:not(.fige) {
  border-color: rgba(139,92,246,.40); color: var(--n-tx-1);
}
.prep-case.on {
  background: rgba(139,92,246,.14); border-color: rgba(139,92,246,.48);
  color: #DCCBFF; font-weight: 600;
}
.prep-case.fige {
  cursor: not-allowed; opacity: .75;
  background: rgba(139,92,246,.10); border-style: dashed;
}
.prep-case svg { flex: none; }

@media (max-width: 700px) {
  .prep-case { font-size: 12px; padding: 6px 11px; }
}

/* ============================================================
   39. LA CUT ROOM — 15 septembre 2026

   Direction : « chouf l google sheet kifach kan organisé ».
   Le Sheet se lisait d'un coup d'oeil parce qu'il était dense et
   que la couleur disait l'état. On garde les deux : des lignes
   serrées, et une couleur par statut, la même partout — dans la
   liste déroulante, la pastille et le bord de la carte.

   Couleurs (tokens --n-*) :
     demandée rouge · à faire gris · en cours bleu · à modifier
     orange · review cyan · validé violet · chez le client or ·
     livré vert.
   ============================================================ */
.cr-barre-haut { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin: 4px 0 18px; }
.cr-barre-haut > .input { flex: 0 1 300px; min-width: 200px; }
.cr-barre-haut > [hidden] { display: none; }
.cr-onglets { display: flex; flex-wrap: wrap; gap: 8px; }
.cr-onglets .chip b.mono { margin-left: 6px; opacity: .75; font-variant-numeric: tabular-nums; }
.cr-zone { min-width: 0; }
.cr-filtres { margin-bottom: -4px; }

.cr-panne {
  padding: 18px 20px; border-radius: 12px;
  border: 1px solid rgba(255,77,85,.35); background: rgba(255,77,85,.06);
  display: flex; flex-direction: column; gap: 6px;
}
.cr-panne b { color: var(--n-rouge); }
.cr-panne p { margin: 0; color: var(--n-tx-2); }

/* Les sections */
.cr-sec { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.cr-sec-tete { display: flex; flex-direction: column; gap: 2px; }
.cr-sec-tete h2 {
  margin: 0; font-size: 15px; font-weight: 600; letter-spacing: .01em; color: var(--n-tx);
  display: flex; align-items: baseline; gap: 8px;
}
.cr-sec-tete h2 b.mono { font-size: 12px; color: var(--n-tx-2); font-weight: 500; }
.cr-vide { margin: 0; padding: 12px 14px; border-radius: 10px; border: 1px dashed var(--n-bord); color: var(--n-tx-2); font-size: 13px; }

/* À prendre : la seule section qui crie */
.cr-sec-entree.a-prendre .cr-sec-tete h2 { color: var(--n-rouge); }
.cr-demandes { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 12px; }
.cr-demande, .cr-carte {
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
  padding: 13px 15px; border-radius: 12px;
  background: var(--n-carte); border: 1px solid var(--n-bord);
}
.cr-demande { border-color: rgba(247,169,40,.35); }
.cr-demande.tard, .cr-demande.urgent { border-color: rgba(255,77,85,.55); background: linear-gradient(180deg, rgba(255,77,85,.08), rgba(7,11,18,.96)); }
.cr-age { font-size: 12px; color: var(--n-tx-2); }
.cr-demande.tard .cr-age { color: var(--n-rouge); }
.cr-dm-titre { font-size: 14.5px; color: var(--n-tx); line-height: 1.3; overflow-wrap: anywhere; }
.cr-dm-detail { margin: 0; font-size: 12.5px; color: var(--n-tx-2); line-height: 1.45; white-space: pre-line; overflow-wrap: anywhere; }
.cr-dm-pied { margin-top: 4px; }
.cr-urgent {
  display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: #fff; background: var(--n-rouge);
}
.cr-nature {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; color: var(--n-tx-2); border: 1px solid var(--n-bord); white-space: nowrap;
}
.cr-nature.n-design { color: #DCCBFF; border-color: rgba(139,92,246,.35); }
.cr-nature.n-photo  { color: #9FE9FF; border-color: rgba(18,217,255,.30); }
.cr-nature.n-modif  { color: #FFD08A; border-color: rgba(247,169,40,.35); }

/* Le tableau */
.cr-defile { overflow-x: auto; border-radius: 12px; border: 1px solid var(--n-bord); background: var(--n-surface); }
.cr-t { width: 100%; min-width: 900px; border-collapse: collapse; }
.cr-t th { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--n-tx-2); text-align: left; padding: 9px 12px; white-space: nowrap; }
.cr-t td { padding: 8px 12px; vertical-align: middle; font-size: 13px; }
.cr-t td b { display: block; color: var(--n-tx); font-weight: 600; }
.cr-td-date { white-space: nowrap; }
.cr-td-date .mono { display: block; color: var(--n-tx); }
.cr-sous { display: block; font-size: 12px; color: var(--n-tx-2); }
.cr-titre { display: block; margin-top: 3px; color: var(--n-tx); overflow-wrap: anywhere; }
.cr-td-note { max-width: 240px; }
.cr-note, .cr-modif { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: 12.5px; }
.cr-modif { color: var(--n-orange); }
.cr-lien { display: inline-flex; align-items: center; gap: 5px; color: var(--n-cyan); text-decoration: none; white-space: nowrap; }
.cr-lien:hover { text-decoration: underline; }
.cr-t tr.cr-en-retard td:first-child { box-shadow: inset 3px 0 0 var(--n-rouge); }
.cr-t tr.cr-tr-urgent { background: rgba(255,77,85,.05); }
.cr-t tr.cr-annule td { opacity: .55; }
.cr-qui { min-width: 150px; max-width: 190px; }

.cr-ech { display: inline-block; margin-top: 2px; font-size: 11.5px; color: var(--n-tx-2); white-space: nowrap; }
.cr-ech.orange { color: var(--n-orange); }
.cr-ech.rouge  { color: var(--n-rouge); font-weight: 600; }

/* Une couleur par statut — la liste, la pastille, le bord */
.cr-st { min-width: 160px; font-weight: 600; }
.cr-pastille {
  display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap; border: 1px solid transparent;
}
.st-demandee.cr-st, .cr-pastille.st-demandee             { color: var(--n-rouge);  border-color: rgba(255,77,85,.40);  background-color: rgba(255,77,85,.10); }
.st-a_faire.cr-st, .cr-pastille.st-a_faire               { color: var(--n-tx);     border-color: var(--n-bord-fort);   background-color: rgba(120,150,190,.08); }
.st-en_cours.cr-st, .cr-pastille.st-en_cours             { color: #7DBBFF;         border-color: rgba(37,139,255,.40); background-color: rgba(37,139,255,.10); }
.st-a_modifier.cr-st, .cr-pastille.st-a_modifier         { color: var(--n-orange); border-color: rgba(247,169,40,.45); background-color: rgba(247,169,40,.10); }
.st-review.cr-st, .cr-pastille.st-review                 { color: var(--n-cyan);   border-color: rgba(18,217,255,.40); background-color: rgba(18,217,255,.08); }
.st-valide_interne.cr-st, .cr-pastille.st-valide_interne { color: #C9B4FF;         border-color: rgba(139,92,246,.45); background-color: rgba(139,92,246,.12); }
.st-envoye_client.cr-st, .cr-pastille.st-envoye_client   { color: var(--n-or);     border-color: rgba(242,185,64,.40); background-color: rgba(242,185,64,.10); }
.st-livre.cr-st, .cr-pastille.st-livre                   { color: var(--n-vert);   border-color: rgba(36,217,129,.40); background-color: rgba(36,217,129,.10); }
.st-annule.cr-st, .cr-pastille.st-annule                 { color: var(--n-tx-2);   border-color: var(--n-bord);        background-color: transparent; }

.cr-carte.st-bord-a_modifier     { box-shadow: inset 3px 0 0 var(--n-orange); }
.cr-carte.st-bord-en_cours       { box-shadow: inset 3px 0 0 var(--n-bleu); }
.cr-carte.st-bord-a_faire        { box-shadow: inset 3px 0 0 var(--n-bord-fort); }
.cr-carte.st-bord-review         { box-shadow: inset 3px 0 0 var(--n-cyan); }
.cr-carte.st-bord-valide_interne { box-shadow: inset 3px 0 0 var(--n-violet); }
.cr-carte.st-bord-envoye_client  { box-shadow: inset 3px 0 0 var(--n-or); }
.cr-modif-bloc {
  margin: 2px 0 0; padding: 8px 10px; border-radius: 8px; font-size: 13px; white-space: pre-line;
  color: #FFD08A; background: rgba(247,169,40,.08); border: 1px solid rgba(247,169,40,.28);
}

/* Le Sheet repris, replié */
.cr-sheet { padding: 12px 14px; border-radius: 12px; border: 1px dashed var(--n-bord-fort); }
.cr-sheet > summary { cursor: pointer; list-style: none; }
.cr-sheet > summary::-webkit-details-marker { display: none; }
.cr-sheet > summary h2::before { content: "▸"; color: var(--n-tx-2); font-size: 12px; }
.cr-sheet[open] > summary h2::before { content: "▾"; }
.cr-sheet-actions { display: flex; justify-content: flex-end; }

/* Les projets */
.cr-projets { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
.cr-pj {
  display: flex; flex-direction: column; gap: 9px; min-width: 0;
  padding: 15px 16px; border-radius: 14px; background: var(--n-carte); border: 1px solid var(--n-bord);
}
.cr-pj-titre { font-size: 15px; color: var(--n-tx); overflow-wrap: anywhere; }
.cr-phrase { margin: 0; font-size: 13px; line-height: 1.5; color: var(--n-tx); }
.cr-barre { height: 5px; }
.cr-pj-lignes { display: flex; flex-direction: column; gap: 4px; padding-top: 4px; border-top: 1px solid var(--line-soft); }
.cr-pj-lignes[hidden] { display: none; }
.cr-mini {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  padding: 6px 8px; border-radius: 8px; border: 0; background: transparent;
  color: var(--n-tx); font: inherit; font-size: 13px; text-align: left; cursor: pointer;
}
.cr-mini:hover { background: rgba(120,150,190,.08); }
.cr-mini:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

/* Ma journée */
.cr-jours { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.cr-tournage { border-color: rgba(37,139,255,.40); }
.cr-info { display: flex; flex-direction: column; gap: 1px; font-size: 13px; color: var(--n-tx); white-space: pre-line; }

/* Les fenêtres */
.cr-form { display: flex; flex-direction: column; }
.cr-seg { display: flex; flex-wrap: wrap; gap: 6px; }
.cr-seg-b {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--n-bord); background: transparent; color: var(--n-tx-2); font: inherit; font-size: 13px; cursor: pointer;
}
.cr-seg-b.on { color: var(--n-tx); border-color: var(--brand-line); background: var(--brand-soft); font-weight: 600; }
.cr-seg-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }
.cr-check { display: flex; align-items: center; gap: 8px; margin-bottom: var(--s-4); font-size: 13px; color: var(--n-tx); cursor: pointer; }
.cr-ta-court { min-height: 70px; }
.cr-journal { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.cr-j { display: flex; align-items: baseline; gap: 10px; font-size: 12.5px; color: var(--n-tx); }
.cr-annuler { color: var(--n-rouge); }

@media (max-width: 700px) {
  .cr-demandes, .cr-projets, .cr-jours { grid-template-columns: 1fr; }
  .cr-qui { min-width: 130px; }
}

/* ============================================================
   40. CERCLE 25 — LES CINQ ÉTAPES — 16 septembre 2026

   Direction : « je veux ykon plus simple ktar mn haka ou ykon
   premium… ykon animé mzian ». Une seule idée à l'écran : le
   chemin en cinq étapes, qui sert aussi de navigation. Des cartes
   aérées, un seul geste principal par carte, l'étape active
   éclairée en or, et des cartes qui arrivent l'une après l'autre.
   ============================================================ */
.cr2-outils { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin: 2px 0 16px; }
.cr2-cherche { flex: 0 1 320px; min-width: 200px; }
.cr2-bascule { display: inline-flex; padding: 3px; border-radius: 999px; border: 1px solid var(--n-bord); background: var(--n-surface); }
.cr2-bascule-b {
  border: 0; background: transparent; color: var(--n-tx-2); font: inherit; font-size: 12.5px;
  padding: 6px 14px; border-radius: 999px; cursor: pointer; transition: background .2s ease, color .2s ease;
}
.cr2-bascule-b.on { background: rgba(120,150,190,.16); color: var(--n-tx); font-weight: 600; }
.cr2-bascule-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

.cr2-tournages { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.cr2-tournages:empty { display: none; }
.cr2-tournage {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px;
  padding: 10px 14px; border-radius: 12px; font-size: 13px;
  border: 1px solid rgba(37,139,255,.40);
  background: linear-gradient(90deg, rgba(37,139,255,.12), rgba(37,139,255,.02));
}
.cr2-tournage-ico { color: #7DBBFF; display: inline-flex; }

/* Le chemin */
.cr2-circuit { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin: 6px 0 24px; }
.cr2-pas {
  position: relative; display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 14px 16px; border-radius: 16px;
  border: 1px solid var(--n-bord); background: var(--n-carte);
  color: var(--n-tx); font: inherit; text-align: left; cursor: pointer;
  transition: border-color .25s ease, transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease, background .25s ease;
}
.cr2-pas:hover { border-color: var(--n-bord-fort); transform: translateY(-2px); }
.cr2-pas:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr2-pas.on {
  border-color: rgba(242,185,64,.65);
  background: linear-gradient(180deg, rgba(242,185,64,.15), rgba(10,16,24,.96) 72%);
  box-shadow: 0 16px 36px -20px rgba(242,185,64,.6);
}
.cr2-pas:not(:last-child)::after {
  content: ""; position: absolute; right: -9px; top: 50%; width: 6px; height: 1px; background: var(--n-bord-fort);
}
.cr2-pas-n {
  flex: none; width: 28px; height: 28px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700; color: var(--n-tx-2); border: 1px solid var(--n-bord-fort);
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.cr2-pas.on .cr2-pas-n { color: #0A0D12; background: var(--n-or); border-color: var(--n-or); animation: cr2-pouls 2.6s ease-in-out infinite; }
@keyframes cr2-pouls {
  0%, 100% { box-shadow: 0 0 0 0 rgba(242,185,64,.45); }
  50%      { box-shadow: 0 0 0 7px rgba(242,185,64,0); }
}
.cr2-pas-corps { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.cr2-pas-corps b { font-size: 14.5px; font-weight: 600; }
.cr2-pas-qui { font-size: 11.5px; color: var(--n-tx-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cr2-pas-chiffre { font-size: 22px; font-weight: 600; font-variant-numeric: tabular-nums; }
.cr2-toi {
  position: absolute; top: -9px; right: 12px; padding: 2px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em; color: #0A0D12; background: var(--n-or);
}

/* Une étape */
.cr2-etape { display: flex; flex-direction: column; gap: 14px; }
.cr2-etape-tete { animation: cr2-fondu .35s ease both; }
.cr2-etape-tete h2 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -.01em; }
.cr2-etape-tete p { margin: 3px 0 0; font-size: 13px; }
@keyframes cr2-fondu { from { opacity: 0; transform: translateY(4px); } }
.cr2-cartes { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
.cr2-cartes.ancien { opacity: .85; }
.cr2-carte {
  display: flex; flex-direction: column; min-width: 0; overflow: hidden;
  border-radius: 16px; border: 1px solid var(--n-bord); background: var(--n-carte);
  transition: border-color .2s ease, box-shadow .25s ease, transform .25s cubic-bezier(.22,1,.36,1);
  animation: cr2-monte .5s cubic-bezier(.22,1,.36,1) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
@keyframes cr2-monte { from { opacity: 0; transform: translateY(12px) scale(.985); } }
.cr2-carte:hover { border-color: var(--n-bord-fort); box-shadow: 0 18px 40px -24px rgba(0,0,0,.9); transform: translateY(-2px); }
.cr2-carte.urgent { border-color: rgba(255,77,85,.55); }
.cr2-carte-corps {
  display: flex; flex-direction: column; gap: 6px; padding: 14px 16px 12px;
  border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.cr2-carte-corps:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: -2px; }
.cr2-carte-haut { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.cr2-carte-titre { font-size: 16px; font-weight: 600; line-height: 1.3; color: var(--n-tx); overflow-wrap: anywhere; }
.cr2-carte-ou { font-size: 12.5px; color: var(--n-tx-2); }
.cr2-carte-note { font-size: 12.5px; line-height: 1.45; color: var(--n-tx-2); white-space: pre-line; }
.cr2-carte-pied {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  padding: 10px 16px 12px; border-top: 1px solid var(--line-soft); background: rgba(255,255,255,.015);
}
.cr2-qui { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--n-tx); }
.cr2-qui.vide { color: var(--n-tx-2); }
.cr2-qui.tard { color: var(--n-rouge); font-weight: 600; }
.cr2-avatar {
  width: 24px; height: 24px; border-radius: 999px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 700; color: var(--n-tx); background: rgba(120,150,190,.18);
}
.cr2-attente { font-size: 12px; font-style: italic; color: var(--n-tx-2); }
.cr2-arme { background: var(--n-rouge) !important; border-color: var(--n-rouge) !important; color: #fff !important; }
.cr2-vide {
  display: flex; align-items: center; gap: 10px; padding: 22px;
  border-radius: 16px; border: 1px dashed var(--n-bord); color: var(--n-tx-2); font-size: 14px;
  animation: cr2-fondu .4s ease both;
}
.cr2-vide-ico { display: inline-flex; color: var(--n-vert); }
.cr2-sheet-lien {
  align-self: flex-start; padding: 2px 0; border: 0; background: transparent; cursor: pointer;
  color: var(--n-tx-2); font: inherit; font-size: 12.5px; text-decoration: underline; text-underline-offset: 3px;
}
.cr2-sheet-lien:hover { color: var(--n-tx); }
.cr2-sheet-lien:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr2-classer { display: flex; }

/* Livré */
.cr2-livres { display: flex; flex-direction: column; overflow: hidden; border-radius: 14px; border: 1px solid var(--n-bord); background: var(--n-surface); }
.cr2-livre {
  display: flex; align-items: center; gap: 8px; padding-right: 10px; border-bottom: 1px solid var(--line-soft);
  animation: cr2-fondu .35s ease both;
}
.cr2-livre:last-child { border-bottom: 0; }
.cr2-livre.annule { opacity: .55; }
.cr2-livre-corps {
  flex: 1; min-width: 0; display: grid; grid-template-columns: 70px minmax(0, 1fr) 110px; align-items: center; gap: 14px;
  padding: 11px 14px; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.cr2-livre-corps:hover { background: rgba(120,150,190,.06); }
.cr2-livre-corps:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: -2px; }
.cr2-livre-date { font-size: 12px; color: var(--n-tx-2); }
.cr2-livre-titre { display: flex; flex-direction: column; min-width: 0; }
.cr2-livre-titre b { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr2-livre-titre span { font-size: 12px; color: var(--n-tx-2); }
.cr2-livre-qui { font-size: 12.5px; color: var(--n-tx-2); }
.cr2-livre-sans { width: 70px; }

@media (max-width: 1100px) {
  .cr2-circuit { grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); }
  .cr2-pas::after { display: none; }
}
@media (max-width: 620px) {
  .cr2-circuit { display: flex; overflow-x: auto; padding: 10px 2px 6px; }
  .cr2-pas { flex: 0 0 180px; }
  .cr2-cartes { grid-template-columns: 1fr; }
  .cr2-livre-corps { grid-template-columns: 56px minmax(0, 1fr); }
  .cr2-livre-qui { display: none; }
}

/* ============================================================
   41. LES NOTIFICATIONS, À UN SEUL ENDROIT — 16 septembre 2026

   Direction : « hadok les notifications mazwininch ou makibaynoch
   achno kayn. Khass ytal3o f blassa wahda, sghar, ghi des petits
   msgs sghiwrin ».

   Avant : deux rails aux deux bouts de l'écran, des cartes larges
   qui passaient par-dessus les boutons. Maintenant : un seul coin,
   en bas à droite, avec les messages « Fait » au même endroit.
   Une ligne de titre, une ligne de détail, un geste — pas plus.
   ============================================================ */
.al-scene .al-rail-u {
  top: auto; left: auto; right: 18px; bottom: 18px;
  width: min(320px, calc(100vw - 28px)); gap: 8px; align-items: stretch;
}
.al-rail-u .al-toasts {
  position: static; max-width: none; pointer-events: auto;
  display: flex; flex-direction: column; gap: 8px;
}
.al-rail-u .toast { font-size: 12.5px; padding: 8px 12px; border-radius: 12px; }
.al-rail-u .al-carte {
  grid-template-columns: 20px 1fr 18px; gap: 2px 10px;
  padding: 9px 10px 9px 12px; border-radius: 12px;
  background: rgba(12,19,29,.95); backdrop-filter: blur(10px);
  box-shadow: 0 12px 30px -14px rgba(0,0,0,.85);
  animation: al-u-entre .5s cubic-bezier(.22,1,.36,1) both;
}
.al-rail-u .al-carte::before { display: none; }
.al-rail-u .al-carte::after { top: 8px; bottom: 8px; }
.al-rail-u .al-carte:hover { transform: translateY(-1px); }
.al-rail-u .al-oeil { width: 20px; height: 20px; border-radius: 6px; animation: none; }
.al-rail-u .al-oeil svg { width: 13px; height: 13px; }
.al-rail-u .al-titre { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.al-rail-u .al-detail { font-size: 11.5px; -webkit-line-clamp: 1; }
.al-rail-u .al-fermer { width: 18px; height: 18px; }
.al-rail-u .al-gestes { grid-column: 2 / -1; margin-top: 6px; gap: 6px; flex-wrap: nowrap; }
.al-rail-u .al-gestes .al-geste { flex: 0 0 auto; margin: 0; padding: 3px 10px; font-size: 11.5px; border-radius: 999px; }
.al-rail-u .al-masquees { align-self: flex-end; font-size: 11.5px; }
@keyframes al-u-entre { from { opacity: 0; transform: translateY(14px) scale(.96); } to { opacity: 1; transform: none; } }
.al-rail-u .al-sort { animation: al-u-sort .24s ease forwards; }
@keyframes al-u-sort { to { opacity: 0; transform: translateX(24px) scale(.97); } }

/* Sur téléphone, une seule notification à la fois : les suivantes
   attendent derrière et apparaissent quand on ferme la première. */
@media (max-width: 620px) {
  .al-scene .al-rail-u { left: 12px; right: 12px; bottom: 76px; width: auto; }
  .al-rail-u .al-carte:nth-of-type(n+2) { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .cr2-pas, .cr2-carte { transition: none; }
  .cr2-pas:hover, .cr2-carte:hover { transform: none; }
  .cr2-carte, .cr2-livre, .cr2-vide, .cr2-etape-tete, .cr2-pas.on .cr2-pas-n,
  .al-rail-u .al-carte, .al-rail-u .al-sort { animation: none; }
}

/* ============================================================
   42. CERCLE 25 — LA VERSION PREMIUM — 16 septembre 2026

   Direction : « mzl machi premium, khass ykon bombe… khass la liste
   b7al l cutroom ». Trois gestes de design, pas davantage :
     • un en-tête qui a de la présence — grand titre, trois chiffres
       vivants sur verre dépoli, deux halos de lumière derrière ;
     • un chemin lumineux dont la ligne se remplit jusqu'à l'étape
       choisie ;
     • le tableau du Cut room, travaillé ligne par ligne : date en
       grand, statut en pastille colorée, un seul bouton doré.
   ============================================================ */
.cr3 { position: relative; isolation: isolate; }
.cr3::before {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  inset: -60px -40px auto -40px; height: 460px;
  background:
    radial-gradient(620px 260px at 10% 0%, rgba(242,185,64,.16), transparent 70%),
    radial-gradient(560px 280px at 92% 8%, rgba(18,217,255,.11), transparent 70%);
}

/* L'en-tête */
.cr3-hero { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 22px 28px; margin: 6px 0 26px; }
.cr3-hero-txt { min-width: 0; }
.cr3-sur { display: block; font-size: 11px; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--n-or); }
.cr3-titre {
  margin: 8px 0 6px; font-size: clamp(34px, 5vw, 52px); line-height: 1; font-weight: 750; letter-spacing: -.035em;
  color: #F5F7FA;
  background: linear-gradient(95deg, #FFFFFF 0%, #FBEBC2 42%, #F2B940 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  text-wrap: balance;
}
.cr3-sous { margin: 0; max-width: 56ch; font-size: 14px; line-height: 1.55; color: var(--n-tx-2); }
/* ⚠ `master-v2.css` impose la taille des h1 d'écran avec !important :
   sans ce rappel, le titre retombait à 21 px. */
.cr3 .cr3-hero .cr3-titre {
  font-size: clamp(34px, 5vw, 52px) !important; line-height: 1 !important;
  letter-spacing: -.035em !important; margin: 8px 0 6px !important;
}

.cr3-stats { display: flex; flex-wrap: wrap; gap: 12px; }
.cr3-stat {
  position: relative; overflow: hidden; min-width: 132px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  padding: 14px 18px 13px; border-radius: 18px; cursor: pointer; text-align: left;
  color: var(--n-tx); font: inherit;
  border: 1px solid rgba(255,255,255,.08);
  background: linear-gradient(180deg, rgba(255,255,255,.055), rgba(255,255,255,.012));
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 24px 48px -32px rgba(0,0,0,.9), inset 0 1px 0 rgba(255,255,255,.06);
  transition: transform .3s cubic-bezier(.22,1,.36,1), border-color .25s ease, box-shadow .3s ease;
}
.cr3-stat::before {
  content: ""; position: absolute; left: 18px; right: 18px; top: 0; height: 2px; border-radius: 0 0 2px 2px;
  background: var(--ton, var(--n-or)); box-shadow: 0 0 18px var(--ton, var(--n-or));
}
.cr3-stat:hover { transform: translateY(-3px); border-color: rgba(255,255,255,.16); }
.cr3-stat:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-stat.ton-rouge { --ton: #FF5A63; }
.cr3-stat.ton-cyan  { --ton: #12D9FF; }
.cr3-stat.ton-or    { --ton: #F2B940; }
.cr3-stat-n { font-size: 32px; line-height: 1; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.cr3-stat-l { font-size: 12px; color: var(--n-tx-2); }

/* Les outils */
.cr3-outils {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; margin-bottom: 16px;
}
.cr3-nouvelle {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: 8px; height: 42px; padding: 0 20px;
  border: 0; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 650; color: #1A1204;
  background: linear-gradient(180deg, #FAD377 0%, #F2B940 55%, #D99A21 100%);
  box-shadow: 0 12px 28px -12px rgba(242,185,64,.75), inset 0 1px 0 rgba(255,255,255,.45);
  transition: transform .25s cubic-bezier(.22,1,.36,1), box-shadow .25s ease;
}
.cr3-nouvelle::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-120%);
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,.55) 50%, transparent 70%);
}
.cr3-nouvelle:hover { transform: translateY(-2px); box-shadow: 0 18px 34px -12px rgba(242,185,64,.85), inset 0 1px 0 rgba(255,255,255,.45); }
.cr3-nouvelle:hover::after { transform: translateX(120%); transition: transform .8s ease; }
.cr3-nouvelle:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

.cr3-cherche-boite {
  position: relative; display: flex; align-items: center; flex: 0 1 340px; min-width: 210px;
}
.cr3-cherche-ico { position: absolute; left: 14px; color: var(--n-tx-2); display: inline-flex; pointer-events: none; }
.cr3-cherche {
  width: 100%; height: 42px; padding: 0 16px 0 40px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.035);
  color: var(--n-tx); font: inherit; font-size: 13.5px;
  transition: border-color .2s ease, background .2s ease, box-shadow .2s ease;
}
.cr3-cherche::placeholder { color: var(--n-tx-2); }
.cr3-cherche:focus { outline: none; border-color: rgba(242,185,64,.55); background: rgba(255,255,255,.06); box-shadow: 0 0 0 4px rgba(242,185,64,.12); }

.cr3-puce {
  height: 34px; padding: 0 14px; border-radius: 999px; cursor: pointer;
  border: 1px solid rgba(255,255,255,.08); background: transparent;
  color: var(--n-tx-2); font: inherit; font-size: 12.5px;
  transition: all .2s ease;
}
.cr3-puce:hover { color: var(--n-tx); border-color: rgba(255,255,255,.18); }
.cr3-puce.on { color: #1A1204; background: var(--n-or); border-color: var(--n-or); font-weight: 600; }
.cr3-puce:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

.cr3-vues { display: inline-flex; padding: 4px; border-radius: 999px; border: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.03); }
.cr3-vue-b {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 14px; border-radius: 999px;
  border: 0; background: transparent; cursor: pointer; color: var(--n-tx-2); font: inherit; font-size: 12.5px;
  transition: background .25s ease, color .25s ease;
}
.cr3-vue-b.on { background: rgba(255,255,255,.1); color: var(--n-tx); font-weight: 600; box-shadow: inset 0 1px 0 rgba(255,255,255,.08); }
.cr3-vue-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }

/* Le chemin lumineux */
.cr3-piste {
  display: flex; align-items: stretch; gap: 18px; margin-bottom: 18px;
  padding: 18px 20px; border-radius: 22px;
  border: 1px solid rgba(255,255,255,.07);
  background: linear-gradient(180deg, rgba(14,22,33,.82), rgba(8,12,19,.82));
  box-shadow: 0 30px 60px -44px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.04);
}
.cr3-tout {
  flex: none; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 2px;
  min-width: 96px; padding: 0 20px 0 4px; border: 0; border-right: 1px solid rgba(255,255,255,.07);
  background: transparent; cursor: pointer; color: var(--n-tx-2); font: inherit; text-align: left;
  transition: color .2s ease;
}
.cr3-tout-l { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; }
.cr3-tout b { font-size: 26px; line-height: 1; font-weight: 700; color: var(--n-tx-2); transition: color .2s ease; }
.cr3-tout:hover, .cr3-tout:hover b { color: var(--n-tx); }
.cr3-tout.on .cr3-tout-l { color: var(--n-or); }
.cr3-tout.on b { color: var(--n-tx); }
.cr3-tout:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; border-radius: 10px; }

/* Trois étapes depuis le 18/09/2026 : le rail va du centre de la
   première colonne (1/6) au centre de la dernière (5/6). */
.cr3-etapes { position: relative; flex: 1; min-width: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cr3-rail {
  position: absolute; left: calc(100% / 6); right: calc(100% / 6); top: 17px; height: 2px; border-radius: 2px;
  background: rgba(255,255,255,.08);
}
.cr3-rail-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: var(--p, 0%); border-radius: 2px;
  background: linear-gradient(90deg, #12D9FF, #F2B940);
  box-shadow: 0 0 14px rgba(242,185,64,.55);
  transition: width .7s cubic-bezier(.22,1,.36,1);
}
.cr3-pas {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 0;
  padding: 0 4px; border: 0; background: transparent; cursor: pointer; color: var(--n-tx); font: inherit;
}
.cr3-pas:focus-visible { outline: none; }
.cr3-pas:focus-visible .cr3-pas-rond { box-shadow: 0 0 0 3px var(--n-cyan); }
.cr3-pas-rond {
  position: relative; z-index: 1; width: 36px; height: 36px; border-radius: 999px;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  color: var(--n-tx-2); background: #0B121C; border: 1px solid rgba(255,255,255,.14);
  transition: all .35s cubic-bezier(.22,1,.36,1);
}
.cr3-pas:hover .cr3-pas-rond { border-color: rgba(255,255,255,.3); color: var(--n-tx); transform: scale(1.06); }
.cr3-pas.passee .cr3-pas-rond { color: #0B121C; background: linear-gradient(180deg, #7EEBFF, #12D9FF); border-color: transparent; }
.cr3-pas.on .cr3-pas-rond {
  color: #1A1204; border-color: transparent; transform: scale(1.12);
  background: radial-gradient(circle at 35% 30%, #FFE7A8, #F2B940 60%, #C98A12);
  box-shadow: 0 0 0 6px rgba(242,185,64,.14), 0 0 26px rgba(242,185,64,.6);
  animation: cr3-halo 2.8s ease-in-out infinite;
}
@keyframes cr3-halo {
  0%, 100% { box-shadow: 0 0 0 6px rgba(242,185,64,.14), 0 0 22px rgba(242,185,64,.5); }
  50%      { box-shadow: 0 0 0 10px rgba(242,185,64,.05), 0 0 34px rgba(242,185,64,.75); }
}
.cr3-pas-t { display: flex; align-items: baseline; gap: 7px; }
.cr3-pas-t b { font-size: 14px; font-weight: 600; }
.cr3-pas-n { font-size: 12px; font-weight: 600; padding: 1px 7px; border-radius: 999px; color: var(--n-tx-2); background: rgba(255,255,255,.06); }
.cr3-pas.on .cr3-pas-n { color: #1A1204; background: var(--n-or); }
.cr3-pas-qui { font-size: 11px; color: var(--n-tx-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.cr3-toi {
  position: absolute; top: -8px; left: calc(50% + 14px); z-index: 2;
  padding: 1px 7px; border-radius: 999px; font-size: 9.5px; font-weight: 800; letter-spacing: .06em;
  color: #1A1204; background: #FFE7A8; box-shadow: 0 4px 10px -4px rgba(242,185,64,.8);
}

.cr3-tournages { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.cr3-tournages:empty { display: none; }

/* Le tableau du Cut room */
.cr3-bloc { display: flex; flex-direction: column; gap: 12px; animation: cr3-apparait .45s ease both; }
@keyframes cr3-apparait { from { opacity: 0; transform: translateY(6px); } }
.cr3-table-boite {
  overflow-x: auto; border-radius: 22px;
  border: 1px solid rgba(255,255,255,.07);
  background: linear-gradient(180deg, rgba(13,20,30,.92), rgba(7,11,17,.92));
  box-shadow: 0 40px 80px -50px rgba(0,0,0,.95), inset 0 1px 0 rgba(255,255,255,.04);
}
.cr3-table { width: 100%; min-width: 980px; border-collapse: separate; border-spacing: 0; }
.cr3-table th {
  position: sticky; top: 0; z-index: 1;
  padding: 14px 18px 12px; text-align: left; white-space: nowrap;
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-2);
  background: rgba(10,15,23,.96); border-bottom: 1px solid rgba(255,255,255,.06);
}
.cr3-th-actions { width: 1%; }
.cr3-table td { padding: 12px 18px; vertical-align: middle; border-bottom: 1px solid rgba(255,255,255,.04); font-size: 13px; }
.cr3-table tbody tr:last-child td { border-bottom: 0; }

.cr3-groupe td { padding: 20px 18px 8px; border-bottom: 0; background: transparent; }
.cr3-groupe-l { display: flex; align-items: center; gap: 10px; }
.cr3-groupe-l b { font-size: 13px; font-weight: 650; letter-spacing: .02em; color: var(--n-tx); }
.cr3-groupe-point { width: 8px; height: 8px; border-radius: 999px; background: var(--g, var(--n-tx-2)); box-shadow: 0 0 12px var(--g, transparent); }
.cr3-groupe-n { font-size: 11.5px; padding: 1px 8px; border-radius: 999px; color: var(--n-tx-2); background: rgba(255,255,255,.06); }
.cr3-groupe-qui { font-size: 11.5px; color: var(--n-tx-2); }
.g-demande    { --g: #FF5A63; }
.g-production { --g: #4AA3FF; }
.g-validation { --g: #12D9FF; }
.g-client     { --g: #F2B940; }
.g-livre      { --g: #F2B940; }

/* L'étape Livré (18/09/2026) : deux onglets, « En cours » et
   « Historique » — la liste façon Google Sheet de tout ce qui est livré. */
.cr3-livre { display: flex; flex-direction: column; gap: 14px; }
.cr3-onglets {
  display: inline-flex; align-self: flex-start; gap: 4px; padding: 4px;
  border-radius: 999px; border: 1px solid rgba(255,255,255,.1); background: rgba(255,255,255,.035);
}
.cr3-onglet {
  display: inline-flex; align-items: center; gap: 8px; height: 34px; padding: 0 16px;
  border: 0; border-radius: 999px; background: transparent; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 600; color: var(--n-tx-2);
  transition: color .2s ease, background .2s ease;
}
.cr3-onglet b { font-size: 11.5px; padding: 1px 8px; border-radius: 999px; background: rgba(255,255,255,.07); color: inherit; }
.cr3-onglet:hover { color: var(--n-tx); }
.cr3-onglet.on {
  color: #1A1204; background: linear-gradient(180deg, #FAD377, #E9A92E);
  box-shadow: 0 8px 20px -10px rgba(242,185,64,.85), inset 0 1px 0 rgba(255,255,255,.4);
}
.cr3-onglet.on b { background: rgba(26,18,4,.14); }
.cr3-onglet:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-histo-filtres { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.cr3-filtre {
  height: 34px; padding: 0 12px; border-radius: 999px; cursor: pointer; max-width: 100%;
  font: inherit; font-size: 12.5px; color: var(--n-tx);
  border: 1px solid rgba(255,255,255,.1); background: rgba(255,255,255,.035);
}
.cr3-filtre option { color: #F5F7FA; background: #0E1621; }
.cr3-filtre:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-histo-total { font-size: 12px; color: var(--n-tx-2); }
.cr3-table td.cr3-projet { font-size: 12.5px; color: var(--n-tx-2); max-width: 220px; }
.cr3-table td.cr3-lien { white-space: nowrap; }
.cr3-final-lien { text-decoration: none; }
.cr3-final-lien:hover { box-shadow: 0 0 22px rgba(242,185,64,.75); }
.cr3-final-lien:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.cr3-sheet {
  display: inline-flex; align-items: center; padding: 1px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; color: var(--n-tx-2);
  border: 1px solid rgba(255,255,255,.12);
}
.cr3-histo .cr3-l.st-annule td { opacity: .55; }
.cr3-histo .cr3-l.st-annule .cr3-livrable-t { text-decoration: line-through; text-decoration-color: rgba(255,255,255,.3); }
@media (max-width: 720px) {
  .cr3-onglets { align-self: stretch; }
  .cr3-onglet { flex: 1 1 0; justify-content: center; }
}
.g-sheet      { --g: rgba(140,152,170,.6); }

.cr3-vide-l td { padding: 26px 18px; color: var(--n-tx-2); font-size: 14px; text-align: center; }

.cr3-l { cursor: pointer; animation: cr3-ligne .5s cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--i, 0) * 28ms); }
@keyframes cr3-ligne { from { opacity: 0; transform: translateY(8px); } }
.cr3-l td { transition: background .2s ease; }
.cr3-l td:first-child { box-shadow: inset 3px 0 0 var(--barre, transparent); }
.cr3-l:hover td { background: linear-gradient(90deg, rgba(242,185,64,.055), rgba(255,255,255,.015)); }
.cr3-l:focus-visible { outline: none; }
.cr3-l:focus-visible td { background: rgba(18,217,255,.07); }
.cr3-l.st-demandee       { --barre: #FF5A63; }
.cr3-l.st-a_faire        { --barre: rgba(140,152,170,.55); }
.cr3-l.st-en_cours       { --barre: #4AA3FF; }
.cr3-l.st-a_modifier     { --barre: #F7A928; }
.cr3-l.st-review         { --barre: #12D9FF; }
.cr3-l.st-valide_interne { --barre: #A07BFF; }
.cr3-l.st-envoye_client  { --barre: #F2B940; }
.cr3-l.st-livre          { --barre: #24D981; }
.cr3-l.urgent td { background: rgba(255,77,85,.045); }

.cr3-quand { width: 104px; white-space: nowrap; }
.cr3-jour { font-size: 22px; line-height: 1; font-weight: 700; color: var(--n-tx); }
.cr3-mois { margin-left: 5px; font-size: 10.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--n-tx-2); }
.cr3-ech { display: block; margin-top: 5px; font-size: 11px; font-weight: 600; }
.cr3-ech.orange { color: #F7A928; }
.cr3-ech.rouge  { color: #FF5A63; }
.cr3-sans { color: var(--n-tx-2); }

.cr3-client { min-width: 140px; }
.cr3-client b { display: block; font-size: 13.5px; font-weight: 600; color: var(--n-tx); }
.cr3-client span { display: block; margin-top: 2px; font-size: 12px; color: var(--n-tx-2); }
.cr3-livrable { min-width: 220px; }
.cr3-livrable-l { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.cr3-livrable-t { font-size: 14px; font-weight: 600; color: var(--n-tx); overflow-wrap: anywhere; }
.cr3-modif { display: block; margin-top: 5px; font-size: 12px; color: #F7A928; max-width: 40ch; }

.cr3-qui-l { display: inline-flex; align-items: center; gap: 9px; font-size: 13px; }
.cr3-avatar {
  width: 28px; height: 28px; border-radius: 999px; flex: none;
  display: grid; place-items: center; font-size: 10.5px; font-weight: 700; color: #F5F7FA;
  background: linear-gradient(135deg, rgba(18,217,255,.35), rgba(160,123,255,.35));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
}
.cr3-personne { font-size: 12.5px; color: var(--n-tx-2); font-style: italic; }
.cr3-confier, .cr3-pill {
  appearance: none; -webkit-appearance: none; cursor: pointer;
  height: 30px; padding: 0 30px 0 12px; border-radius: 999px;
  font: inherit; font-size: 12px; font-weight: 600;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 15px) 55%, calc(100% - 10px) 55%;
  background-size: 5px 5px; background-repeat: no-repeat;
  transition: box-shadow .2s ease, border-color .2s ease;
}
.cr3-confier { color: var(--n-tx); border: 1px dashed rgba(255,255,255,.22); background-color: transparent; max-width: 170px; }
.cr3-confier:hover { border-color: rgba(242,185,64,.6); }
.cr3-pill { border: 1px solid transparent; }
.cr3-pill:focus-visible, .cr3-confier:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(18,217,255,.35); }
.cr3-pill.fixe { display: inline-flex; align-items: center; padding: 0 12px; cursor: default; background-image: none; }
.cr3-pill.st-demandee       { color: #FF7A81; background-color: rgba(255,77,85,.12);  border-color: rgba(255,77,85,.35); }
.cr3-pill.st-a_faire        { color: #D5DCE6; background-color: rgba(140,152,170,.12); border-color: rgba(140,152,170,.3); }
.cr3-pill.st-en_cours       { color: #8CC4FF; background-color: rgba(37,139,255,.13); border-color: rgba(37,139,255,.38); }
.cr3-pill.st-a_modifier     { color: #FFC061; background-color: rgba(247,169,40,.13); border-color: rgba(247,169,40,.4); }
.cr3-pill.st-review         { color: #6FE6FF; background-color: rgba(18,217,255,.11); border-color: rgba(18,217,255,.38); }
.cr3-pill.st-valide_interne { color: #C9B4FF; background-color: rgba(139,92,246,.14); border-color: rgba(139,92,246,.42); }
.cr3-pill.st-envoye_client  { color: #FFD57A; background-color: rgba(242,185,64,.13); border-color: rgba(242,185,64,.42); }
.cr3-pill.st-livre          { color: #6CF0B0; background-color: rgba(36,217,129,.12); border-color: rgba(36,217,129,.38); }
.cr3-pill.st-annule         { color: var(--n-tx-2); background-color: transparent; border-color: rgba(255,255,255,.12); }
.cr3-pill option, .cr3-confier option { color: #F5F7FA; background: #0E1621; }

.cr3-actions { width: 1%; white-space: nowrap; text-align: right; }
.cr3-actions-l { display: inline-flex; align-items: center; justify-content: flex-end; gap: 8px; }
.cr3-icone {
  width: 32px; height: 32px; border-radius: 999px; flex: none;
  display: grid; place-items: center; color: var(--n-tx-2);
  border: 1px solid rgba(255,255,255,.1); background: rgba(255,255,255,.03);
  transition: all .2s ease;
}
.cr3-icone:hover { color: #0B121C; background: var(--n-cyan); border-color: var(--n-cyan); box-shadow: 0 0 18px rgba(18,217,255,.45); }
.cr3-icone:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-btn {
  display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 14px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 600; white-space: nowrap;
  color: var(--n-tx); border: 1px solid rgba(255,255,255,.14); background: rgba(255,255,255,.04);
  transition: transform .2s cubic-bezier(.22,1,.36,1), box-shadow .2s ease, background .2s ease;
}
.cr3-btn:hover { transform: translateY(-1px); background: rgba(255,255,255,.08); }
.cr3-btn.fort {
  color: #1A1204; border-color: transparent;
  background: linear-gradient(180deg, #FAD377, #E9A92E);
  box-shadow: 0 8px 20px -10px rgba(242,185,64,.8), inset 0 1px 0 rgba(255,255,255,.4);
}
.cr3-btn.fort:hover { box-shadow: 0 12px 26px -10px rgba(242,185,64,.95), inset 0 1px 0 rgba(255,255,255,.4); }
.cr3-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.cr3-btn:disabled { opacity: .6; cursor: default; transform: none; }

.cr3-pied { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 18px; padding: 0 6px; }

@media (max-width: 1100px) {
  .cr3-piste { flex-direction: column; gap: 14px; }
  .cr3-tout { flex-direction: row; align-items: baseline; gap: 10px; border-right: 0; border-bottom: 1px solid rgba(255,255,255,.07); padding: 0 0 12px; }
}
@media (max-width: 720px) {
  .cr3-hero { align-items: flex-start; }
  .cr3-stats { width: 100%; }
  .cr3-stat { flex: 1 1 0; min-width: 0; padding: 12px 14px; }
  .cr3-stat-n { font-size: 26px; }
  .cr3-etapes { grid-template-columns: repeat(3, minmax(0, 1fr)); padding-top: 10px; }
  .cr3-rail { left: calc(100% / 6); right: calc(100% / 6); top: 27px; }
  .cr3-cherche-boite { flex: 1 1 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .cr3-l, .cr3-bloc, .cr3-pas.on .cr3-pas-rond { animation: none; }
  .cr3-rail-fill, .cr3-pas-rond, .cr3-stat, .cr3-nouvelle, .cr3-btn { transition: none; }
  .cr3-nouvelle:hover::after { transform: translateX(-120%); }
}

/* ── LA CHAÎNE — 18 septembre 2026 (soir) ────────────────────────
   « bhal une chaine, makaynch les barrieres ». Une phrase sous les
   étapes ; « Je prends » bien visible sur chaque demande ; et
   l'HISTORIQUE — le stock des clients livrés — en destination à part,
   au bout du chemin. */
/* Le halo de `.cr3::before` déborde de 40 px : sur téléphone, il
   faisait défiler la page de côté. */
.cr3 { overflow-x: clip; }
.cr3-stat.ton-vert { --ton: #24D981; }

.cr3-chaine {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  margin: -6px 4px 18px; max-width: none; font-size: 12.5px; line-height: 1.5; color: var(--n-tx-2);
}
.cr3-chaine-m { color: var(--n-tx); }
.cr3-chaine-fl { color: var(--n-or); font-weight: 700; }

.cr3-histo-pill {
  flex: none; align-self: center; display: inline-flex; align-items: center; gap: 12px;
  padding: 10px 14px 10px 12px; margin-left: 4px; border-radius: 18px; cursor: pointer;
  font: inherit; color: var(--n-tx); text-align: left;
  border: 1px solid rgba(36,217,129,.28); background: linear-gradient(180deg, rgba(36,217,129,.10), rgba(36,217,129,.03));
  transition: transform .25s cubic-bezier(.22,1,.36,1), border-color .2s ease, box-shadow .25s ease;
}
.cr3-histo-pill:hover { transform: translateY(-2px); border-color: rgba(36,217,129,.55); box-shadow: 0 12px 28px -16px rgba(36,217,129,.7); }
.cr3-histo-pill:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-histo-pill.on { border-color: #24D981; box-shadow: 0 0 0 4px rgba(36,217,129,.14), 0 0 26px rgba(36,217,129,.35); }
.cr3-histo-pill-ico { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 999px; color: #0B121C; background: linear-gradient(180deg, #7CF3BC, #24D981); }
.cr3-histo-pill-t { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cr3-histo-pill-t b { font-size: 14px; font-weight: 650; }
.cr3-histo-pill-t span { font-size: 11px; color: var(--n-tx-2); }
.cr3-histo-pill-n { font-size: 22px; line-height: 1; font-weight: 700; color: #6CF0B0; }

.cr3-personne.libre { color: #FF7A81; font-style: normal; font-weight: 600; }
.cr3-btn.cr3-prendre { height: 36px; padding: 0 18px; font-size: 13.5px; }
.cr3-btn.cr3-prendre svg { flex: none; }

.cr3-clients { display: flex; flex-direction: column; gap: 12px; }
.cr3-clients-h { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
.cr3-clients-h > b { font-size: 16px; font-weight: 650; }
.cr3-clients-n { font-size: 11.5px; padding: 1px 8px; border-radius: 999px; color: #1A1204; background: #6CF0B0; }
.cr3-clients-aide { font-size: 12px; color: var(--n-tx-2); }
.cr3-clients-vide { margin: 0; font-size: 13px; color: var(--n-tx-2); }
.cr3-clients-g { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 12px; }
.cr3-cl {
  display: flex; flex-direction: column; min-width: 0; padding: 0; overflow: hidden; cursor: pointer;
  font: inherit; color: var(--n-tx); text-align: left; border-radius: 16px;
  border: 1px solid rgba(255,255,255,.08); background: linear-gradient(180deg, rgba(13,20,30,.92), rgba(7,11,17,.92));
  animation: cr3-ligne .5s cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--i, 0) * 30ms);
  transition: transform .25s cubic-bezier(.22,1,.36,1), border-color .2s ease, box-shadow .25s ease;
}
.cr3-cl:hover { transform: translateY(-3px); border-color: rgba(255,255,255,.2); }
.cr3-cl:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-cl.on { border-color: #24D981; box-shadow: 0 0 0 3px rgba(36,217,129,.18); }
.cr3-cl-couv { display: block; aspect-ratio: 16 / 9; overflow: hidden; background: #0B121C; }
.cr3-cl-couv > * { width: 100%; height: 100%; }
.cr3-cl-couv img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cr3-cl-t { display: flex; flex-direction: column; gap: 3px; padding: 10px 12px 12px; min-width: 0; }
.cr3-cl-t b { font-size: 13.5px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cr3-cl-meta { display: flex; flex-wrap: wrap; gap: 4px; font-size: 11.5px; color: var(--n-tx-2); }

@media (max-width: 1100px) {
  .cr3-histo-pill { align-self: stretch; margin-left: 0; }
  .cr3-histo-pill-n { margin-left: auto; }
}
@media (max-width: 720px) {
  .cr3-stat { flex: 1 1 calc(50% - 6px); }
  .cr3-clients-g { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .cr3-clients-aide { flex-basis: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .cr3-cl, .cr3-histo-pill { animation: none; transition: none; }
}

/* ============================================================
   43. LA CLOCHE — 16 septembre 2026

   Direction : « mzl les notifications kibarzto bzff ». Plus rien ne
   surgit. Une pastille discrète en bas à droite dit combien de
   choses attendent ; on ouvre quand on veut. Quand il y a du
   nouveau, elle respire deux fois — elle ne s'ouvre pas.
   ============================================================ */
.al-scene .al-rail-u.al-coin {
  top: auto; left: auto; right: 18px; bottom: 18px;
  width: auto; max-width: calc(100vw - 28px); align-items: flex-end; gap: 10px;
}
.al-coin .al-toasts { width: min(320px, calc(100vw - 28px)); }
.al-pastille {
  pointer-events: auto; display: inline-flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 8px 0 14px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--n-tx);
  border: 1px solid rgba(255,255,255,.1);
  background: rgba(12,19,29,.9); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 14px 30px -16px rgba(0,0,0,.9);
  transition: transform .25s cubic-bezier(.22,1,.36,1), border-color .2s ease;
}
.al-pastille[hidden] { display: none; }
.al-pastille:hover { transform: translateY(-2px); border-color: rgba(242,185,64,.45); }
.al-pastille:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.al-pastille svg { color: var(--n-or); }
.al-pastille-l { color: var(--n-tx-2); }
.al-compte {
  min-width: 24px; height: 24px; padding: 0 7px; border-radius: 999px;
  display: grid; place-items: center; font-size: 12px; font-weight: 700; color: #1A1204; background: var(--n-or);
}
.al-pastille.vide .al-compte { color: var(--n-tx-2); background: rgba(255,255,255,.08); }
.al-pastille.on { border-color: rgba(242,185,64,.55); }
.al-pastille.al-nouveau { animation: al-respire 1.4s ease-in-out 2; }
@keyframes al-respire {
  0%, 100% { box-shadow: 0 14px 30px -16px rgba(0,0,0,.9), 0 0 0 0 rgba(242,185,64,.0); }
  50%      { box-shadow: 0 14px 30px -16px rgba(0,0,0,.9), 0 0 0 8px rgba(242,185,64,.18); }
}

.al-panneau {
  pointer-events: auto; width: min(340px, calc(100vw - 28px)); max-height: min(60vh, 520px); overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px; padding: 10px;
  border-radius: 18px; border: 1px solid rgba(255,255,255,.09);
  background: rgba(10,16,24,.96); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 30px 60px -24px rgba(0,0,0,.95);
  transform-origin: bottom right; animation: al-panneau-ouvre .3s cubic-bezier(.22,1,.36,1) both;
}
.al-panneau[hidden] { display: none; }
@keyframes al-panneau-ouvre { from { opacity: 0; transform: translateY(8px) scale(.97); } }
.al-panneau-tete { display: flex; align-items: center; justify-content: space-between; padding: 2px 4px 4px; font-size: 12.5px; color: var(--n-tx); }
.al-panneau .al-carte { animation: none; box-shadow: none; background: rgba(255,255,255,.03); }
.al-panneau .al-carte:nth-of-type(n+2) { display: grid; }

@media (prefers-reduced-motion: reduce) {
  .al-pastille.al-nouveau, .al-panneau { animation: none; }
}

/* ============================================================
   44. CERCLE 25 — MOI / TOUT 25, LE LIEN, LE DÉPÔT SUR LE DRIVE
   16 septembre 2026

   Direction : « filtre moi / all 25… copier le lien… glisser la
   vidéo f wasst l OS… ou zid mzl premium ktar ».
   ============================================================ */

/* Moi / Tout 25 : un curseur doré qui glisse d'une position à l'autre */
.cr3-portee {
  position: relative; isolation: isolate;
  display: inline-grid; grid-template-columns: 1fr 1fr; padding: 4px;
  border-radius: 999px; border: 1px solid rgba(255,255,255,.1); background: rgba(255,255,255,.035);
}
.cr3-portee::before {
  content: ""; position: absolute; z-index: -1; top: 4px; bottom: 4px; left: 4px; width: calc(50% - 4px);
  border-radius: 999px; background: linear-gradient(180deg, #FAD377, #E9A92E);
  box-shadow: 0 8px 20px -10px rgba(242,185,64,.85), inset 0 1px 0 rgba(255,255,255,.4);
  transition: transform .45s cubic-bezier(.22,1,.36,1);
}
.cr3-portee[data-portee="tout"]::before { transform: translateX(100%); }
.cr3-portee-b {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; padding: 0 16px; border: 0; border-radius: 999px; background: transparent; cursor: pointer;
  font: inherit; font-size: 12.5px; font-weight: 600; white-space: nowrap; color: var(--n-tx-2);
  transition: color .3s ease;
}
.cr3-portee[data-portee="moi"] .cr3-portee-b[data-k="moi"],
.cr3-portee[data-portee="tout"] .cr3-portee-b[data-k="tout"] { color: #1A1204; }
.cr3-portee-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

/* Une lumière qui bouge lentement derrière l'en-tête, un titre qui brille */
.cr3::before { background-size: 140% 140%; animation: cr3-aurore 22s ease-in-out infinite alternate; }
@keyframes cr3-aurore {
  0%   { background-position: 0% 0%;   opacity: .8; }
  100% { background-position: 60% 30%; opacity: 1; }
}
.cr3 .cr3-hero .cr3-titre {
  background-image: linear-gradient(95deg, #FFFFFF 0%, #FBEBC2 28%, #F2B940 52%, #FFF3D1 74%, #F2B940 100%);
  background-size: 220% 100%;
  animation: cr3-or 9s ease-in-out infinite;
}
@keyframes cr3-or { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }

/* Un liseré or et cyan autour du tableau */
.cr3-table-boite {
  border-color: transparent;
  background:
    linear-gradient(180deg, rgba(13,20,30,.96), rgba(7,11,17,.96)) padding-box,
    linear-gradient(135deg, rgba(242,185,64,.38), rgba(255,255,255,.05) 38%, rgba(255,255,255,.04) 62%, rgba(18,217,255,.28)) border-box;
}
.cr3-table-boite::-webkit-scrollbar { height: 10px; }
.cr3-table-boite::-webkit-scrollbar-thumb { background: rgba(255,255,255,.12); border-radius: 999px; }
.cr3-table-boite::-webkit-scrollbar-track { background: transparent; }

/* Copier le lien */
.cr3-icone.copie {
  color: #0B121C; background: var(--n-vert); border-color: var(--n-vert);
  box-shadow: 0 0 18px rgba(36,217,129,.5); animation: cr3-pop .35s cubic-bezier(.22,1,.36,1);
}
@keyframes cr3-pop { 50% { transform: scale(1.18); } }
.cr3-presse { position: fixed; left: -9999px; top: 0; width: 1px; height: 1px; opacity: 0; }
.cr3-deposer { display: inline-flex; }

/* Le voile de dépôt : il n'attrape rien, il montre où lâcher */
.cr3-depot {
  position: fixed; inset: 10px; z-index: 70; pointer-events: none;
  display: flex; justify-content: center; align-items: flex-start; padding-top: 22px;
  border-radius: 26px; border: 2px dashed rgba(242,185,64,.75);
  background: radial-gradient(900px 500px at 50% 0%, rgba(242,185,64,.14), transparent 70%), rgba(5,8,13,.22);
  box-shadow: inset 0 0 90px rgba(242,185,64,.18);
  animation: cr3-depot 1.6s ease-in-out infinite;
}
.cr3-depot[hidden] { display: none; }
@keyframes cr3-depot { 50% { border-color: rgba(242,185,64,.32); } }
.cr3-depot-carte {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 16px 28px; text-align: center;
  border-radius: 18px; border: 1px solid rgba(242,185,64,.5); background: rgba(10,16,24,.95);
  box-shadow: 0 30px 60px -20px rgba(0,0,0,.9), 0 0 40px rgba(242,185,64,.25);
  animation: cr3-depot-carte .4s cubic-bezier(.22,1,.36,1) both;
}
@keyframes cr3-depot-carte { from { opacity: 0; transform: translateY(-10px) scale(.96); } }
.cr3-depot-ico {
  width: 52px; height: 52px; border-radius: 999px; display: grid; place-items: center; color: #1A1204;
  background: radial-gradient(circle at 35% 30%, #FFE7A8, #F2B940 60%, #C98A12);
  box-shadow: 0 0 30px rgba(242,185,64,.6);
  animation: cr3-fleche 1.2s ease-in-out infinite;
}
@keyframes cr3-fleche { 50% { transform: translateY(-4px); } }
.cr3-depot-carte b { font-size: 16px; color: var(--n-tx); }
.cr3-depot-carte span:last-child { font-size: 12.5px; color: var(--n-tx-2); }
.cr3-l.cible td { background: linear-gradient(90deg, rgba(242,185,64,.22), rgba(242,185,64,.05)) !important; }
.cr3-l.cible td:first-child { box-shadow: inset 4px 0 0 #F2B940; }
.cr3-l.cible .cr3-livrable-t::after { content: "  ← lâche ici"; color: #F2B940; font-weight: 700; }

/* La vidéo qui part : une barre dans la ligne elle-même */
.cr3-envoi {
  display: grid; grid-template-columns: auto minmax(80px, 1fr) auto; align-items: center; gap: 10px;
  max-width: 380px; margin-top: 8px; font-size: 11.5px; color: var(--n-tx-2);
}
.cr3-envoi-nom { display: inline-flex; align-items: center; gap: 5px; max-width: 150px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: #FFD57A; }
.cr3-envoi-piste { position: relative; height: 6px; overflow: hidden; border-radius: 999px; background: rgba(255,255,255,.08); }
.cr3-envoi-piste i {
  position: absolute; inset: 0 auto 0 0; width: var(--p, 0%); overflow: hidden; border-radius: 999px;
  background: linear-gradient(90deg, #12D9FF, #F2B940); box-shadow: 0 0 12px rgba(242,185,64,.6);
  transition: width .2s linear;
}
.cr3-envoi-piste i::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  animation: cr3-lame 1.1s linear infinite;
}
@keyframes cr3-lame { from { transform: translateX(-100%); } to { transform: translateX(100%); } }

/* « Pour quelle vidéo ? » */
.cr3-choix { display: flex; flex-direction: column; gap: 8px; }
.cr3-choix-b {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 10px 12px; cursor: pointer; text-align: left;
  border-radius: 12px; border: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.03);
  color: var(--n-tx); font: inherit; transition: border-color .2s ease, background .2s ease;
}
.cr3-choix-b:hover { border-color: rgba(242,185,64,.5); background: rgba(242,185,64,.06); }
.cr3-choix-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-choix-t { display: flex; flex-direction: column; min-width: 0; }
.cr3-choix-t b { font-size: 13.5px; }
.cr3-choix-t span { font-size: 12px; color: var(--n-tx-2); }

@media (prefers-reduced-motion: reduce) {
  .cr3::before, .cr3 .cr3-hero .cr3-titre, .cr3-depot, .cr3-depot-carte, .cr3-depot-ico,
  .cr3-envoi-piste i::after, .cr3-icone.copie { animation: none; }
  .cr3-portee::before { transition: none; }
}

/* ============================================================
   45. CERCLE 25 — OR : FINAL · CYAN : ATTEND LA DIRECTION
   16 septembre 2026

   Direction : « darlihom chi couleur gold bli rah final ». Une
   ligne dont le fichier est validé brille en or ; une ligne dont le
   fichier attend la Direction est bordée de cyan, lien sous cadenas.
   ============================================================ */
.cr3-legende { display: flex; flex-wrap: wrap; gap: 8px 22px; padding: 0 6px; font-size: 12px; color: var(--n-tx-2); }
.cr3-legende span { display: inline-flex; align-items: center; gap: 8px; }
.cr3-legende-point { width: 10px; height: 10px; border-radius: 999px; flex: none; }
.cr3-legende-point.final { background: linear-gradient(180deg, #FFE7A8, #F2B940); box-shadow: 0 0 10px rgba(242,185,64,.65); }
.cr3-legende-point.attente { border: 2px dashed #12D9FF; }

/* Le dégradé est posé sur la LIGNE, pas sur chaque cellule : cellule par
   cellule, il recommençait six fois et dessinait des blocs. */
.cr3-l.fichier-final { background: linear-gradient(90deg, rgba(242,185,64,.15), rgba(242,185,64,.03) 55%, transparent); }
.cr3-l.fichier-final:hover { background: linear-gradient(90deg, rgba(242,185,64,.24), rgba(242,185,64,.06) 60%, transparent); }
.cr3-l.fichier-final td, .cr3-l.fichier-final:hover td { background: transparent; }
.cr3-l.fichier-final td:first-child { box-shadow: inset 3px 0 0 #F2B940, inset 14px 0 18px -14px rgba(242,185,64,.7); }
.cr3-l.fichier-final .cr3-livrable-t { color: #FFE7A8; }
.cr3-l.fichier-attente { background: linear-gradient(90deg, rgba(18,217,255,.09), transparent 55%); }
.cr3-l.fichier-attente:hover { background: linear-gradient(90deg, rgba(18,217,255,.15), transparent 60%); }
.cr3-l.fichier-attente td, .cr3-l.fichier-attente:hover td { background: transparent; }
.cr3-l.fichier-attente td:first-child { box-shadow: inset 3px 0 0 #12D9FF; }

.cr3-final {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px 2px 7px; border-radius: 999px;
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: #1A1204; background: linear-gradient(180deg, #FFE7A8, #F2B940);
  box-shadow: 0 0 16px rgba(242,185,64,.45);
}
.cr3-final::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-120%);
  background: linear-gradient(100deg, transparent 35%, rgba(255,255,255,.75) 50%, transparent 65%);
  animation: cr3-reflet 3.4s ease-in-out infinite;
}
@keyframes cr3-reflet { 0%, 60% { transform: translateX(-120%); } 100% { transform: translateX(120%); } }
.cr3-attente-v {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px 2px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 600; color: #6FE6FF;
  border: 1px dashed rgba(18,217,255,.55); background: rgba(18,217,255,.07);
}
.cr3-icone.verrou { color: rgba(255,255,255,.4); border-style: dashed; cursor: help; }
.cr3-icone.verrou:hover { color: rgba(255,255,255,.6); background: rgba(255,255,255,.03); border-color: rgba(255,255,255,.2); box-shadow: none; }

.cr2-carte.fichier-final { border-color: rgba(242,185,64,.6); box-shadow: 0 0 0 1px rgba(242,185,64,.22), 0 22px 44px -28px rgba(242,185,64,.55); }
.cr2-carte.fichier-attente { border-color: rgba(18,217,255,.45); }

@media (prefers-reduced-motion: reduce) { .cr3-final::after { animation: none; } }

/* ============================================================
   46. CERCLE 25 — L'ANCIEN CERCLE RETIRÉ — 16 septembre 2026

   Le projet filtré, le tournage du jour, la couverture du client sur
   chaque carte projet, et les fenêtres au niveau du reste de l'écran.
   ============================================================ */
.cr3-outils > [hidden] { display: none; }
.cr3-puce-projet { display: inline-flex; align-items: center; gap: 6px; max-width: 260px; }
.cr3-puce-projet span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* Le tournage du jour */
.cr3-tournages { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.cr3-tournages:empty { display: none; }
.cr3-tournage {
  position: relative; overflow: hidden; width: 100%;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 26px;
  padding: 14px 20px; border-radius: 18px; cursor: pointer; text-align: left;
  color: var(--n-tx); font: inherit;
  border: 1px solid rgba(74,163,255,.35);
  background: linear-gradient(100deg, rgba(37,139,255,.2), rgba(18,217,255,.06) 45%, rgba(10,16,24,.9) 80%);
  box-shadow: 0 24px 50px -34px rgba(37,139,255,.7);
  transition: transform .25s cubic-bezier(.22,1,.36,1), border-color .2s ease;
}
.cr3-tournage:hover { transform: translateY(-2px); border-color: rgba(74,163,255,.6); }
.cr3-tournage:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.cr3-tournage-ico {
  width: 42px; height: 42px; border-radius: 999px; flex: none; display: grid; place-items: center;
  color: #06121F; background: radial-gradient(circle at 35% 30%, #CFE6FF, #4AA3FF 65%);
  box-shadow: 0 0 0 6px rgba(74,163,255,.12); animation: cr3-rec 2.2s ease-in-out infinite;
}
@keyframes cr3-rec { 50% { box-shadow: 0 0 0 11px rgba(74,163,255,.03); } }
.cr3-tournage-t { display: flex; flex-direction: column; gap: 2px; min-width: 160px; }
.cr3-tournage-sur { font-size: 10.5px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: #8CC4FF; }
.cr3-tournage-t b { font-size: 16px; }
.cr3-tournage-info { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
.cr3-tournage-info i { font-style: normal; font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--n-tx-2); }

/* La carte projet avec la couverture du client */
.cr3-pj { padding-top: 0; }
.cr3-pj-couv {
  position: relative; overflow: hidden; margin: 0 -16px 4px; aspect-ratio: 16 / 7; border-radius: 14px 14px 0 0;
}
.cr3-pj-couv img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .7s cubic-bezier(.22,1,.36,1); }
.cr3-pj:hover .cr3-pj-couv img { transform: scale(1.05); }
.cr3-pj-couv::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(5,8,13,0) 45%, rgba(10,16,24,.95));
}
.cr3-pj-tournage {
  position: absolute; z-index: 1; top: 10px; left: 10px;
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 700; color: #06121F; background: #8CC4FF; box-shadow: 0 6px 16px -6px rgba(74,163,255,.8);
}

/* L'équipe du tournage */
.cr3-equipe { display: flex; flex-wrap: wrap; gap: 8px; }
.cr3-equipe-b {
  display: inline-flex; align-items: center; gap: 8px; padding: 3px 12px 3px 3px; border-radius: 999px; cursor: pointer;
  border: 1px solid rgba(255,255,255,.1); background: transparent; color: var(--n-tx-2); font: inherit; font-size: 12.5px;
  transition: all .2s ease;
}
.cr3-equipe-b.on { color: var(--n-tx); border-color: rgba(242,185,64,.6); background: rgba(242,185,64,.12); }
.cr3-equipe-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }

/* Les fenêtres du CERCLE */
.modal.cr3-modal {
  border-radius: 24px; border: 1px solid transparent;
  background:
    linear-gradient(180deg, rgba(17,25,37,.985), rgba(9,14,21,.985)) padding-box,
    linear-gradient(135deg, rgba(242,185,64,.5), rgba(255,255,255,.06) 40%, rgba(255,255,255,.04) 60%, rgba(18,217,255,.32)) border-box;
  box-shadow: 0 50px 100px -30px rgba(0,0,0,.95), 0 0 80px -40px rgba(242,185,64,.4);
  animation: cr3-fenetre .38s cubic-bezier(.22,1,.36,1) both;
}
@keyframes cr3-fenetre { from { opacity: 0; transform: translateY(14px) scale(.975); } }
.modal.cr3-modal .modal-head { padding-bottom: 14px; border-bottom: 1px solid rgba(255,255,255,.06); }
.modal.cr3-modal .modal-head h3 { font-size: 19px; font-weight: 650; letter-spacing: -.015em; }
.modal.cr3-modal .field > label { font-size: 10.5px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--n-tx-2); }
.modal.cr3-modal .input, .modal.cr3-modal .select, .modal.cr3-modal .textarea {
  border-radius: 12px; border-color: rgba(255,255,255,.09); background-color: rgba(255,255,255,.035);
}
.modal.cr3-modal .input:focus, .modal.cr3-modal .select:focus, .modal.cr3-modal .textarea:focus {
  border-color: rgba(242,185,64,.6); box-shadow: 0 0 0 4px rgba(242,185,64,.12);
}
.modal.cr3-modal .btn-primary {
  border: 0; border-radius: 999px; color: #1A1204; font-weight: 650;
  background: linear-gradient(180deg, #FAD377, #E9A92E);
  box-shadow: 0 10px 24px -12px rgba(242,185,64,.85), inset 0 1px 0 rgba(255,255,255,.4);
}
.modal.cr3-modal .btn-ghost { border-radius: 999px; }
.modal.cr3-modal .cr-seg-b.on { color: #1A1204; background: linear-gradient(180deg, #FAD377, #E9A92E); border-color: transparent; }

@media (prefers-reduced-motion: reduce) {
  .cr3-tournage-ico, .modal.cr3-modal { animation: none; }
  .cr3-pj-couv img, .cr3-tournage { transition: none; }
}

/* 47 — CERCLE 25 : colonne « Chef de projet » (17/09/2026) */
.cr3-avatar.chef { background: linear-gradient(135deg, rgba(212,169,79,.28), rgba(212,169,79,.08)); color: #E8C877; border-color: rgba(212,169,79,.35); }
.cr3-table td.cr3-chef { white-space: nowrap; }

/* 48 — SPIDER : RDV & Rappels (17/09/2026)
   Direction : « zid wahd la liste bach yb9aw les commerciaux ykhadmo
   kolchi f OS ». L'onglet SPIDER qui remplace l'onglet RDV du Google
   Sheet « Suivi_Prospects_Equipe ». Or = aujourd'hui, rouge = en
   retard, cyan = en ligne. ⚠ Le tableau défile dans sa propre boîte :
   à 400 px, c'est lui qui glisse, jamais la page. */
.sp-rdv { display: flex; flex-direction: column; gap: 14px; }

.sp-rdv-tete {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.3fr); gap: 16px 22px; align-items: center;
  padding: 20px 22px; border-radius: 20px; border: 1px solid transparent;
  background:
    linear-gradient(180deg, rgba(17,25,37,.96), rgba(9,14,21,.96)) padding-box,
    linear-gradient(135deg, rgba(242,185,64,.42), rgba(255,255,255,.05) 45%, rgba(139,92,246,.3)) border-box;
  box-shadow: 0 30px 60px -40px rgba(0,0,0,.9);
}
.sp-rdv-titres h3 { margin: 2px 0 4px; font-size: 22px; font-weight: 700; letter-spacing: -.02em; color: var(--n-tx); }
.sp-rdv-titres p { margin: 0; max-width: 52ch; font-size: 13px; line-height: 1.45; color: var(--n-tx-2); }
.sp-rdv-sur { font-size: 10.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--n-or); }

.sp-rdv-compteurs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.sp-rdv-compteur {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0;
  padding: 12px 14px; border-radius: 16px; cursor: pointer; text-align: left; font: inherit;
  color: var(--n-tx); border: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.03);
  transition: transform .18s ease, border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.sp-rdv-compteur b { font-size: 28px; line-height: 1; font-weight: 750; letter-spacing: -.03em; }
.sp-rdv-compteur span { font-size: 13px; font-weight: 650; }
.sp-rdv-compteur small { font-size: 11px; color: var(--n-tx-2); }
.sp-rdv-compteur:hover { transform: translateY(-1px); border-color: rgba(255,255,255,.18); }
.sp-rdv-compteur:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.sp-rdv-compteur.c-auj b { color: #FAD377; }
.sp-rdv-compteur.c-retard b { color: #FF6B72; }
.sp-rdv-compteur.c-avenir b { color: #7FE6FF; }
.sp-rdv-compteur.zero b { color: var(--n-tx-2); }
.sp-rdv-compteur.c-auj.on { border-color: rgba(242,185,64,.7); background: rgba(242,185,64,.12); box-shadow: 0 12px 28px -18px rgba(242,185,64,.9); }
.sp-rdv-compteur.c-retard.on { border-color: rgba(255,77,85,.7); background: rgba(255,77,85,.1); box-shadow: 0 12px 28px -18px rgba(255,77,85,.9); }
.sp-rdv-compteur.c-avenir.on { border-color: rgba(18,217,255,.6); background: rgba(18,217,255,.08); box-shadow: 0 12px 28px -18px rgba(18,217,255,.9); }

.sp-rdv-outils { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.sp-rdv-portee { display: inline-flex; padding: 4px; gap: 4px; border-radius: 999px; border: 1px solid rgba(255,255,255,.08); background: rgba(0,0,0,.25); }
.sp-rdv-p {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 14px; border: 0; border-radius: 999px;
  background: transparent; color: var(--n-tx-2); font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.sp-rdv-p i { font-style: normal; font-size: 11px; padding: 1px 7px; border-radius: 999px; background: rgba(255,255,255,.07); }
.sp-rdv-p.on { color: #1A1204; background: linear-gradient(180deg, #FAD377, #E9A92E); box-shadow: 0 8px 18px -10px rgba(242,185,64,.9); }
.sp-rdv-p.on i { background: rgba(26,18,4,.16); }
.sp-rdv-p:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }
.sp-rdv-cherche { flex: 1 1 220px; min-width: 0; max-width: 420px; border-radius: 999px; padding-left: 16px; }

.sp-rdv-lecture { margin: 0 0 10px; font-size: 12.5px; color: var(--n-tx-2); }

/* Le tableau façon Sheet — mais lisible */
.sp-rdv-defile {
  overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%;
  border-radius: 18px; border: 1px solid rgba(255,255,255,.07);
  background: linear-gradient(180deg, rgba(14,22,33,.9), rgba(7,11,18,.9));
}
.sp-rdv-table { width: 100%; min-width: 860px; border-collapse: separate; border-spacing: 0; font-size: 13px; }
.sp-rdv-table th {
  position: sticky; top: 0; z-index: 1; padding: 11px 14px; text-align: left; white-space: nowrap;
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--n-tx-2);
  background: rgba(10,16,24,.97); border-bottom: 1px solid rgba(255,255,255,.07);
}
.sp-rdv-table td { padding: 12px 14px; vertical-align: top; border-bottom: 1px solid rgba(255,255,255,.045); color: var(--n-tx); }
.sp-rdv-l { --barre: rgba(140,152,170,.4); }
.sp-rdv-l td:first-child { box-shadow: inset 3px 0 0 var(--barre); }
.sp-rdv-l.g-retard { --barre: #FF4D55; }
.sp-rdv-l.g-auj { --barre: #F2B940; }
.sp-rdv-l.g-demain { --barre: rgba(18,217,255,.7); }
.sp-rdv-l.g-auj td { background: rgba(242,185,64,.045); }
.sp-rdv-l:hover td { background: linear-gradient(90deg, rgba(242,185,64,.06), rgba(255,255,255,.015)); }
.sp-rdv-l.fait td { color: var(--n-tx-2); }
.sp-rdv-l.fait .sp-rdv-nom { color: var(--n-tx-2); }

.sp-rdv-groupe td {
  padding: 14px 14px 8px; border-bottom: 0; background: transparent;
  font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--n-tx-2);
}
.sp-rdv-groupe td > * { vertical-align: middle; }
.sp-rdv-groupe i { display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 999px; background: rgba(140,152,170,.6); }
.sp-rdv-groupe span { margin-left: 8px; padding: 1px 8px; border-radius: 999px; background: rgba(255,255,255,.06); letter-spacing: 0; }
.sp-rdv-groupe.g-retard b { color: #FF6B72; }
.sp-rdv-groupe.g-retard i { background: #FF4D55; box-shadow: 0 0 10px rgba(255,77,85,.8); }
.sp-rdv-groupe.g-auj b { color: #FAD377; }
.sp-rdv-groupe.g-auj i { background: #F2B940; box-shadow: 0 0 10px rgba(242,185,64,.8); }
.sp-rdv-groupe.g-demain i { background: var(--n-cyan); }
.sp-rdv-reste td { font-size: 12px; color: var(--n-tx-2); font-style: italic; }

.sp-rdv-quand { width: 130px; white-space: nowrap; }
.sp-rdv-quand b { display: block; font-size: 14px; font-weight: 650; text-transform: capitalize; }
.sp-rdv-h { display: block; margin-top: 3px; font-size: 16px; font-weight: 700; letter-spacing: -.01em; color: var(--n-tx); font-variant-numeric: tabular-nums; }
.sp-rdv-h.vide { font-size: 11.5px; font-weight: 500; color: var(--n-tx-2); }
.sp-rdv-puce {
  display: inline-block; margin-bottom: 6px; padding: 2px 9px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .02em;
}
.sp-rdv-puce.p-retard { color: #FFD3D5; background: rgba(255,77,85,.18); box-shadow: inset 0 0 0 1px rgba(255,77,85,.45); }
.sp-rdv-puce.p-auj { color: #1A1204; background: linear-gradient(180deg, #FAD377, #E9A92E); }
.sp-rdv-puce.p-demain { color: #BFF3FF; background: rgba(18,217,255,.12); box-shadow: inset 0 0 0 1px rgba(18,217,255,.35); }

.sp-rdv-client { min-width: 190px; }
.sp-rdv-nom {
  display: block; padding: 0; border: 0; background: none; font: inherit; text-align: left;
  font-size: 14px; font-weight: 650; color: var(--n-tx); overflow-wrap: anywhere;
}
button.sp-rdv-nom { cursor: pointer; }
button.sp-rdv-nom:hover { color: #FAD377; }
button.sp-rdv-nom:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; border-radius: 4px; }
.sp-rdv-liens { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.sp-rdv-lien {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; text-decoration: none; white-space: nowrap;
  color: var(--n-tx-2); border: 1px solid rgba(255,255,255,.1);
}
.sp-rdv-lien.l-tel:hover { color: var(--n-tx); border-color: rgba(255,255,255,.3); }
.sp-rdv-lien.l-wa { color: #7CF0B4; border-color: rgba(36,217,129,.3); background: rgba(36,217,129,.07); }
.sp-rdv-lien.l-wa:hover { background: rgba(36,217,129,.16); }
.sp-rdv-lien.l-vide { font-style: italic; font-weight: 500; }

.sp-rdv-type-td { white-space: nowrap; }
.sp-rdv-type { display: inline-flex; align-items: center; gap: 7px; padding: 4px 11px; border-radius: 999px; font-size: 12px; font-weight: 650; }
.sp-rdv-type i { width: 7px; height: 7px; border-radius: 999px; background: currentColor; }
.sp-rdv-type.t-en_ligne { color: #7FE6FF; background: rgba(18,217,255,.1); box-shadow: inset 0 0 0 1px rgba(18,217,255,.3); }
.sp-rdv-type.t-sur_place { color: #C4A8FF; background: rgba(139,92,246,.12); box-shadow: inset 0 0 0 1px rgba(139,92,246,.35); }
.sp-rdv-type.t-bureau, .sp-rdv-type.t-rdv { color: #FAD377; background: rgba(242,185,64,.1); box-shadow: inset 0 0 0 1px rgba(242,185,64,.32); }
.sp-rdv-type.t-rappel { color: var(--n-tx); background: rgba(255,255,255,.05); box-shadow: inset 0 0 0 1px rgba(255,255,255,.14); }
.sp-rdv-adresse { display: block; max-width: 170px; margin-top: 5px; overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--n-tx-2); }

.sp-rdv-qui { white-space: nowrap; }
.sp-rdv-qui > span:last-child { margin-left: 8px; vertical-align: middle; font-size: 13px; }
.sp-rdv-qui .cr3-avatar { display: inline-grid; vertical-align: middle; }

.sp-rdv-note-td { min-width: 220px; max-width: 360px; }
.sp-rdv-note {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: 13px; line-height: 1.45; color: var(--n-tx); overflow-wrap: anywhere; cursor: help;
}
.sp-rdv-note.vide { display: inline; font-style: italic; color: var(--n-tx-2); cursor: default; }
.sp-rdv-origine { display: block; margin-top: 4px; font-size: 11px; color: var(--n-tx-2); }

.sp-rdv-th-act { width: 1%; }
.sp-rdv-act { white-space: nowrap; text-align: right; }
.sp-rdv-act .btn + .btn { margin-left: 6px; }
.sp-rdv-b-fait {
  border: 0; border-radius: 999px; color: #1A1204; font-weight: 700;
  background: linear-gradient(180deg, #FAD377, #E9A92E);
  box-shadow: 0 8px 20px -12px rgba(242,185,64,.9), inset 0 1px 0 rgba(255,255,255,.4);
}
.sp-rdv-b-fait:hover { filter: brightness(1.06); }
.sp-rdv-b { border-radius: 999px; }
.sp-rdv-issue { display: inline-block; margin-right: 6px; padding: 3px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; color: var(--n-tx-2); background: rgba(255,255,255,.05); }
.sp-rdv-issue.i-realise, .sp-rdv-issue.i-rappele { color: #7CF0B4; background: rgba(36,217,129,.09); }
.sp-rdv-issue.i-reporte { color: #FAD377; background: rgba(242,185,64,.09); }
.sp-rdv-issue.i-annule { color: #FF9CA1; background: rgba(255,77,85,.09); }
.sp-rdv-lecture-seule { margin-right: 6px; font-size: 11.5px; color: var(--n-tx-2); font-style: italic; }

/* Vide, et historique */
.sp-rdv-vide {
  display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 44px 20px; text-align: center;
  border-radius: 20px; border: 1px dashed rgba(242,185,64,.28); background: rgba(242,185,64,.03);
}
.sp-rdv-vide b { font-size: 16px; color: var(--n-tx); }
.sp-rdv-vide span { max-width: 52ch; font-size: 13px; line-height: 1.5; color: var(--n-tx-2); }
.sp-rdv-vide .btn { margin-top: 6px; }
.sp-rdv-vide-ico { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 18px; color: #FAD377; background: rgba(242,185,64,.1); }
.sp-rdv-vide-doux { padding: 26px 20px; border-style: solid; border-color: rgba(255,255,255,.07); background: transparent; }

.sp-rdv-histo { margin-top: 14px; }
.sp-rdv-histo > summary {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px; cursor: pointer; list-style: none;
  border-radius: 14px; border: 1px solid rgba(255,255,255,.07); background: rgba(255,255,255,.025); color: var(--n-tx);
}
.sp-rdv-histo > summary::-webkit-details-marker { display: none; }
.sp-rdv-histo > summary::before { content: "›"; font-size: 18px; line-height: 1; color: var(--n-tx-2); transition: transform .2s ease; }
.sp-rdv-histo[open] > summary::before { transform: rotate(90deg); }
.sp-rdv-histo > summary span { font-size: 12px; color: var(--n-tx-2); }
.sp-rdv-histo > summary:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 2px; }
.sp-rdv-histo[open] > .sp-rdv-defile { margin-top: 10px; }

/* Les fenêtres de saisie */
.sp-rdv-form { display: flex; flex-direction: column; gap: 14px; }
.sp-rdv-form-sous { margin: 0; font-size: 13px; line-height: 1.45; color: var(--n-tx-2); }
.sp-rdv-duo { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 12px; }
.sp-rdv-rac { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.sp-rdv-rac-b {
  padding: 5px 11px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 12px; font-weight: 600;
  color: var(--n-tx-2); border: 1px solid rgba(255,255,255,.1); background: transparent;
}
.sp-rdv-rac-b:hover { color: var(--n-tx); border-color: rgba(242,185,64,.5); }
.sp-rdv-rac-b:focus-visible { outline: 2px solid var(--n-cyan); outline-offset: 1px; }
.sp-rdv-seg .cr-seg-b { padding: 9px 14px; font-weight: 600; }
.sp-rdv-ta { min-height: 88px; resize: vertical; }
.sp-rdv-suite[hidden] { display: none; }
.sp-rdv-suite { display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 14px; background: rgba(242,185,64,.05); border: 1px solid rgba(242,185,64,.18); }
.sp-rdv-suite-titre { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: #FAD377; }

@media (max-width: 860px) {
  .sp-rdv-tete { grid-template-columns: minmax(0, 1fr); padding: 16px; }
}
@media (max-width: 480px) {
  .sp-rdv-compteurs { gap: 6px; }
  .sp-rdv-compteur { padding: 10px; }
  .sp-rdv-compteur b { font-size: 22px; }
  .sp-rdv-compteur small { display: none; }
  .sp-rdv-cherche { flex-basis: 100%; max-width: none; }
  .sp-rdv-duo { grid-template-columns: minmax(0, 1fr); }
  .sp-rdv-table { min-width: 760px; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-rdv-compteur, .sp-rdv-histo > summary::before { transition: none; }
}



/* ============================================================
   49 — PASSE PREMIUM : TOUT L'OS (17/09/2026)

   Direction : « dir l OS KAML PREMIUM ou classe ». Les deux
   écrans validés — la liste CERCLE 25 (`.cr3-*`, section 42-47)
   et SPIDER · RDV (`.sp-rdv-*`, section 48) — deviennent la
   référence. Cette section n'invente AUCUN langage : elle reprend
   leurs valeurs (rayons, filets, ombres, angles de dégradé,
   durées) et les applique au reste de l'OS.

   ⚠ CE QUI N'EST PAS TOUCHÉ, ET POURQUOI
     · `.cr3-*` et `.sp-*` : validés par la Direction. On harmonise
       VERS eux, jamais eux vers autre chose. Seuls `.table` et
       `.sp-table` (le tableau générique de SPIDER, qui n'a jamais
       eu de traitement propre) sont alignés sur `.cr3-table`.
     · `.me-pas` / `.mini-etapes` (tableau-cercle.css) et `.couv-*`
       (couvertures.css) : ces deux feuilles sont chargées APRÈS
       os25.css. Toute règle de même spécificité y perdrait. On ne
       les vise pas ; les fenêtres `.couv-modal` sont exclues
       nommément des règles de modale.

   ⚠ LA SPÉCIFICITÉ, UNE FOIS POUR TOUTES
   `master-v2.css` impose en `!important` la page, le titre, les
   panneaux, les en-têtes de panneau et les tableaux, depuis
   `.main > .page:not(.dashboard-home):not(.ps-root) …` — soit
   cinq classes. La section 45.1 de ce fichier les a ensuite
   rapetissés depuis quatre classes. Pour reprendre la main sans
   empiler les `!important` au hasard, on ajoute `.app` en tête :
   six classes, ce qui bat les deux. `!important` n'est réécrit
   QUE là où master-v2 ou la section 45.1 forçait déjà la
   propriété — nulle part ailleurs.

   ⚠ AUCUNE POLICE IMPORTÉE, AUCUNE IMAGE DISTANTE : le studio
   travaille hors ligne et la CSP refuserait les deux. On n'utilise
   que Inter et JetBrains Mono, déjà chargées par app.html.
   ============================================================ */

/* =============================================================
   49.0 LE VOCABULAIRE — six jetons, tirés de `.cr3-bloc`

   Ce ne sont pas de nouvelles couleurs : ce sont les valeurs
   littérales de la section 42, nommées une fois pour ne plus être
   recopiées à trente endroits.
   ============================================================= */
:root {
  --pm-r-s: 12px;    /* une puce, un champ, un petit bloc       */
  --pm-r-m: 16px;    /* une carte, une tuile, un encadré        */
  --pm-r-l: 18px;    /* un panneau                              */
  --pm-r-xl: 22px;   /* une boîte de tableau, une fenêtre       */

  --pm-bord:      rgba(255,255,255,.07);
  --pm-bord-fort: rgba(255,255,255,.14);
  --pm-filet:     rgba(255,255,255,.045);   /* séparateur de ligne */

  /* Le fond d'une surface : un dégradé vertical, jamais un aplat —
     c'est ce qui donne la profondeur sans poser d'ombre. Valeurs
     de `.cr3-table-boite`. */
  --pm-surface:   linear-gradient(180deg, rgba(13,20,30,.92), rgba(7,11,17,.92));
  --pm-surface-h: linear-gradient(180deg, rgba(19,28,40,.94), rgba(10,15,23,.94));
  --pm-creux:     rgba(255,255,255,.035);   /* un champ, un encadré */

  --pm-ombre:      0 30px 60px -44px rgba(0,0,0,.95);
  --pm-ombre-forte: 0 40px 80px -50px rgba(0,0,0,.95);
  --pm-lueur-haute: inset 0 1px 0 rgba(255,255,255,.05);

  --pm-or:       #F2B940;
  --pm-or-clair: #FAD377;
  --pm-or-fonce: #E9A92E;
  --pm-encre:    #1A1204;   /* le texte SUR l'or */
  --pm-cyan:     #12D9FF;

  --pm-t: .22s;
  --pm-courbe: cubic-bezier(.22,1,.36,1);
}

/* Le thème clair existe : sans ce repli, les surfaces resteraient
   presque noires sur un fond blanc. Mêmes rayons, mêmes gestes. */
[data-theme="light"] {
  --pm-bord:      rgba(16,23,32,.10);
  --pm-bord-fort: rgba(16,23,32,.20);
  --pm-filet:     rgba(16,23,32,.07);
  --pm-surface:   linear-gradient(180deg, #FFFFFF, #FBFCFD);
  --pm-surface-h: linear-gradient(180deg, #FFFFFF, #F5F7FA);
  --pm-creux:     rgba(16,23,32,.035);
  --pm-ombre:      0 18px 40px -30px rgba(16,23,32,.35);
  --pm-ombre-forte: 0 26px 60px -34px rgba(16,23,32,.4);
  --pm-lueur-haute: inset 0 1px 0 rgba(255,255,255,.7);
  --pm-or:       #B8860B;
  --pm-or-clair: #D9A93A;
  --pm-or-fonce: #9A6E06;
  --pm-encre:    #FFFFFF;
}


/* =============================================================
   49.1 FONDATIONS — l'échelle du texte et la respiration

   La section 45.1 avait descendu tout l'OS à 11,5 px pour gagner
   de la densité. Sur les deux écrans validés, le texte courant
   est à 13-14 px (`.cr3-sous` 14, `.sp-rdv-titres p` 13) : c'est
   ce cran-là qui fait la différence entre « dense » et « serré ».
   On remonte le corps du texte DANS LA PAGE seulement — la barre
   latérale et l'en-tête gardent leur propre échelle, qui est
   validée et n'a pas de raison de bouger.
   ============================================================= */

.app .main > .page:not(.dashboard-home):not(.ps-root):not(.cr3) {
  font-size: 13px;
  line-height: 1.55;
}

/* La marge de page : un cran de plus, des deux côtés. Un écran
   premium respire sur ses bords ; c'est la première chose qu'on
   voit avant même de lire. */
.app .main > .page:not(.dashboard-home):not(.ps-root) {
  padding: 26px 30px 56px !important;
}

/* ── LE TITRE D'ÉCRAN ────────────────────────────────────────
   `.cr3-titre` monte à 52 px : c'est un écran-vitrine. Un écran
   de travail n'a pas besoin d'autant, mais 30 px maximum ne
   tenait plus la page. 38 px, même graisse (750), même chasse
   négative, et le même dégradé blanc → or que le CERCLE, en plus
   sobre : le titre EST l'accent doré de l'écran, il n'en faut pas
   d'autre. */
.app .main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1,
.app .main > .page:not(.dashboard-home):not(.ps-root) > .page-head > b:first-child {
  font-size: clamp(26px, 2.4vw, 38px) !important;
  line-height: 1.04 !important;
  font-weight: 750 !important;
  letter-spacing: -.035em !important;
  margin: 2px 0 0 !important;
  text-wrap: balance;
  /* Le dégradé de `.cr3-titre`, à la virgule près : blanc, crème à
     42 %, or plein au bout. Posé plus tard, l'or ne se voyait pas
     sur un titre d'un seul mot — « Clients » restait blanc. */
  background: linear-gradient(95deg, #FFFFFF 0%, #FBEBC2 42%, #F2B940 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  color: #F5F7FA;
}

/* ⚠ Le dégradé découpé n'existe pas partout. Sans ce repli, un
   navigateur qui ignore `background-clip: text` affiche un titre
   transparent sur fond clair — donc rien. */
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .app .main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1 {
    background: none; -webkit-text-fill-color: currentColor; color: #F5F7FA;
  }
}

/* Le sur-titre de l'en-tête prend l'or, comme `.cr3-sur`. Ailleurs
   dans la page il reste gris : l'or ne se distribue pas. */
.app .main > .page .page-head .eyebrow {
  font-family: var(--f-display);
  font-size: 11px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--pm-or);
}
.app .main > .page .page-head .muted,
.app .main > .page .page-head > div > p {
  margin: 8px 0 0;
  max-width: 62ch;
  font-size: 13.5px; line-height: 1.55;
  color: var(--n-tx-2);
}
.app .main > .page > .page-head { align-items: flex-end; gap: 16px 24px; }
.app .main > .page > .page-head .actions { gap: 10px; align-items: center; }

/* ── LE SUR-TITRE COURANT ────────────────────────────────────
   Il garde son tiret de couleur (section 45.2) ; on ne règle ici
   que la chasse et la graisse, pour qu'il soit le MÊME objet
   partout : 10,5 px, 700, .16em. C'est la mesure de `.cr3-sur` et
   de `.sp-rdv-sur`. */
.app .main .eyebrow {
  font-family: var(--f-display);
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
}

/* ── LE TITRE DE PANNEAU ─────────────────────────────────────
   Un panneau n'est pas un écran : son titre est un sur-titre, pas
   un titre. 12 px, majuscules espacées, comme l'en-tête de
   `.cr3-table`. */
.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-head h2,
.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-head h3,
.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-head > b {
  font-size: 12px !important;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--n-tx);
}

/* Les titres intérieurs — ceux des blocs dans un corps de panneau.
   Trois crans, pas davantage. */
.app .main > .page .panel-body h4,
.app .main > .page .encadre h4 { margin: 0 0 6px; font-size: 14px; font-weight: 650; letter-spacing: -.01em; color: var(--n-tx); }
.app .main > .page .panel-body h5 { margin: 0 0 4px; font-size: 12.5px; font-weight: 650; color: var(--n-tx); }

/* ── LES TEXTES SECONDAIRES ──────────────────────────────────
   `.muted` et `.hint` disaient la même chose à deux tailles et
   deux gris différents selon la feuille qui gagnait. Une seule
   règle : `.muted` est le texte secondaire (même corps que le
   texte courant), `.hint` est l'aide sous un champ (un cran plus
   petit). Les deux au même gris, celui des écrans validés. */
.app .main > .page .muted { color: var(--n-tx-2); }
.app .main > .page .hint {
  font-size: 11.5px; line-height: 1.5;
  color: var(--n-tx-2);
}
.app .main > .page .hint.danger, .app .main > .page .hint.rouge { color: #FF7A81; }

/* ── LES CHIFFRES ────────────────────────────────────────────
   Tabulaires partout où un nombre se compare en colonne. Un
   chiffre qui change de largeur fait sauter la ligne entière. */
.app .main .mono, .app .main .num, .app .main .id, .app .main .tc,
.app .main .tbl td, .app .main .table td, .app .main th,
.app .main .kpi .v, .app .main .kpi b, .app .main .kpi-v,
.app .main .tuile .n, .app .main .badge, .app .main .chip,
.app .main .porte-chiffre b, .app .main .universe-number {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ── LA RESPIRATION VERTICALE ────────────────────────────────
   ⚠ EN `margin-top`, PAS EN `gap`. La page reste un bloc, donc
   les marges verticales fusionnent : un panneau qui porte déjà
   `mb-4` (16 px) et le suivant qui demande 20 px donnent 20, pas
   36. Passer `.page` en flex aurait au contraire ADDITIONNÉ les
   deux et décalé tous les écrans. */
.app .main > .page:not(.dashboard-home):not(.ps-root) > .panel + .panel,
.app .main > .page:not(.dashboard-home):not(.ps-root) > section + section,
.app .main > .page:not(.dashboard-home):not(.ps-root) > .panel + .grid,
.app .main > .page:not(.dashboard-home):not(.ps-root) > .grid + .panel,
.app .main > .page:not(.dashboard-home):not(.ps-root) > .grid + .grid {
  margin-top: 20px;
}


/* =============================================================
   49.2 SURFACES — une seule famille de bords, de fonds, de rayons

   `.panel`, `.card`, `.encadre`, `.tuile`, `.kpi`, `.list-row` :
   six objets, six traitements différents hérités de quatre
   feuilles. Ils reçoivent tous celui de `.cr3-bloc` : filet blanc
   à 7 %, dégradé vertical, ombre basse et large, et un liseré
   clair d'un pixel sur l'arête haute — c'est lui qui fait qu'une
   surface a l'air posée et non peinte.
   ============================================================= */

.app .main > .page:not(.dashboard-home):not(.ps-root) .panel,
.app .main > .page:not(.dashboard-home):not(.ps-root) .card {
  border: 1px solid var(--pm-bord) !important;
  border-radius: var(--pm-r-l) !important;
  background: var(--pm-surface) !important;
  box-shadow: var(--pm-ombre), var(--pm-lueur-haute) !important;
}

.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-head {
  min-height: 52px;
  padding: 15px 18px 12px !important;
  border-bottom: 1px solid var(--pm-filet);
}
.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-body {
  padding: 16px 18px !important;
}
.app .main > .page:not(.dashboard-home):not(.ps-root) .panel-body.flush {
  padding: 0 !important;
}
/* Un panneau sans en-tête ne doit pas commencer par un filet. */
.app .main > .page .panel > .panel-body:first-child { border-top: 0; }

/* Le lien discret en haut à droite d'un panneau. */
.app .main > .page .panel-head .db-lien,
.app .main > .page .panel-head a.btn-sm,
.app .main > .page .panel-head .btn-ghost {
  color: var(--pm-or);
  font-size: 12px; font-weight: 600;
}

/* ── L'ENCADRÉ ───────────────────────────────────────────────
   Un bloc DANS un panneau. Il doit se distinguer sans refaire une
   carte : fond creux à 3,5 %, filet, pas d'ombre. */
.app .main > .page .encadre {
  padding: 14px 16px;
  border-radius: var(--pm-r-m);
  border: 1px solid var(--pm-bord);
  background: var(--pm-creux);
  box-shadow: none;
}
.app .main > .page .encadre.en-appel { border-color: rgba(242,185,64,.55); background: rgba(242,185,64,.06); }

/* ── LA TUILE CHIFFRÉE ───────────────────────────────────────
   Même famille. Le survol n'existe QUE si la tuile est un lien ou
   un bouton : une tuile de lecture qui réagit à la souris promet
   une action qui n'existe pas. */
.app .main > .page .tuile {
  gap: 7px;
  padding: 14px 12px;
  border-radius: var(--pm-r-m);
  border: 1px solid var(--pm-bord);
  background: var(--pm-creux);
  transition: transform var(--pm-t) var(--pm-courbe), border-color var(--pm-t) ease;
}
.app .main > .page .tuile .n { font-size: 24px; line-height: 1; font-weight: 700; letter-spacing: -.02em; color: var(--n-tx); }
.app .main > .page .tuile .l { font-size: 11.5px; color: var(--n-tx-2); }
.app .main > .page .tuile .ico { color: var(--pm-or); }
.app .main > .page a.tuile:hover,
.app .main > .page button.tuile:hover {
  transform: translateY(-2px);
  border-color: var(--pm-bord-fort);
}
.app .main > .page a.tuile:focus-visible,
.app .main > .page button.tuile:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; }

/* ── LE CHIFFRE CLÉ ──────────────────────────────────────────
   Il garde son filet du haut et son halo (section 45.2). On ne
   règle ici que l'échelle : le nombre doit dominer son libellé
   d'un rapport net, comme `.cr3-stat-n` (32) domine `.cr3-stat-l`
   (12). */
.app .main > .page .kpi .v,
.app .main > .page .kpi > b {
  font-size: clamp(22px, 2vw, 28px); line-height: 1;
  font-weight: 750; letter-spacing: -.025em; color: var(--n-tx);
}
.app .main > .page .kpi .l {
  font-family: var(--f-display);
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--n-tx-2);
}
/* La variation sous le chiffre était mesurée trop sombre sur les
   cartes (#22C55E donne moins de 3:1 sur `--pm-surface`). Mêmes
   teintes que les pastilles de `.cr3-pill`, qui passent le seuil. */
.app .main > .page .kpi .d { font-size: 11.5px; font-weight: 600; }
.app .main > .page .kpi .d.up { color: #6CF0B0; }
.app .main > .page .kpi .d.down { color: #FF7A81; }
.app .main > .page .card.kpi { padding: 16px 18px; }

/* ── LA LIGNE DE LISTE ───────────────────────────────────────
   ⚠ LE SURVOL NE S'ALLUME QUE SI LA LIGNE MÈNE QUELQUE PART.
   `neon-systeme.css` éclaire toutes les `.list-row` ; sur une
   liste de lecture (une fiche RH, un récapitulatif), ça fait
   clignoter le bloc au moindre passage de souris et ça promet un
   clic qui ne fera rien. */
.app .main > .page .list-row {
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--pm-filet);
}
.app .main > .page .stack-list > *:last-child,
.app .main > .page .list-row:last-child { border-bottom: 0; }

.app .main > .page .list-row:not(.clickable):not(a):not(button):hover {
  background: transparent;
  box-shadow: none;
}
.app .main > .page .list-row:not(.clickable):not(a):not(button):hover::before {
  transform: scaleY(0);
}
.app .main > .page a.list-row:hover,
.app .main > .page button.list-row:hover,
.app .main > .page .list-row.clickable:hover {
  background: linear-gradient(90deg, rgba(242,185,64,.05), rgba(255,255,255,.012));
}
.app .main > .page a.list-row:focus-visible,
.app .main > .page button.list-row:focus-visible,
.app .main > .page .list-row.clickable:focus-visible {
  outline: 2px solid var(--pm-cyan); outline-offset: -2px; border-radius: var(--pm-r-s);
}

/* ── LA CARTE CLIQUABLE ──────────────────────────────────────
   Le même geste que `.cr3-stat` : deux pixels vers le haut, le
   filet qui s'éclaircit. Pas d'ombre supplémentaire — une ombre
   qui grossit au survol fait « sauter » la grille entière. */
.app .main > .page .card.clickable,
.app .main > .page a.card, .app .main > .page button.card {
  cursor: pointer;
  transition: transform var(--pm-t) var(--pm-courbe), border-color var(--pm-t) ease;
}
.app .main > .page .card.clickable:hover,
.app .main > .page a.card:hover, .app .main > .page button.card:hover {
  transform: translateY(-2px);
  border-color: var(--pm-bord-fort) !important;
}
.app .main > .page .card.clickable:focus-visible,
.app .main > .page a.card:focus-visible, .app .main > .page button.card:focus-visible {
  outline: 2px solid var(--pm-cyan); outline-offset: 2px;
}

/* La grille de cartes : le même écart partout. */
.app .main > .page .grid-2, .app .main > .page .grid-3, .app .main > .page .grid-4 { gap: 14px; }

/* La liste clé/valeur d'une fiche. */
.app .main > .page .kv { gap: 8px 18px; font-size: 13px; }
.app .main > .page .kv dt {
  font-size: 10.5px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--n-tx-2);
}
.app .main > .page .kv dd { color: var(--n-tx); }


/* =============================================================
   49.3 TABLEAUX GÉNÉRIQUES — au niveau de `.cr3-table`

   `.tbl` (28 écrans), `.table` (le conteneur ET, dans SPIDER, la
   table elle-même) et `.sp-table` prennent l'en-tête collant en
   majuscules espacées, les séparateurs à très basse opacité, la
   ligne survolée en dégradé doré, et surtout : leur propre boîte
   de défilement. À 400 px, c'est le tableau qui glisse, jamais la
   page.
   ============================================================= */

.app .main > .page .table-wrap,
.app .main > .page .panel-body.flush.table,
.app .main > .page .panel-body.flush.table-wrap,
.app .main > .page .sp-defile {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}
/* Une boîte posée À RAS du panneau n'a pas de bord à elle : c'est
   celui du panneau. Une boîte posée DANS un corps de panneau en a
   un — sinon le tableau flotte sans cadre. `master-v2.css` en
   donnait un à toutes les deux, d'où le double filet. */
.app .main > .page .panel-body.flush.table,
.app .main > .page .panel-body.flush.table-wrap {
  border: 0;
  border-radius: 0;
}
.app .main > .page .table-wrap:not(.panel-body),
.app .main > .page .sp-defile {
  border: 1px solid var(--pm-bord);
  border-radius: var(--pm-r-m);
  background: var(--pm-surface);
  box-shadow: var(--pm-lueur-haute);
}
/* La barre de défilement du tableau : visible mais discrète, comme
   celle de `.cr3-table-boite`. */
.app .main > .page .table-wrap::-webkit-scrollbar,
.app .main > .page .sp-defile::-webkit-scrollbar,
.app .main > .page .panel-body.flush.table::-webkit-scrollbar { height: 10px; }
.app .main > .page .table-wrap::-webkit-scrollbar-thumb,
.app .main > .page .sp-defile::-webkit-scrollbar-thumb,
.app .main > .page .panel-body.flush.table::-webkit-scrollbar-thumb { background: rgba(255,255,255,.12); border-radius: 999px; }
.app .main > .page .table-wrap::-webkit-scrollbar-track,
.app .main > .page .sp-defile::-webkit-scrollbar-track,
.app .main > .page .panel-body.flush.table::-webkit-scrollbar-track { background: transparent; }

.app .main > .page .tbl,
.app .main > .page table.table,
.app .main > .page .sp-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}

/* ⚠ `!important` ICI, ET SEULEMENT ICI : master-v2 pose
   `.table th { height:46px!important }` et la section 45.1 l'a
   redescendu à 36 px, toujours en `!important`. On ne peut
   répondre qu'avec la même arme. */
.app .main .tbl th,
.app .main .table th,
.app .main .sp-table th {
  position: sticky; top: 0; z-index: 2;
  height: 42px !important;
  padding: 12px 16px;
  text-align: left; white-space: nowrap;
  font-family: var(--f-display);
  font-size: 10.5px !important; font-weight: 600 !important;
  letter-spacing: .14em !important; text-transform: uppercase;
  color: var(--n-tx-2);
  background: rgba(10,15,23,.97);
  border-bottom: 1px solid var(--pm-bord);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.app .main .tbl td,
.app .main .table td,
.app .main .sp-table td {
  padding: 12px 16px !important;
  vertical-align: middle;
  border-bottom: 1px solid var(--pm-filet);
  color: var(--n-tx);
  overflow-wrap: break-word;
}
.app .main > .page .tbl tbody tr:last-child td,
.app .main > .page table.table tbody tr:last-child td,
.app .main > .page .sp-table tbody tr:last-child td { border-bottom: 0; }

/* La première et la dernière colonne prennent l'air du bord : sans
   ça, le texte touche le filet de la boîte. */
.app .main > .page .tbl th:first-child, .app .main > .page .tbl td:first-child,
.app .main > .page table.table th:first-child, .app .main > .page table.table td:first-child,
.app .main > .page .sp-table th:first-child, .app .main > .page .sp-table td:first-child { padding-left: 18px !important; }
.app .main > .page .tbl th:last-child, .app .main > .page .tbl td:last-child,
.app .main > .page table.table th:last-child, .app .main > .page table.table td:last-child,
.app .main > .page .sp-table th:last-child, .app .main > .page .sp-table td:last-child { padding-right: 18px !important; }

/* La ligne survolée : le dégradé doré de `.cr3-l:hover`, pas un
   aplat. Il s'éteint vers la droite, donc il désigne le début de
   la ligne — là où l'œil revient. */
.app .main > .page .tbl tbody tr:hover td,
.app .main > .page table.table tbody tr:hover td,
.app .main > .page .sp-table tbody tr:hover td {
  background: linear-gradient(90deg, rgba(242,185,64,.055), rgba(255,255,255,.012));
}
.app .main > .page .tbl tbody tr.is-on td,
.app .main > .page .tbl tbody tr[aria-selected="true"] td {
  background: rgba(242,185,64,.09);
}
.app .main > .page .tbl tbody tr:focus-visible { outline: none; }
.app .main > .page .tbl tbody tr:focus-visible td { background: rgba(18,217,255,.07); }

/* Les colonnes de chiffres et d'actions ne se coupent pas. */
.app .main > .page .tbl td.mono, .app .main > .page .tbl td.right,
.app .main > .page .table td.mono, .app .main > .page .table td.right { white-space: nowrap; }
.app .main > .page .tbl td .btn, .app .main > .page .table td .btn { white-space: nowrap; }


/* =============================================================
   49.4 BOUTONS ET CHAMPS

   Le langage validé est la PASTILLE : `.cr3-btn`, `.cr3-nouvelle`,
   `.cr3-puce`, `.sp-rdv-p`, et jusqu'aux boutons des fenêtres du
   CERCLE sont tous en 999 px. Les boutons de l'OS suivent, avec la
   même échelle de hauteurs (30 / 36 / 44) et le même or.
   ============================================================= */

.app .btn {
  height: 36px;
  padding: 0 18px;
  gap: 8px;
  border-radius: 999px;
  font-family: var(--f-display);
  font-size: 13px; font-weight: 600;
  letter-spacing: 0;
  transition: transform var(--pm-t) var(--pm-courbe),
              background var(--pm-t) ease,
              border-color var(--pm-t) ease,
              box-shadow var(--pm-t) ease;
}
.app .btn:hover:not(:disabled) { transform: translateY(-1px); }
.app .btn:active:not(:disabled) { transform: translateY(0) scale(.98); transition-duration: 70ms; }

/* ⚠ UN BOUTON NE SE LAISSE PAS ÉCRASER. Dans une `.row` sans
   `wrap`, quatre boutons se partageaient la largeur disponible :
   le plus long — donc l'action principale — rétrécissait le plus,
   et « Enregistrer » s'affichait « regist ». On interdit le
   rétrécissement, et on autorise la rangée à passer à la ligne :
   un bouton qui descend d'une ligne reste lisible, un bouton
   coupé ne l'est pas. `.btn-block` est exclu : il DOIT suivre la
   largeur de son conteneur. */
.app .btn:not(.btn-block) { flex-shrink: 0; }
.app .main > .page .row { flex-wrap: wrap; }
/* Un bouton pleine largeur dans une liste reste aligné à gauche. */
.app .main > .page button.list-row, .app .main > .page a.list-row { text-align: left; }

/* Le secondaire — c'est `.cr3-btn` au repos. */
.app .btn, .app .btn-outline, .app .btn-secondaire {
  color: var(--n-tx);
  border: 1px solid var(--pm-bord-fort);
  background: rgba(255,255,255,.04);
}
.app .btn:hover:not(:disabled),
.app .btn-outline:hover:not(:disabled) { background: rgba(255,255,255,.08); border-color: var(--pm-bord-fort); }

/* Le principal — c'est `.cr3-btn.fort`, au pixel près. Un seul par
   écran, en principe : l'or veut dire « c'est ici qu'on décide ». */
.app .btn-primary, .app .btn-hero, .app .btn-gate {
  color: var(--pm-encre);
  border: 0;
  background: linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce));
  box-shadow: 0 8px 20px -10px rgba(242,185,64,.8), inset 0 1px 0 rgba(255,255,255,.4);
  font-weight: 650;
}
.app .btn-primary:hover:not(:disabled),
.app .btn-hero:hover:not(:disabled),
.app .btn-gate:hover:not(:disabled) {
  filter: none;
  background: linear-gradient(180deg, #FFDE8F, #F0B23A);
  box-shadow: 0 12px 26px -10px rgba(242,185,64,.95), inset 0 1px 0 rgba(255,255,255,.4);
}
/* Un bouton de département garde SA couleur : l'or est réservé à
   la décision du studio, pas à l'étape en cours. */
.app .btn-gate[class*="dep-"] { background: var(--dep, linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce))); }

.app .btn-ghost {
  color: var(--n-tx-2);
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.app .btn-ghost:hover:not(:disabled) { color: var(--n-tx); background: rgba(255,255,255,.06); border-color: transparent; }

.app .btn-danger {
  color: #fff; border: 0;
  background: linear-gradient(180deg, #FF6A71, #EF3F48);
  box-shadow: 0 8px 20px -10px rgba(255,77,85,.8), inset 0 1px 0 rgba(255,255,255,.22);
}
.app .btn-danger:hover:not(:disabled) { background: linear-gradient(180deg, #FF7C82, #F5484F); }

.app .btn-sm { height: 30px; padding: 0 14px; font-size: 12px; }
.app .btn-lg, .app .btn-hero { height: 44px; padding: 0 24px; font-size: 14px; }
.app .btn-block { width: 100%; }
.app .btn.btn-carre { width: 30px; min-width: 30px; height: 30px; padding: 0; border-radius: 999px; }

/* ⚠ Deux écrans forçaient un rayon de 10 px en `!important`
   (master-v2, cockpit technique et fiche mission). On les remet
   dans le rang plutôt que de laisser deux formes de bouton
   cohabiter dans le même OS. */
.app .main .tech-cockpit .btn-primary,
.app .main .mission-page .btn-primary,
.app .main .mission-page .btn-lg.btn-primary { border-radius: 999px !important; }

/* L'ACCESSIBILITÉ N'EST PAS NÉGOCIABLE : un anneau visible sur tout
   ce qui se tabule. Cyan sur les surfaces sombres, blanc sur l'or —
   exactement la règle de `.cr3-btn`. */
.app .btn:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; }
.app .btn-primary:focus-visible,
.app .btn-hero:focus-visible,
.app .btn-danger:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.app .btn:disabled, .app .btn[disabled], .app .btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
  filter: none;
}

/* Le bouton-icône rond, comme `.cr3-icone`. */
.app .main > .page .icon-btn {
  width: 34px; height: 34px;
  border-radius: 999px;
  color: var(--n-tx-2);
  border: 1px solid rgba(255,255,255,.1);
  background: rgba(255,255,255,.03);
  transition: color var(--pm-t) ease, background var(--pm-t) ease, border-color var(--pm-t) ease;
}
.app .main > .page .icon-btn:hover { color: var(--n-tx); background: rgba(255,255,255,.08); border-color: var(--pm-bord-fort); }
.app .icon-btn:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; }

/* ── LES CHAMPS ──────────────────────────────────────────────
   Même hauteur que les boutons (36 → 38 avec le filet), même
   rayon que les blocs, et l'anneau de focus doré de
   `.cr3-cherche` : quatre pixels à 12 % d'or. */
/* ⚠ `background-color`, JAMAIS `background`. Le chevron du menu
   déroulant est dessiné en `background-image` (components.css) :
   la propriété raccourcie l'effacerait, et `.select` deviendrait
   un champ de texte sans flèche. Même raison pour le focus. */
.app .main .input, .app .main .select, .app .main .textarea,
.modal .input, .modal .select, .modal .textarea,
.tiroir .input, .tiroir .select, .tiroir .textarea {
  min-height: 38px;
  padding: 9px 14px;
  border-radius: var(--pm-r-s);
  border: 1px solid rgba(255,255,255,.09);
  background-color: var(--pm-creux);
  color: var(--n-tx);
  font-family: var(--f-display);
  font-size: 13px;
}
/* ⚠ LE CHEVRON DU MENU DÉROULANT AVAIT DISPARU, ET PAS À CAUSE DE
   CETTE SECTION. `master-v2.css` écrit `.input,.select,.textarea{
   background:#09111A}` : la propriété raccourcie efface le
   `background-image` où components.css dessine la flèche. Depuis
   le 7 septembre, tous les `.select` de l'OS étaient donc des
   champs de texte sans repère. On la redessine ici, avec la même
   technique (deux dégradés qui se croisent, zéro image, zéro
   requête réseau — la CSP n'aurait pas laissé passer autre chose). */
.app .main .select, .modal .select, .tiroir .select {
  appearance: none; -webkit-appearance: none;
  padding-right: 34px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--n-tx-2) 50%),
    linear-gradient(135deg, var(--n-tx-2) 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.app .main .select:focus, .modal .select:focus {
  background-image:
    linear-gradient(45deg, transparent 50%, var(--pm-or) 50%),
    linear-gradient(135deg, var(--pm-or) 50%, transparent 50%);
}
.app .main .input::placeholder, .app .main .textarea::placeholder,
.modal .input::placeholder, .modal .textarea::placeholder { color: var(--n-tx-2); }

.app .main .input:focus, .app .main .select:focus, .app .main .textarea:focus,
.app .main .input:focus-visible, .app .main .select:focus-visible, .app .main .textarea:focus-visible,
.modal .input:focus, .modal .select:focus, .modal .textarea:focus {
  outline: none;
  border-color: rgba(242,185,64,.6);
  background-color: rgba(255,255,255,.06);
  box-shadow: 0 0 0 4px rgba(242,185,64,.12);
}
.app .main .input:disabled, .app .main .select:disabled, .app .main .textarea:disabled {
  opacity: .5; cursor: not-allowed;
}
.app .main .textarea { min-height: 96px; line-height: 1.55; resize: vertical; }
.app .main .select-sm { min-height: 30px; padding-block: 4px; font-size: 12px; }
.app .main .select option { color: #F5F7FA; background: #0E1621; }

.app .main .field { gap: 7px; margin-bottom: 14px; }
.app .main .field > label,
.modal .field > label {
  font-family: var(--f-display);
  font-size: 10.5px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--n-tx-2);
}
.app .main .field-row { display: flex; flex-wrap: wrap; gap: 12px; }
.app .main .field-row > .field { flex: 1 1 200px; min-width: 0; }
.app .main .req-mark { color: var(--pm-or); }


/* =============================================================
   49.5 BADGES ET PASTILLES — une seule forme, un seul contraste

   ⚠ L'OR EST RÉSERVÉ À CE QUI EST FINAL OU DÉCIDÉ. C'est la règle
   de la section 45 (« darlihom chi couleur gold bli rah final »).
   Un badge d'attente est orange, un badge d'information est bleu,
   un badge en cours est cyan — jamais or. Les couleurs reprises
   ici sont littéralement celles de `.cr3-pill`, qui ont été
   mesurées lisibles sur fond sombre.
   ============================================================= */

.app .main .badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 10px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--f-display);
  font-size: 11px; font-weight: 600;
  letter-spacing: .01em; white-space: nowrap;
}
.app .main .badge::before { width: 5px; height: 5px; }

.app .main .badge-ok     { color: #6CF0B0; background: rgba(36,217,129,.12);  border-color: rgba(36,217,129,.38); }
.app .main .badge-info   { color: #8CC4FF; background: rgba(37,139,255,.13);  border-color: rgba(37,139,255,.38); }
.app .main .badge-warn   { color: #FFC061; background: rgba(247,169,40,.13);  border-color: rgba(247,169,40,.40); }
.app .main .badge-danger { color: #FF7A81; background: rgba(255,77,85,.12);   border-color: rgba(255,77,85,.35); }
.app .main .badge.plain  { color: #D5DCE6; background: rgba(140,152,170,.12); border-color: rgba(140,152,170,.30); }
.app .main .badge-dep {
  color: var(--dep-tx, var(--dep));
  background: color-mix(in srgb, var(--dep) 13%, transparent);
  border-color: color-mix(in srgb, var(--dep) 34%, transparent);
}
/* Le seul badge doré de l'OS : celui qui dit « c'est fini ». */
.app .main .badge.final, .app .main .badge-final {
  color: var(--pm-encre); border-color: transparent;
  background: linear-gradient(180deg, #FFE7A8, var(--pm-or));
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.app .main .badge.final::before, .app .main .badge-final::before { display: none; }

/* ── LA PUCE DE FILTRE ───────────────────────────────────────
   `.chip` prend la forme et le comportement de `.cr3-puce` : vide
   au repos, or plein quand elle est active. Une puce de
   département garde sa couleur (règle de neon-systeme, conservée
   exprès). */
.app .main .chip {
  height: 30px; padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--pm-bord);
  background: transparent;
  color: var(--n-tx-2);
  font-family: var(--f-display); font-size: 12.5px;
  transition: color var(--pm-t) ease, border-color var(--pm-t) ease, background var(--pm-t) ease;
}
.app .main .chip:hover { color: var(--n-tx); border-color: var(--pm-bord-fort); }
.app .main .chip.is-on:not([class*="dep-"]) {
  color: var(--pm-encre);
  background: var(--pm-or);
  border-color: var(--pm-or);
  font-weight: 600;
  box-shadow: 0 8px 18px -12px rgba(242,185,64,.9);
}
.app .main .chip:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; }

/* Le segment (Jour / Semaine / Mois) : la barre de `.cr3-vues`. */
.app .main .seg {
  display: inline-flex; padding: 4px; gap: 2px;
  border-radius: 999px;
  border: 1px solid var(--pm-bord);
  background: rgba(255,255,255,.03);
}
.app .main .seg-btn {
  height: 32px; padding: 0 16px;
  border: 0; border-radius: 999px;
  background: transparent;
  color: var(--n-tx-2);
  font-family: var(--f-display); font-size: 12.5px; font-weight: 600;
  transition: color var(--pm-t) ease, background var(--pm-t) ease;
}
.app .main .seg-btn.is-on {
  color: var(--n-tx);
  background: rgba(255,255,255,.1);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08);
}
.app .main .seg-btn:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }


/* =============================================================
   49.6 MODALES ET FENÊTRES

   ⚠ CE QUI EST RETIRÉ ICI, ET POURQUOI. La section 24 posait sur
   `.modal` une animation `os25-veille` en `!important` : le filet
   de la fenêtre passait au cyan toutes les 7 secondes, sans fin.
   Sur une fenêtre de saisie qu'on garde ouverte deux minutes,
   c'est un clignotant. Il est éteint pour toutes les fenêtres
   SAUF celles du CERCLE et des couvertures, qui ont leur propre
   contrat validé et ne sont pas touchées.
   ============================================================= */

.modal:not(.cr3-modal):not(.couv-modal) {
  animation: os25-fenetre 380ms var(--pm-courbe) 40ms !important;
  border: 1px solid var(--pm-bord);
  border-radius: var(--pm-r-xl);
  background: linear-gradient(180deg, rgba(17,25,37,.985), rgba(9,14,21,.985));
  box-shadow: 0 50px 100px -34px rgba(0,0,0,.95), var(--pm-lueur-haute);
}
.modal:not(.cr3-modal):not(.couv-modal)::before {
  /* Le filet d'or qui se tire en haut de la fenêtre reste : c'est
     le même geste que la barre sous une couverture, et il ne dure
     qu'une fois. */
  animation: c25-tirer 640ms var(--m-vif) 100ms backwards;
}

.modal-scrim {
  background-color: rgba(3,6,10,.72);
  backdrop-filter: blur(14px) saturate(.9);
  -webkit-backdrop-filter: blur(14px) saturate(.9);
}

.modal:not(.couv-modal) .modal-head {
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--pm-filet);
}
.modal:not(.cr3-modal):not(.couv-modal) .modal-head h3 {
  font-size: 18px; font-weight: 650; letter-spacing: -.015em; color: var(--n-tx);
}
.modal:not(.couv-modal) .modal-body {
  padding: 18px 20px;
  max-height: min(72dvh, 660px);
  overflow-y: auto;
}
.modal:not(.couv-modal) .modal-foot {
  padding: 14px 20px;
  gap: 10px;
  border-top: 1px solid var(--pm-filet);
  background: rgba(0,0,0,.18);
}
.modal .modal-body > p:first-child { margin-top: 0; }
.modal .modal-body { font-size: 13px; line-height: 1.55; }

/* Le tiroir latéral (core/tiroir.js) suit la fenêtre. */
.tiroir { border-left: 1px solid var(--pm-bord); }
.tiroir-titre { font-size: 15px; font-weight: 650; letter-spacing: -.015em; color: var(--n-tx); }
.tiroir-ligne { border-bottom: 1px solid var(--pm-filet); }
.tiroir-ligne:last-child { border-bottom: 0; }
.tiroir-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.tiroir-fermer { border-radius: 999px; }
.tiroir-fond { backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }

/* Sur téléphone, la fenêtre monte du bas et son pied reste
   atteignable au pouce : le corps défile, le pied ne bouge pas. */
@media (max-width: 700px) {
  /* ⚠ LA MÊME CHAÎNE DE `:not()` QU'AU-DESSUS, SINON LA RÈGLE DE
     BUREAU GAGNE. Un `:not()` de moins, c'est une classe de moins
     dans le calcul : la fenêtre gardait ses quatre coins arrondis
     alors qu'elle est collée au bas de l'écran. */
  .modal:not(.cr3-modal):not(.couv-modal) {
    border-radius: var(--pm-r-xl) var(--pm-r-xl) 0 0;
    max-height: 92dvh;
  }
  .modal:not(.couv-modal) .modal-body { max-height: none; padding: 16px; }
  .modal:not(.couv-modal) .modal-head { padding: 16px 16px 12px; }
  .modal:not(.couv-modal) .modal-foot {
    padding: 12px 16px calc(12px + var(--safe-b));
    flex-wrap: wrap;
  }
  .modal:not(.couv-modal) .modal-foot > .btn { flex: 1 1 140px; justify-content: center; }
}


/* =============================================================
   49.7 ÉTATS VIDES ET CHARGEMENT

   « Je ne veux plus de : écran vide, texte loading…, bloc brutal. »

   ⚠ IL Y AVAIT DEUX ICÔNES. `core/ui.js` pose un `.ico` avec un
   dossier dedans ; `neon-systeme.css` ajoutait par-dessus un rond
   gris en `::before`. On garde celui du JavaScript — il porte un
   sens — et on éteint l'autre quand il est là.
   ============================================================= */

.app .main .empty {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 12px; padding: 44px 24px; text-align: center;
  color: var(--n-tx-2);
}
.app .main .empty:has(.ico)::before { display: none; }

.app .main .empty .ico {
  display: grid; place-items: center;
  width: 62px; height: 62px;
  border-radius: 999px;
  color: var(--n-tx-2);
  opacity: 1;
  border: 1px solid var(--pm-bord);
  background: radial-gradient(circle at 50% 38%, rgba(242,185,64,.10), transparent 70%);
  box-shadow: var(--pm-lueur-haute);
}
.app .main .empty h4, .app .main .empty b, .app .main .empty strong {
  margin: 0; font-size: 15px; font-weight: 650; letter-spacing: -.01em; color: var(--n-tx);
}
.app .main .empty p {
  margin: 0; max-width: 44ch;
  font-size: 13px; line-height: 1.55; color: var(--n-tx-2);
}
.app .main .empty .btn { margin-top: 6px; }

/* ── LES SQUELETTES ──────────────────────────────────────────
   Trois longueurs alternées (base.css : 60 / 74 / 88 %) — c'est ce
   qui fait qu'une attente ressemble à du texte et non à un bloc.
   On leur donne la hauteur d'une vraie ligne et le rayon d'une
   pastille, et on espace : trois barres collées font un pavé. */
.app .main .skel, .app .main .skel-line, .app .main .skel-card {
  border-radius: 999px;
  background: linear-gradient(90deg,
              rgba(255,255,255,.04) 25%,
              rgba(255,255,255,.09) 37%,
              rgba(255,255,255,.04) 63%);
  background-size: 400% 100%;
}
.app .main .skel-line { height: 13px; margin-bottom: 12px; }
.app .main .skel-line:last-child { margin-bottom: 0; }
.app .main .skel-card { height: 132px; border-radius: var(--pm-r-l); }


/* =============================================================
   49.8 ÉCRANS CLÉS — l'en-tête, puis le détail

   Rien de structurel : de l'espacement, de la hiérarchie, et des
   en-têtes qui ressemblent au hero du CERCLE en plus petit. Aucun
   fichier .js n'est touché ; on ne vise que des classes qui
   existent déjà dans le balisage.
   ============================================================= */

/* ── L'ACCUEIL (pages/dashboard.js, tableau-cercle.css) ──────
   master-v2 tient l'accueil en `!important` sur presque tout. On
   n'y remet la main que sur trois points : le bas de page, les
   indicateurs et le mot du jour. */
.app .main > .page.dashboard-home .bottom-grid > .panel {
  border: 1px solid var(--pm-bord) !important;
  background: var(--pm-surface) !important;
  box-shadow: var(--pm-ombre), var(--pm-lueur-haute) !important;
}
.app .main > .page.dashboard-home .db-indicateurs .kpi-carte {
  border-radius: var(--pm-r-m);
  border: 1px solid var(--pm-bord);
  background: var(--pm-creux);
}
.app .main > .page.dashboard-home .kpi-v { font-family: var(--f-display); font-size: 26px; font-weight: 750; letter-spacing: -.03em; }
.app .main > .page.dashboard-home .kpi-l {
  font-size: 10.5px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--n-tx-2);
}
.app .main > .page.dashboard-home .mot-jour { border-radius: var(--pm-r-m); }
.app .main > .page.dashboard-home .profil-barre { border-radius: 999px; }
.app .main > .page.dashboard-home .panel-head h3 { letter-spacing: .09em; }

/* ── CLIENTS ET CLIENT 360 (pages/clients.js) ────────────────
   ⚠ `.couv-*` appartient à couvertures.css, chargé APRÈS celui-ci :
   on ne vise pas ces classes. Seuls les objets génériques de
   l'écran sont repris. */
.app .main > .page .dossier-hero h1 { letter-spacing: -.04em; }
.app .main > .page .dossier-id {
  font-family: var(--f-mono); font-size: 10.5px;
  letter-spacing: .1em; color: var(--n-tx-2);
}
.app .main > .page .avatar.xl { box-shadow: 0 0 0 1px var(--pm-bord), var(--pm-ombre); }

/* ── MON TRAVAIL (pages/mon-travail.js) ──────────────────────
   L'en-tête de la mission du jour prend la mesure du hero CERCLE,
   d'un cran plus bas. */
.app .main > .page .ma-kicker {
  font-size: 10.5px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; color: var(--pm-or);
}
.app .main > .page .ma-titre { letter-spacing: -.035em; text-wrap: balance; }
.app .main > .page .ma-sous { font-size: 13.5px; line-height: 1.55; max-width: 58ch; color: var(--n-tx-2); }
.app .main > .page .ma-pill { border-radius: 999px; }
.app .main > .page .ma-actions { gap: 10px; }

/* ── AGENDA (pages/agenda.js) ────────────────────────────────
   La grille garde sa géométrie ; seuls les bords et les creux
   passent à la famille commune. */
.app .main > .page .agenda-titre { font-size: 17px; font-weight: 650; letter-spacing: -.02em; }
.app .main > .page .ag-panneau { border-radius: var(--pm-r-l); }
.app .main > .page .mois-case { border-radius: var(--pm-r-s); border-color: var(--pm-bord); }
.app .main > .page .mois-case.auj { border-color: rgba(242,185,64,.6); background: rgba(242,185,64,.05); }
.app .main > .page .mini-case { border-radius: 8px; }
.app .main > .page .ag-pastille, .app .main > .page .mois-event { border-radius: 999px; }

/* ── ÉQUIPE / RH (pages/equipe-unifiee.js, rh-collaborateur.js) */
.app .main > .page .eq-carte { border-radius: var(--pm-r-m); }
.app .main > .page .profil-ligne {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 7px 0; border-bottom: 1px solid var(--pm-filet);
}
.app .main > .page .profil-ligne:last-child { border-bottom: 0; }
.app .main > .page .profil-ligne .l { font-size: 12px; color: var(--n-tx-2); }
.app .main > .page .profil-ligne .v { font-weight: 650; color: var(--n-tx); }
.app .main > .page .gate-bar { border-radius: var(--pm-r-m); border: 1px solid var(--pm-bord); }
.app .main > .page .net-periode { border-radius: var(--pm-r-m); }

/* ── GUIDE ET DOCUMENTS ──────────────────────────────────────
   Deux écrans de lecture : la largeur de ligne compte plus que
   tout le reste. 68 caractères, c'est le confort mesuré. */
.app .main > .page .measure { max-width: 68ch; }
.app .main > .page .liste-puces { font-size: 13px; line-height: 1.6; color: var(--n-tx-2); }
.app .main > .page .liste-puces li { margin-bottom: 5px; }
.app .main > .page .liste-puces li::marker { color: var(--pm-or); }
.app .main > .page .chemin-etape { border-radius: var(--pm-r-m); border: 1px solid var(--pm-bord); }
.app .main > .page .chemin-num, .app .main > .page .guide-num {
  border-radius: 999px; font-variant-numeric: tabular-nums;
}
.app .main > .page .onglets-projet { border-radius: 999px; border: 1px solid var(--pm-bord); }

/* ── LE TÉLÉPHONE ────────────────────────────────────────────
   ⚠ RIEN NE DOIT DÉPASSER EN LARGEUR. La règle existait (section
   43.2) ; on la redit pour ce que cette section ajoute, et on
   redonne au titre sa taille de téléphone — sinon la règle de
   49.1, plus spécifique, s'appliquerait aussi à 390 px. */
@media (max-width: 700px) {
  .app .main > .page:not(.dashboard-home):not(.ps-root) {
    padding: 16px 14px 96px !important;
  }
  .app .main > .page:not(.dashboard-home):not(.ps-root) > .page-head h1,
  .app .main > .page:not(.dashboard-home):not(.ps-root) > .page-head > b:first-child {
    font-size: clamp(22px, 6.6vw, 28px) !important;
  }
  .app .main > .page:not(.dashboard-home):not(.ps-root) .panel-head {
    min-height: 46px; padding: 12px 14px !important;
  }
  .app .main > .page:not(.dashboard-home):not(.ps-root) .panel-body { padding: 12px 14px !important; }
  .app .main > .page .list-row { padding: 12px 14px; }
  .app .main .tbl th, .app .main .table th, .app .main .sp-table th { height: 38px !important; }
  .app .main .tbl td, .app .main .table td, .app .main .sp-table td { padding: 10px 12px !important; }
  .app .main > .page .tbl th:first-child, .app .main > .page .tbl td:first-child,
  .app .main > .page table.table th:first-child, .app .main > .page table.table td:first-child,
  .app .main > .page .sp-table th:first-child, .app .main > .page .sp-table td:first-child { padding-left: 14px !important; }
  .app .main > .page .grid-2, .app .main > .page .grid-3, .app .main > .page .grid-4 { gap: 10px; }
  .app .main > .page .page-head .actions { width: 100%; }
  .app .main > .page .page-head .actions > .btn { flex: 1 1 auto; justify-content: center; }
  /* Une boîte de tableau ne déborde jamais de son panneau. */
  .app .main > .page .table-wrap,
  .app .main > .page .panel-body.flush.table,
  .app .main > .page .panel-body.flush.table-wrap,
  .app .main > .page .sp-defile { max-width: 100%; overflow-x: auto; }

  /* ⚠⚠ LE TABLEAU SUR TÉLÉPHONE ÉTAIT CASSÉ, ET DEPUIS LONGTEMPS.

     Deux stratégies opposées cohabitaient, écrites à trois
     semaines d'écart :

       · `components.css` (≤ 700 px) met chaque ligne à plat en
         carte — `table`, `tbody`, `tr`, `td` passent en `block`,
         le `<thead>` est déplacé hors de l'écran, et le nom de
         colonne doit revenir par `td[data-col]::before` ;
       · `neon-systeme.css` (≤ 560 px), chargé APRÈS, redonne au
         tableau `min-width: 640px` et remet la boîte en
         défilement horizontal.

     Résultat réel, mesuré à 400 px : les « cartes » font 640 px
     de large dans une boîte de 370, avec `text-align: right` —
     toutes les valeurs sortaient de l'écran. Le tableau était
     VIDE à l'œil.

     Et la carte ne pouvait de toute façon pas fonctionner : le
     commentaire de components.css confie l'étiquette à
     `etiqueterTableaux()` (core/ui.js) — cette fonction N'EXISTE
     NULLE PART dans le code. Aucun `data-col` n'est jamais posé,
     donc entre 561 et 700 px on obtenait une colonne de valeurs
     alignées à droite, sans un seul nom de colonne.

     On tranche pour la boîte qui défile : c'est ce que font les
     deux écrans validés (`.cr3-table`, `.sp-rdv-table`), c'est
     lisible, et ça ne dépend d'aucun JavaScript. La page, elle,
     ne défile toujours pas — c'est le tableau qui glisse. */
  .app .main > .page .table-wrap table.tbl {
    display: table; width: 100%; min-width: 640px;
  }
  .app .main > .page .table-wrap .tbl thead {
    display: table-header-group;
    position: static; width: auto; height: auto;
    overflow: visible; clip-path: none; white-space: nowrap;
  }
  .app .main > .page .table-wrap .tbl tbody { display: table-row-group; width: auto; }
  .app .main > .page .table-wrap .tbl tbody tr {
    display: table-row; width: auto;
    margin: 0; padding: 0;
    border: 0; border-radius: 0; background: transparent;
  }
  .app .main > .page .table-wrap .tbl tbody td {
    display: table-cell; width: auto; text-align: left;
  }
  .app .main > .page .table-wrap .tbl tbody td.right,
  .app .main > .page .table-wrap .tbl tbody td.center { text-align: right; }
  .app .main > .page .table-wrap .tbl tbody td.center { text-align: center; }
  .app .main > .page .table-wrap .tbl tbody td::before { content: none; display: none; }

  /* Les tableaux qui n'ont jamais eu de mode carte gardent leur
     largeur de lecture et glissent dans leur boîte. */
  .app .main > .page .sp-defile .sp-table,
  .app .main > .page .sp-defile table.table { min-width: 720px; }
}

/* Poste de montage : la page a de la place, on la lui laisse. */
@media (min-width: 1500px) {
  .app .main > .page:not(.dashboard-home):not(.ps-root) {
    padding: 30px 40px 64px !important;
  }
}


/* =============================================================
   49.9 IMPRESSION — fond blanc, encre noire, rien qui brille

   ⚠ CE BLOC RÉPARE AUTANT QU'IL HABILLE. La section 35 pose
   `body * { visibility: hidden }` pour n'imprimer que la feuille
   de point SPIDER (`.sp-feuille`). La règle est globale : depuis,
   imprimer N'IMPORTE QUEL autre écran donnait une page blanche.
   On rend la vue aux pages qui ne contiennent pas de `.sp-feuille`
   — la feuille SPIDER, elle, garde son comportement exact.
   ============================================================= */
@media print {
  @page { margin: 14mm; }

  body:not(:has(.sp-feuille)) * { visibility: visible !important; }

  html, body:not(:has(.sp-feuille)),
  body:not(:has(.sp-feuille)) .app,
  body:not(:has(.sp-feuille)) .main,
  body:not(:has(.sp-feuille)) .page {
    background: #FFFFFF !important;
    color: #101418 !important;
  }
  body:not(:has(.sp-feuille)) .app { display: block !important; }
  body:not(:has(.sp-feuille)) .main { overflow: visible !important; height: auto !important; }
  body:not(:has(.sp-feuille)) .page {
    max-width: none !important;
    padding: 0 !important;
    animation: none !important;
  }

  /* Ce qui ne s'imprime pas : la navigation, les outils, les
     couches flottantes. Une feuille imprimée n'a pas de boutons. */
  body:not(:has(.sp-feuille)) .sidebar,
  body:not(:has(.sp-feuille)) .header,
  body:not(:has(.sp-feuille)) .nav-scrim,
  body:not(:has(.sp-feuille)) .toasts,
  body:not(:has(.sp-feuille)) .modal-scrim,
  body:not(:has(.sp-feuille)) .tiroir,
  body:not(:has(.sp-feuille)) .assistant-bulle,
  body:not(:has(.sp-feuille)) .assistant-panneau,
  body:not(:has(.sp-feuille)) .cr3-depot,
  body:not(:has(.sp-feuille)) .icon-btn,
  body:not(:has(.sp-feuille)) .btn,
  body:not(:has(.sp-feuille)) .seg,
  body:not(:has(.sp-feuille)) .noprint {
    display: none !important;
  }

  /* Les surfaces : un filet gris, pas une ombre. Une ombre à
     l'impression sort en aplat sale et mange l'encre. */
  body:not(:has(.sp-feuille)) .panel,
  body:not(:has(.sp-feuille)) .card,
  body:not(:has(.sp-feuille)) .encadre,
  body:not(:has(.sp-feuille)) .tuile,
  body:not(:has(.sp-feuille)) .table-wrap,
  body:not(:has(.sp-feuille)) .modal {
    background: #FFFFFF !important;
    color: #101418 !important;
    border: 1px solid #C8CED6 !important;
    border-radius: 6px !important;
    box-shadow: none !important;
    break-inside: avoid;
  }
  body:not(:has(.sp-feuille)) .panel { margin-bottom: 10mm !important; }

  /* Le texte : noir sur blanc, y compris les titres en dégradé —
     un titre découpé dans une image s'imprime invisible. */
  body:not(:has(.sp-feuille)) h1,
  body:not(:has(.sp-feuille)) h2,
  body:not(:has(.sp-feuille)) h3,
  body:not(:has(.sp-feuille)) h4 {
    background: none !important;
    -webkit-text-fill-color: #101418 !important;
    color: #101418 !important;
  }
  body:not(:has(.sp-feuille)) .muted,
  body:not(:has(.sp-feuille)) .hint,
  body:not(:has(.sp-feuille)) .eyebrow,
  body:not(:has(.sp-feuille)) .kv dt { color: #4A5260 !important; }
  body:not(:has(.sp-feuille)) .eyebrow::before { display: none !important; }

  /* Les tableaux : des filets, un en-tête gris clair, et jamais de
     ligne coupée entre deux pages. */
  body:not(:has(.sp-feuille)) .tbl th,
  body:not(:has(.sp-feuille)) .table th,
  body:not(:has(.sp-feuille)) .sp-table th {
    position: static !important;
    background: #F1F3F6 !important;
    color: #3A424F !important;
    border-bottom: 1px solid #C8CED6 !important;
    backdrop-filter: none !important;
  }
  body:not(:has(.sp-feuille)) .tbl td,
  body:not(:has(.sp-feuille)) .table td,
  body:not(:has(.sp-feuille)) .sp-table td {
    color: #101418 !important;
    border-bottom: 1px solid #DEE2E8 !important;
  }
  body:not(:has(.sp-feuille)) tr { break-inside: avoid; }
  body:not(:has(.sp-feuille)) .table-wrap,
  body:not(:has(.sp-feuille)) .sp-defile,
  body:not(:has(.sp-feuille)) .panel-body.flush.table { overflow: visible !important; }

  /* Les pastilles gardent leur sens mais perdent leur fond
     coloré : à l'impression, c'est le mot qui porte, pas la
     couleur — et beaucoup d'imprimantes sont en noir et blanc. */
  body:not(:has(.sp-feuille)) .badge,
  body:not(:has(.sp-feuille)) .chip {
    background: none !important;
    color: #101418 !important;
    border: 1px solid #9BA3AE !important;
    box-shadow: none !important;
  }
  body:not(:has(.sp-feuille)) .badge::before { display: none !important; }

  /* Rien ne bouge sur du papier. */
  body:not(:has(.sp-feuille)) *,
  body:not(:has(.sp-feuille)) *::before,
  body:not(:has(.sp-feuille)) *::after {
    animation: none !important;
    transition: none !important;
    text-shadow: none !important;
  }
}


/* =============================================================
   49.10 MOINS DE MOUVEMENT

   Tout ce que cette section ajoute de mouvant s'éteint si la
   personne l'a demandé au système. Ce n'est pas une option : sur
   certains troubles vestibulaires, une carte qui monte de deux
   pixels suffit à donner la nausée.
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  .app .btn,
  .app .main > .page .tuile,
  .app .main > .page .card.clickable,
  .app .main > .page a.card, .app .main > .page button.card,
  .app .main > .page .icon-btn,
  .app .main .chip,
  .app .main .seg-btn,
  .app .main .skel, .app .main .skel-line, .app .main .skel-card {
    transition: none !important;
    animation: none !important;
  }
  .app .btn:hover:not(:disabled),
  .app .main > .page a.tuile:hover,
  .app .main > .page button.tuile:hover,
  .app .main > .page .card.clickable:hover,
  .app .main > .page a.card:hover,
  .app .main > .page button.card:hover {
    transform: none;
  }
  /* Le squelette garde une teinte lisible au lieu de clignoter. */
  .app .main .skel, .app .main .skel-line, .app .main .skel-card {
    background: rgba(255,255,255,.06);
  }
  .modal:not(.cr3-modal):not(.couv-modal) { animation: none !important; }
  .modal:not(.cr3-modal):not(.couv-modal)::before { animation: none !important; }
}

/* =========================================================================
   50 — ÉCRITURE PLUS FINE — 17 septembre 2026

   Direction : « saghaar lktaba ou 9adha yji zwin ». La passe 49 a rangé
   l'OS ; il reste à alléger le texte. Tout descend d'environ un cran :
   les titres surtout, le corps à peine.

   ⚠ DEUX PLANCHERS À NE PAS FRANCHIR.
     • 11 px pour un texte qu'on lit (une ligne de tableau, une note) ;
       en dessous, l'écran se lit à la loupe et l'équipe agrandit la page.
     • 16 px pour un <select> SUR TÉLÉPHONE : Safari zoome de lui-même
       sur un champ plus petit, et la page reste zoomée après. La pastille
       de statut garde donc sa taille sous 640 px.
   ========================================================================= */

/* ── Les titres : c'est là que le gain se voit ─────────────────────── */
:is(.app, body) .cr3 .cr3-hero .cr3-titre,
:is(.app, body) .cr3-titre { font-size: clamp(26px, 3.4vw, 36px) !important; letter-spacing: -.03em !important; }
:is(.app, body) .cr3-sous { font-size: 12.5px; }
:is(.app, body) .page-head h1 { font-size: clamp(21px, 2.3vw, 29px); letter-spacing: -.02em; }
:is(.app, body) .page-head .muted, :is(.app, body) .page-head p { font-size: 12px; }
:is(.app, body) .panel-head h2 { font-size: 15px; }
:is(.app, body) .panel-head h3, :is(.app, body) .panel-head b { font-size: 13px; }
.app h4 { font-size: 12.5px; }
:is(.app, body) .eyebrow { font-size: 9.5px; letter-spacing: .14em; }

/* ── Les chiffres : plus petits, toujours lisibles de loin ─────────── */
:is(.app, body) .cr3-stat-n { font-size: 22px; }
:is(.app, body) .cr3-stat-l { font-size: 10px; }
:is(.app, body) .kpi-v, :is(.app, body) .tuile .n, :is(.app, body) .kpi .v { font-size: 20px; }
:is(.app, body) .kpi-l, :is(.app, body) .tuile .l, :is(.app, body) .kpi .l { font-size: 10.5px; }

/* ── Le corps et les tableaux ───────────────────────────────────────── */
:is(.app, body) .page { font-size: 12px; }
:is(.app, body) .muted, :is(.app, body) .hint { font-size: 11.5px; }
:is(.app, body) .cr3-table th, :is(.app, body) .sp-rdv-table th, :is(.app, body) .table th, :is(.app, body) .sp-table th { font-size: 10px; }
:is(.app, body) .cr3-table td, :is(.app, body) .sp-rdv-table td, :is(.app, body) .table td, :is(.app, body) .sp-table td { font-size: 12px; }
:is(.app, body) .cr3-livrable-t { font-size: 12.75px; }
:is(.app, body) .cr3-client b { font-size: 12.5px; }
:is(.app, body) .cr3-qui-l, :is(.app, body) .cr3-chef { font-size: 11.5px; }
:is(.app, body) .cr3-avatar { width: 25px; height: 25px; font-size: 9.5px; }

/* ── Boutons, pastilles, badges ─────────────────────────────────────── */
:is(.app, body) .cr3-btn { font-size: 11.75px; }
:is(.app, body) .btn { font-size: 12px; }
:is(.app, body) .btn-sm { font-size: 11.25px; }
:is(.app, body) .badge, :is(.app, body) .chip { font-size: 10.5px; }
@media (min-width: 641px) {
  :is(.app, body) .cr3-pill, :is(.app, body) .cr3-confier { font-size: 11.5px; }
  :is(.app, body) .select, :is(.app, body) .input, :is(.app, body) .textarea { font-size: 12px; }
}

/* ── Le texte long garde sa mesure : plus petit, donc plus étroit ───── */
:is(.app, body) .measure, :is(.app, body) .guide p, :is(.app, body) .page > p { max-width: 68ch; }

/* =========================================================================
   51 — MENU RÉDUIT : LA CARTE « LE STUDIO » — 17 septembre 2026

   Menu replié, la carte du bas gardait ses textes dans 68 px de large :
   « LE STU », « Ac et ho ». Repliée, elle ne garde que l'essentiel —
   l'interrupteur d'ouverture du studio — et le reste revient dès que le
   menu est déplié. Rien n'est supprimé, seulement caché à cette largeur.
   ========================================================================= */
.app[data-nav="collapsed"] .nav-direction { padding-top: 10px; }
.app[data-nav="collapsed"] .studio-console {
  padding: 10px 6px; display: grid; justify-items: center; gap: 8px;
}
.app[data-nav="collapsed"] .studio-console .sc-titre,
.app[data-nav="collapsed"] .studio-console .sc-texte,
.app[data-nav="collapsed"] .studio-console .sc-lien span,
.app[data-nav="collapsed"] .studio-console .sc-action span { display: none; }
.app[data-nav="collapsed"] .studio-console .sc-bascule { margin: 0; }
/* ⚠ Le libellé de « Accès et horaires » est un NŒUD TEXTE nu à côté de
   l'icône, pas un <span> : on ne peut pas le cacher par un sélecteur.
   La taille zéro sur le lien l'efface, l'icône reprend la sienne. */
.app[data-nav="collapsed"] .studio-console .sc-lien {
  justify-content: center; padding: 6px; width: 34px; min-width: 0;
  font-size: 0; gap: 0;
}
.app[data-nav="collapsed"] .studio-console .sc-lien .ico { font-size: 12px; }
.app[data-nav="collapsed"] .studio-console .sc-lien .ico svg { width: 15px; height: 15px; }
/* L'interrupteur tenait 73 px de large dans une carte de 43 : il s'étire
   maintenant à la carte, sans marge intérieure. */
.app[data-nav="collapsed"] .studio-console .sc-bascule {
  width: 100%; min-width: 0; padding: 0; justify-content: center; gap: 0;
}
.app[data-nav="collapsed"] .studio-console { padding: 10px 4px; }

/* =========================================================================
   52 — LA PASTILLE « À FAIRE » DANS L'EN-TÊTE — 18 septembre 2026

   Direction : « notif jaw fou9 l 25 AI ». En bas à droite, la pastille
   recouvrait le bouton de l'assistant. Elle se range maintenant dans
   l'en-tête, à côté de la cloche ; son panneau et les messages « Fait »
   s'ouvrent sous l'en-tête, en haut à droite — plus rien ne touche le
   coin de l'assistant.
   ========================================================================= */
.al-pastille.al-entete {
  height: 34px; padding: 0 6px 0 12px; font-size: 11.5px; flex: none;
  background: rgba(255,255,255,.03); box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
}
.al-pastille.al-entete:hover { transform: none; border-color: rgba(242,185,64,.45); }
.al-pastille.al-entete .al-compte { min-width: 22px; height: 22px; font-size: 11px; }
.al-scene.al-en-haut .al-rail-u.al-coin { top: 72px; bottom: auto; right: 18px; left: auto; }
.al-scene.al-en-haut .al-panneau { order: -1; transform-origin: top right; }
@media (max-width: 640px) {
  .al-pastille.al-entete .al-pastille-l { display: none; }
  .al-pastille.al-entete { padding: 0 6px 0 10px; }
  .al-scene.al-en-haut .al-rail-u.al-coin { top: 64px; bottom: auto; left: 12px; right: 12px; align-items: stretch; }
}

/* =========================================================================
   53 — SPIDER : SUIVI CLIENTS (18/09/2026)

   Direction : « 9aad lia bhal hada f spider, yb9aw ydozo lih directe li
   kidwiw m3ahom ». L'onglet s'ouvre sur une ligne par client, comme
   l'onglet RDV du Google Sheet : Client · Téléphone · Date · Heure ·
   Type · Note commerciale · Commercial · Actions. L'agenda daté de la
   section 48 reste, en second mode.

   ⚠ Un tableur, pas des cartes : lignes de ~44 px, filets fins, pas
   de zébrure. L'or ne sert qu'au RDV du jour et à ce qui est actif ;
   le cyan dit « en ligne ». Tailles de la section 50 : 12 px dans le
   tableau, 10 px dans les en-têtes. Le tableau défile dans sa boîte
   (`.sp-rdv-defile`) : à 400 px c'est lui qui glisse, jamais la page.
   ========================================================================= */

/* ── L'en-tête : les deux modes ────────────────────────────────────── */
.sp-sc-modes {
  display: inline-flex; gap: 4px; margin-top: 12px; padding: 4px;
  border-radius: 999px; border: 1px solid var(--pm-bord); background: rgba(0,0,0,.25);
}
.sp-sc-mode {
  padding: 7px 16px; border: 0; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 650; color: var(--n-tx-2); background: transparent;
  transition: color var(--pm-t) var(--pm-courbe), background var(--pm-t) var(--pm-courbe);
}
.sp-sc-mode:hover { color: var(--n-tx); }
.sp-sc-mode.on {
  color: var(--pm-encre); background: linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce));
  box-shadow: 0 8px 18px -10px rgba(242,185,64,.9);
}
.sp-sc-mode:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }
.sp-sc-periode[hidden] { display: none; }

/* ── Les filtres par type ──────────────────────────────────────────── */
.sp-sc-puces { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.sp-sc-puce {
  display: inline-flex; align-items: center; gap: 7px; padding: 5px 12px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 11.5px; font-weight: 600; color: var(--n-tx-2);
  border: 1px solid var(--pm-bord); background: var(--pm-creux);
  transition: color var(--pm-t) var(--pm-courbe), border-color var(--pm-t) var(--pm-courbe), background var(--pm-t) var(--pm-courbe);
}
.sp-sc-puce i { font-style: normal; font-size: 10.5px; padding: 0 6px; border-radius: 999px; background: rgba(255,255,255,.07); font-variant-numeric: tabular-nums; }
.sp-sc-puce:hover { color: var(--n-tx); border-color: var(--pm-bord-fort); }
.sp-sc-puce.on { color: var(--n-tx); border-color: rgba(242,185,64,.55); background: rgba(242,185,64,.1); }
.sp-sc-puce.on i { color: var(--pm-or-clair); background: rgba(242,185,64,.16); }
.sp-sc-puce:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }

.sp-sc-filtre { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; font-size: 12px; color: var(--n-tx-2); }
.sp-sc-auto {
  align-self: flex-start; margin-top: 10px; padding: 6px 14px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 11.5px; font-weight: 600; color: var(--n-tx-2);
  border: 1px dashed var(--pm-bord-fort); background: transparent;
}
.sp-sc-auto:hover, .sp-sc-auto.on { color: var(--n-tx); border-style: solid; }
.sp-sc-auto:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }

/* ── Le tableau façon Sheet ────────────────────────────────────────── */
.sp-sc-defile { border-radius: var(--pm-r-xl); border-color: var(--pm-bord); background: var(--pm-surface); box-shadow: var(--pm-ombre), var(--pm-lueur-haute); }
.sp-sc-table { min-width: 1080px; }
.sp-sc-table th { padding: 10px 12px; }
.sp-sc-table td {
  height: 44px; padding: 5px 12px; vertical-align: middle;
  border-bottom: 1px solid var(--pm-filet); line-height: 1.35;
}
.sp-sc-table tbody tr:last-child td { border-bottom: 0; }
.sp-sc-l.auj td:first-child { box-shadow: inset 3px 0 0 var(--pm-or); }
.sp-sc-l.retard td:first-child { box-shadow: inset 3px 0 0 rgba(255,77,85,.8); }
.sp-sc-l.auj td { background: rgba(242,185,64,.04); }
.sp-sc-l:hover td { background: rgba(255,255,255,.025); }
.sp-sc-l.auj:hover td { background: rgba(242,185,64,.07); }

.sp-sc-muet { color: var(--n-tx-2); font-style: italic; }

/* Client */
.sp-sc-client { min-width: 170px; max-width: 230px; }
.sp-sc-nom {
  display: block; max-width: 100%; padding: 0; border: 0; background: none; font: inherit; text-align: left;
  font-weight: 700; color: var(--n-tx); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
button.sp-sc-nom { cursor: pointer; }
button.sp-sc-nom:hover { color: var(--pm-or-clair); }
button.sp-sc-nom:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; border-radius: 4px; }
.sp-sc-sous { display: block; font-size: 11px; color: var(--n-tx-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Téléphone */
.sp-sc-tel { white-space: nowrap; font-variant-numeric: tabular-nums; }
.sp-sc-appel { color: var(--n-tx); text-decoration: none; }
.sp-sc-appel:hover { color: var(--pm-or-clair); text-decoration: underline; text-underline-offset: 3px; }
.sp-sc-wa {
  display: inline-block; margin-left: 8px; padding: 1px 7px; border-radius: 999px; vertical-align: 1px;
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-decoration: none;
  color: #7CF0B4; border: 1px solid rgba(36,217,129,.3); background: rgba(36,217,129,.07);
}
.sp-sc-wa:hover { background: rgba(36,217,129,.16); }
.sp-sc-appel:focus-visible, .sp-sc-wa:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; border-radius: 4px; }
.sp-sc-tel-faux { color: var(--n-tx-2); }
.sp-sc-verif {
  display: block; width: max-content; margin-top: 2px; padding: 0 6px; border-radius: 999px;
  font-size: 10px; font-weight: 600; color: #FFB3B7; background: rgba(255,77,85,.1); cursor: help;
}

/* Date · Heure */
.sp-sc-date { white-space: nowrap; text-transform: capitalize; font-weight: 600; }
.sp-sc-date.d-contact { font-weight: 500; color: var(--n-tx-2); }
.sp-sc-l.auj .sp-sc-date, .sp-sc-l.auj .sp-sc-heure { color: var(--pm-or-clair); }
.sp-sc-l.retard .sp-sc-date { color: #FF9CA1; }
.sp-sc-heure { white-space: nowrap; font-weight: 700; font-variant-numeric: tabular-nums; }
.sp-sc-heure.vide { font-weight: 500; color: var(--n-tx-2); }

/* Type */
.sp-sc-type-td { white-space: nowrap; }
.sp-sc-type {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 650; color: var(--n-tx-2);
  background: rgba(255,255,255,.04); box-shadow: inset 0 0 0 1px rgba(255,255,255,.1);
}
.sp-sc-type i { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.sp-sc-type.t-en_ligne { color: #7FE6FF; background: rgba(18,217,255,.1); box-shadow: inset 0 0 0 1px rgba(18,217,255,.3); }
.sp-sc-type.t-sur_place { color: #C4A8FF; background: rgba(139,92,246,.1); box-shadow: inset 0 0 0 1px rgba(139,92,246,.32); }
.sp-sc-type.t-bureau, .sp-sc-type.t-rdv { color: var(--n-tx); background: rgba(255,255,255,.06); box-shadow: inset 0 0 0 1px rgba(255,255,255,.2); }
.sp-sc-l.auj .sp-sc-type.t-bureau, .sp-sc-l.auj .sp-sc-type.t-rdv,
.sp-sc-l.auj .sp-sc-type.t-sur_place { color: var(--pm-or-clair); background: rgba(242,185,64,.1); box-shadow: inset 0 0 0 1px rgba(242,185,64,.35); }
.sp-sc-type.t-rappel { color: var(--n-tx); }
.sp-sc-type.t-wa { color: #7CF0B4; background: rgba(36,217,129,.07); box-shadow: inset 0 0 0 1px rgba(36,217,129,.28); }
.sp-sc-type.t-muet { color: var(--n-tx-2); background: transparent; }
.sp-sc-type.t-non { color: #FF9CA1; background: rgba(255,77,85,.07); box-shadow: inset 0 0 0 1px rgba(255,77,85,.25); }
.sp-sc-type.t-devis, .sp-sc-type.t-presentation { color: #C4A8FF; }
.sp-sc-type.t-signe { color: #7CF0B4; background: rgba(36,217,129,.09); box-shadow: inset 0 0 0 1px rgba(36,217,129,.32); }

/* Note commerciale */
.sp-sc-note-td { min-width: 240px; max-width: 380px; }
.sp-sc-note {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  color: var(--n-tx); overflow-wrap: anywhere; cursor: help;
}
.sp-sc-note-meta { display: block; margin-top: 1px; font-size: 10.5px; color: var(--n-tx-2); }

/* Commercial */
.sp-sc-qui { white-space: nowrap; }
.sp-sc-qui .cr3-avatar { display: inline-grid; vertical-align: middle; }
.sp-sc-qui > span:last-child { margin-left: 7px; vertical-align: middle; }

/* Actions */
.sp-sc-act { white-space: nowrap; text-align: right; }
.sp-sc-b { min-height: 28px; padding: 3px 10px; border-radius: 999px; }
.sp-sc-act .btn + .btn { margin-left: 4px; }
.sp-sc-b.b-rdv:hover { color: var(--pm-or-clair); border-color: rgba(242,185,64,.5); }

/* Le thème clair : l'or du jour reste lisible sur fond blanc. */
[data-theme="light"] .sp-sc-l.auj .sp-sc-date,
[data-theme="light"] .sp-sc-l.auj .sp-sc-heure { color: var(--pm-or-fonce); }

@media (max-width: 480px) {
  .sp-sc-modes { display: flex; width: 100%; }
  .sp-sc-mode { flex: 1 1 0; }
  .sp-sc-table { min-width: 980px; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-sc-mode, .sp-sc-puce { transition: none; }
}

/* =========================================================================
   54 — SPIDER : CLIENT EXTÉRIEUR & AGENDA (18/09/2026)

   Direction : « zid y9adro les commerciaux y ajoutiw des clients mn l
   extérieur ydirohom f la listes des rendez vous, ou atzid f spider khass
   agenda reel dial les rendez vous b7al l agenda li 3andna ».

   Deux choses dans l'onglet « Suivi clients » :
     · « + Client extérieur » (`.sp-ce-*`) — le bouton or de l'en-tête et
       sa fenêtre ;
     · l'agenda réel (`.sp-ag-*`) — semaine / jour / mois, de la même
       famille que la page Agenda de l'OS (`.ag-*`, pages.css), mais avec
       les jetons premium de la section 49 et les tailles de la section 50.

   Couleurs : or = RDV, cyan = RDV en ligne, gris = rappel, rouge = en
   retard, estompé = fait.

   ⚠ Positions et hauteurs : variables CSS posées par `el()` (`--top`,
   `--h`, `--col`, `--cols`, `--jours`, `--pas`, `--haut`) — aucun style
   en ligne. ⚠ La grille défile dans sa boîte (`.sp-ag-boite`) : à 400 px
   c'est elle qui glisse, jamais la page.

   En fin de section : les rappels dans la page Agenda de l'OS
   (`.ag-rappel`, lecture seule).
   ========================================================================= */

/* ── L'en-tête : les modes et le bouton or ─────────────────────────── */
.sp-ce-barre { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }
.sp-ce-barre .sp-sc-modes { margin-top: 0; }
.sp-sc-mode.sp-sc-mode-petit { padding: 7px 11px; font-size: 11px; }
.sp-ce-ajout {
  display: inline-flex; align-items: center; gap: 7px; min-height: 36px; padding: 7px 16px; border-radius: 999px;
  font-weight: 700; color: var(--pm-encre);
  background: linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce));
  box-shadow: 0 10px 22px -12px rgba(242,185,64,.9), var(--pm-lueur-haute);
}
.sp-ce-ajout:hover { filter: brightness(1.06); }
.sp-ce-ajout:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 2px; }

/* ── La fenêtre « Client extérieur » ───────────────────────────────── */
.modal.slim.sp-ce-modal { width: min(560px, 100%); }
.sp-ce-listes[hidden], .sp-ce-bloc[hidden], .sp-ce-doublon[hidden] { display: none; }
.sp-ce-section {
  display: flex; flex-direction: column; gap: 12px; padding: 14px;
  border-radius: var(--pm-r-m); border: 1px solid var(--pm-bord); background: var(--pm-creux);
}
.sp-ce-section-t { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--pm-or-clair); }
.sp-ce-bloc { display: flex; flex-direction: column; gap: 12px; }
.sp-ce-doublon {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px;
  margin-top: -4px; padding: 10px 12px; border-radius: var(--pm-r-s); font-size: 12px; line-height: 1.4;
}
.sp-ce-doublon.d-existe { border: 1px solid rgba(255,77,85,.42); background: rgba(255,77,85,.08); }
.sp-ce-doublon.d-faux { border: 1px dashed rgba(255,179,71,.45); background: rgba(255,179,71,.06); color: #FFD08A; }
.sp-ce-doublon-t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-ce-doublon-t b { color: #FFB3B7; font-weight: 700; overflow-wrap: anywhere; }
.sp-ce-doublon-t span, .sp-ce-doublon-qui { font-size: 11.5px; color: var(--n-tx-2); }
.sp-ce-ouvrir { border-radius: 999px; border-color: rgba(242,185,64,.55); color: var(--pm-or-clair); }
.sp-ce-ouvrir:hover { background: rgba(242,185,64,.12); }

/* Le client qu'on vient d'ajouter : un éclat d'or, deux fois. */
@keyframes sp-ce-eclat {
  0%   { background-color: rgba(242,185,64,.26); }
  100% { background-color: transparent; }
}
@keyframes sp-ce-anneau {
  0%   { box-shadow: 0 0 0 0 rgba(242,185,64,.75); }
  100% { box-shadow: 0 0 0 10px rgba(242,185,64,0); }
}
.sp-sc-l.sp-ce-neuf td { animation: sp-ce-eclat 1.6s var(--pm-courbe) 2; }
.sp-sc-l.sp-ce-neuf td:first-child { box-shadow: inset 3px 0 0 var(--pm-or); }
.sp-ag-bloc.sp-ce-neuf, .sp-ag-puce.sp-ce-neuf { animation: sp-ce-anneau 1.3s var(--pm-courbe) 3; }

/* ── L'agenda : la barre ───────────────────────────────────────────── */
.sp-ag { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.sp-ag-barre { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.sp-ag-nav {
  display: inline-flex; align-items: center; gap: 2px; padding: 3px;
  border-radius: 999px; border: 1px solid var(--pm-bord); background: rgba(0,0,0,.25);
}
.sp-ag-fleche {
  width: 30px; height: 30px; display: inline-grid; place-items: center; padding: 0 0 2px;
  border: 0; border-radius: 999px; background: transparent; cursor: pointer;
  font: inherit; font-size: 19px; line-height: 1; color: var(--n-tx-2);
  transition: color var(--pm-t) var(--pm-courbe), background var(--pm-t) var(--pm-courbe);
}
.sp-ag-fleche:hover { color: var(--n-tx); background: rgba(255,255,255,.06); }
.sp-ag-auj {
  padding: 6px 13px; border: 0; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 650; color: var(--n-tx); background: rgba(255,255,255,.06);
}
.sp-ag-auj:hover { color: var(--pm-or-clair); background: rgba(242,185,64,.1); }
.sp-ag-titre { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 15px; font-weight: 700; letter-spacing: -.01em; color: var(--n-tx); }
.sp-ag-titre::first-letter { text-transform: uppercase; }
.sp-ag-vues {
  display: inline-flex; gap: 3px; padding: 3px;
  border-radius: 999px; border: 1px solid var(--pm-bord); background: rgba(0,0,0,.25);
}
.sp-ag-vue {
  padding: 6px 13px; border: 0; border-radius: 999px; cursor: pointer; background: transparent;
  font: inherit; font-size: 11.5px; font-weight: 650; color: var(--n-tx-2);
  transition: color var(--pm-t) var(--pm-courbe), background var(--pm-t) var(--pm-courbe);
}
.sp-ag-vue:hover { color: var(--n-tx); }
.sp-ag-vue.on { color: var(--pm-encre); background: linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce)); }
.sp-ag-fleche:focus-visible, .sp-ag-auj:focus-visible, .sp-ag-vue:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }

.sp-ag-legende { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; font-size: 11px; color: var(--n-tx-2); }
.sp-ag-legende span { display: inline-flex; align-items: center; gap: 6px; }
.sp-ag-legende span::before { content: ""; width: 12px; height: 8px; border-radius: 3px; }
.sp-ag-legende .lg-rdv::before { background: rgba(242,185,64,.3); box-shadow: inset 2px 0 0 var(--pm-or); }
.sp-ag-legende .lg-ligne::before { background: rgba(18,217,255,.22); box-shadow: inset 2px 0 0 var(--pm-cyan); }
.sp-ag-legende .lg-rappel::before { background: rgba(255,255,255,.08); box-shadow: inset 2px 0 0 rgba(255,255,255,.4); }
.sp-ag-legende .lg-fait::before { background: rgba(255,255,255,.05); opacity: .6; }
.sp-ag-legende small { margin-left: auto; font-size: 11px; }

/* ── L'agenda : la boîte et la grille horaire ──────────────────────── */
.sp-ag-boite {
  max-width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain;
  border-radius: var(--pm-r-xl); border: 1px solid var(--pm-bord);
  background: var(--pm-surface); box-shadow: var(--pm-ombre), var(--pm-lueur-haute);
}
.sp-ag-grille { display: grid; grid-template-columns: 56px repeat(var(--jours, 7), minmax(112px, 1fr)); }
.sp-ag-grille.v-jour { grid-template-columns: 56px minmax(240px, 1fr); }

/* La colonne des heures reste à gauche quand la semaine glisse. */
.sp-ag-coin, .sp-ag-heures, .sp-ag-libre-l {
  position: sticky; left: 0; z-index: 4; background: rgba(9,14,21,.97); border-right: 1px solid var(--pm-bord);
}
.sp-ag-coin { border-bottom: 1px solid var(--pm-bord); }

.sp-ag-tete {
  display: flex; align-items: center; gap: 7px; min-width: 0; height: 50px; padding: 0 10px;
  border: 0; border-left: 1px solid var(--pm-filet); border-bottom: 1px solid var(--pm-bord);
  background: transparent; font: inherit; color: var(--n-tx); text-align: left;
}
.sp-ag-tete:first-of-type { border-left: 0; }
button.sp-ag-tete { cursor: pointer; }
button.sp-ag-tete:hover { background: rgba(255,255,255,.03); }
button.sp-ag-tete:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: -2px; }
.sp-ag-tete .j { font-size: 10px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--n-tx-2); }
.sp-ag-tete .n { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sp-ag-tete .c {
  margin-left: auto; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px;
  display: inline-grid; place-items: center; font-style: normal; font-size: 10px; font-weight: 700;
  color: var(--n-tx-2); background: rgba(255,255,255,.07);
}
.sp-ag-tete.auj { background: rgba(242,185,64,.06); box-shadow: inset 0 -2px 0 var(--pm-or); }
.sp-ag-tete.auj .n, .sp-ag-tete.auj .j { color: var(--pm-or-clair); }
.sp-ag-tete.auj .c { color: var(--pm-encre); background: var(--pm-or); }

/* « Sans heure » : les rappels posés sans heure, en haut du jour. */
.sp-ag-libre-l {
  display: flex; align-items: flex-start; padding: 8px 6px; border-bottom: 1px solid var(--pm-bord);
  font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; line-height: 1.2; color: var(--n-tx-2);
}
.sp-ag-libre {
  display: flex; flex-direction: column; gap: 3px; min-width: 0; padding: 5px;
  border-left: 1px solid var(--pm-filet); border-bottom: 1px solid var(--pm-bord); background: rgba(255,255,255,.015);
}
.sp-ag-libre.auj { background: rgba(242,185,64,.04); }

.sp-ag-heures { display: flex; flex-direction: column; }
.sp-ag-h { position: relative; height: calc(var(--pas, 26px) * 2); }
.sp-ag-h span {
  position: absolute; top: -7px; right: 8px; font-family: var(--f-mono); font-size: 10px;
  font-variant-numeric: tabular-nums; color: var(--n-tx-2);
}
.sp-ag-h:first-child span { top: 3px; }

.sp-ag-col { position: relative; min-width: 0; height: var(--haut); border-left: 1px solid var(--pm-filet); }
.sp-ag-col.auj { background: rgba(242,185,64,.025); }
.sp-ag-case {
  display: block; width: 100%; height: var(--pas, 26px); padding: 0 0 0 6px;
  border: 0; border-top: 1px solid rgba(255,255,255,.055); background: transparent; cursor: pointer;
  font: inherit; font-size: 10px; text-align: left; color: transparent;
  transition: background var(--pm-t) var(--pm-courbe);
}
.sp-ag-case:first-child { border-top-color: transparent; }
.sp-ag-case.demi { border-top: 1px dashed rgba(255,255,255,.028); }
.sp-ag-col.passe .sp-ag-case { background: rgba(0,0,0,.14); }
.sp-ag-case:hover { background: rgba(242,185,64,.07); }
.sp-ag-case:hover::after { content: "+ RDV"; font-weight: 700; color: var(--pm-or-clair); }
.sp-ag-case:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: -2px; }

/* ── Un RDV (or), en ligne (cyan), un rappel (gris) ────────────────── */
.sp-ag-bloc {
  position: absolute; z-index: 2; top: var(--top); height: var(--h);
  left: calc(var(--col, 0) * (100% - 6px) / var(--cols, 1) + 3px);
  width: calc((100% - 6px) / var(--cols, 1) - 2px);
  display: flex; flex-direction: column; gap: 1px; overflow: hidden; padding: 4px 7px;
  border-radius: 9px; cursor: pointer; font: inherit; text-align: left; color: var(--n-tx);
  border: 1px solid rgba(242,185,64,.5); border-left: 3px solid var(--pm-or);
  background: linear-gradient(180deg, rgba(242,185,64,.2), rgba(242,185,64,.09)), rgba(12,18,27,.94);
  box-shadow: 0 12px 24px -18px rgba(0,0,0,.95);
  transition: filter var(--pm-t) var(--pm-courbe), box-shadow var(--pm-t) var(--pm-courbe);
}
.sp-ag-bloc:hover { z-index: 5; filter: brightness(1.12); box-shadow: 0 14px 30px -14px rgba(0,0,0,.95); }
.sp-ag-bloc:focus-visible { z-index: 5; outline: 2px solid var(--pm-cyan); outline-offset: 1px; }
.sp-ag-bloc.t-en_ligne {
  border-color: rgba(18,217,255,.5); border-left-color: var(--pm-cyan);
  background: linear-gradient(180deg, rgba(18,217,255,.17), rgba(18,217,255,.07)), rgba(12,18,27,.94);
}
.sp-ag-bloc.b-rappel {
  border-color: rgba(255,255,255,.12); border-left-color: rgba(255,255,255,.42);
  background: linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.035)), rgba(12,18,27,.94);
}
.sp-ag-bloc.retard { border-left-color: #FF4D55; }
.sp-ag-bloc.fait { opacity: .5; filter: saturate(.4); }
.sp-ag-bloc.fait .sp-ag-bloc-t { text-decoration: line-through; text-decoration-color: rgba(255,255,255,.35); }
.sp-ag-bloc.court { flex-direction: row; align-items: center; gap: 6px; padding-top: 1px; padding-bottom: 1px; }
.sp-ag-bloc-h {
  flex: none; font-family: var(--f-mono); font-size: 10px; font-variant-numeric: tabular-nums;
  white-space: nowrap; color: var(--pm-or-clair);
}
.sp-ag-bloc.t-en_ligne .sp-ag-bloc-h { color: #7FE6FF; }
.sp-ag-bloc.b-rappel .sp-ag-bloc-h { color: var(--n-tx-2); }
.sp-ag-bloc-t { min-width: 0; font-size: 12px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-ag-bloc-n {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: 11px; line-height: 1.3; color: var(--n-tx-2);
}

/* Le trait de l'heure courante. */
.sp-ag-maintenant {
  position: absolute; left: 0; right: 0; top: var(--top); z-index: 4; height: 2px;
  background: #FF4D55; box-shadow: 0 0 10px rgba(255,77,85,.6); pointer-events: none;
}
.sp-ag-maintenant::before {
  content: ""; position: absolute; left: -4px; top: -3px; width: 8px; height: 8px; border-radius: 999px; background: #FF4D55;
}

/* ── Une puce : la bande « sans heure » et les cases du mois ───────── */
.sp-ag-puce {
  display: flex; align-items: center; gap: 5px; width: 100%; min-width: 0; padding: 2px 7px;
  border-radius: 999px; cursor: pointer; font: inherit; font-size: 10.5px; text-align: left; color: var(--n-tx);
  border: 1px solid rgba(242,185,64,.4); background: rgba(242,185,64,.1);
}
.sp-ag-puce:hover { filter: brightness(1.15); }
.sp-ag-puce:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }
.sp-ag-puce.t-en_ligne { border-color: rgba(18,217,255,.4); background: rgba(18,217,255,.09); }
.sp-ag-puce.b-rappel { border-color: rgba(255,255,255,.12); background: rgba(255,255,255,.045); }
.sp-ag-puce.retard { box-shadow: inset 2px 0 0 #FF4D55; }
.sp-ag-puce.fait { opacity: .5; }
.sp-ag-puce-h { flex: none; font-family: var(--f-mono); font-size: 10px; font-variant-numeric: tabular-nums; color: var(--pm-or-clair); }
.sp-ag-puce.t-en_ligne .sp-ag-puce-h { color: #7FE6FF; }
.sp-ag-puce.b-rappel .sp-ag-puce-h { color: var(--n-tx-2); }
.sp-ag-puce-t { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ── Le mois ───────────────────────────────────────────────────────── */
.sp-ag-mois { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; padding: 12px; }
.sp-ag-msem { padding-bottom: 2px; text-align: center; font-size: 9.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-2); }
.sp-ag-mcase {
  display: flex; flex-direction: column; gap: 3px; min-width: 0; min-height: 108px; padding: 6px;
  border-radius: var(--pm-r-s); border: 1px solid var(--pm-bord); background: var(--pm-creux);
}
.sp-ag-mcase.hors { background: none; border-color: transparent; }
.sp-ag-mcase.passe { opacity: .78; }
.sp-ag-mcase.auj { border-color: rgba(242,185,64,.6); background: rgba(242,185,64,.05); opacity: 1; }
.sp-ag-mtete { display: flex; align-items: center; justify-content: space-between; gap: 4px; }
.sp-ag-mnum {
  padding: 1px 5px; border: 0; border-radius: 6px; background: none; cursor: pointer;
  font-family: var(--f-mono); font-size: 12px; color: var(--n-tx-2);
}
.sp-ag-mnum:hover { color: var(--n-tx); background: rgba(255,255,255,.06); }
.sp-ag-mcase.auj .sp-ag-mnum { color: var(--pm-or-clair); font-weight: 700; }
.sp-ag-mplus {
  width: 22px; height: 22px; display: inline-grid; place-items: center; padding: 0;
  border: 0; border-radius: 999px; background: none; cursor: pointer; color: var(--n-tx-2); opacity: 0;
  transition: opacity var(--pm-t) var(--pm-courbe);
}
.sp-ag-mcase:hover .sp-ag-mplus, .sp-ag-mplus:focus-visible { opacity: 1; }
.sp-ag-mplus:hover { color: var(--pm-or-clair); background: rgba(242,185,64,.12); }
.sp-ag-mnum:focus-visible, .sp-ag-mplus:focus-visible, .sp-ag-plus:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }
@media (hover: none) { .sp-ag-mplus { opacity: 1; } }
.sp-ag-plus {
  align-self: flex-start; padding: 0 5px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 10.5px; font-weight: 700; color: var(--pm-or-clair);
}

/* ── Le détail d'un RDV / d'un rappel ──────────────────────────────── */
.sp-ag-detail { display: flex; flex-direction: column; gap: 10px; }
.sp-ag-d-tete {
  display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; border-radius: var(--pm-r-m);
  border: 1px solid rgba(242,185,64,.45); border-left: 3px solid var(--pm-or); background: rgba(242,185,64,.08);
}
.sp-ag-d-tete.t-en_ligne { border-color: rgba(18,217,255,.45); border-left-color: var(--pm-cyan); background: rgba(18,217,255,.07); }
.sp-ag-d-tete.b-rappel { border-color: rgba(255,255,255,.14); border-left-color: rgba(255,255,255,.45); background: rgba(255,255,255,.04); }
.sp-ag-d-tete.retard { border-left-color: #FF4D55; }
.sp-ag-d-type { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--pm-or-clair); }
.sp-ag-d-tete.t-en_ligne .sp-ag-d-type { color: #7FE6FF; }
.sp-ag-d-tete.b-rappel .sp-ag-d-type { color: var(--n-tx-2); }
.sp-ag-d-tete b { font-size: 15px; font-weight: 700; color: var(--n-tx); }
.sp-ag-d-tete b::first-letter { text-transform: uppercase; }
.sp-ag-d-statut { font-size: 11.5px; color: var(--n-tx-2); }
.sp-ag-d-tete.retard .sp-ag-d-statut { color: #FF9CA1; }
.sp-ag-d-l {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 6px 2px; border-bottom: 1px solid var(--pm-filet); font-size: 12.5px;
}
.sp-ag-d-l > span:first-child { flex: none; color: var(--n-tx-2); }
.sp-ag-d-l > b, .sp-ag-d-l > a, .sp-ag-d-l > .sp-ag-d-tel { min-width: 0; text-align: right; font-weight: 600; overflow-wrap: anywhere; }
.sp-ag-d-tel { display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 4px; }
.sp-ag-d-lien { color: #7FE6FF; }
.sp-ag-d-note { padding: 10px 12px; border-radius: var(--pm-r-s); background: var(--pm-creux); border: 1px solid var(--pm-bord); }
.sp-ag-d-note > span { font-size: 10px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--n-tx-2); }
.sp-ag-d-note p { margin: 4px 0 0; font-size: 12.5px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
.sp-ag-d-modal .modal-foot { flex-wrap: wrap; }

/* ── Un créneau vide : pour qui ? ──────────────────────────────────── */
.sp-ag-choix-corps { display: flex; flex-direction: column; gap: 10px; }
.sp-ag-choix-liste {
  display: flex; flex-direction: column; gap: 4px; max-height: min(52vh, 420px);
  overflow-y: auto; overscroll-behavior: contain;
}
.sp-ag-choix-l {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 44px; padding: 7px 10px;
  border-radius: var(--pm-r-s); border: 1px solid var(--pm-bord); background: var(--pm-creux);
  cursor: pointer; font: inherit; text-align: left; color: var(--n-tx);
  transition: border-color var(--pm-t) var(--pm-courbe), background var(--pm-t) var(--pm-courbe);
}
.sp-ag-choix-l:hover { border-color: rgba(242,185,64,.5); background: rgba(242,185,64,.06); }
.sp-ag-choix-l:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: 1px; }
.sp-ag-choix-t { display: flex; flex-direction: column; min-width: 0; }
.sp-ag-choix-t b { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-ag-choix-t small { font-size: 11px; color: var(--n-tx-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-ag-choix-vide { margin: 6px 2px; font-size: 12px; line-height: 1.45; color: var(--n-tx-2); }

/* ── Le thème clair ────────────────────────────────────────────────── */
[data-theme="light"] .sp-ag-coin,
[data-theme="light"] .sp-ag-heures,
[data-theme="light"] .sp-ag-libre-l { background: #FFFFFF; }
[data-theme="light"] .sp-ag-case { border-top-color: rgba(16,23,32,.07); }
[data-theme="light"] .sp-ag-case.demi { border-top-color: rgba(16,23,32,.035); }
[data-theme="light"] .sp-ag-col.passe .sp-ag-case { background: rgba(16,23,32,.025); }
[data-theme="light"] .sp-ag-bloc { background: linear-gradient(180deg, rgba(242,185,64,.24), rgba(242,185,64,.12)), #FFFFFF; }
[data-theme="light"] .sp-ag-bloc.t-en_ligne { background: linear-gradient(180deg, rgba(18,217,255,.2), rgba(18,217,255,.08)), #FFFFFF; }
[data-theme="light"] .sp-ag-bloc.b-rappel { background: #F3F5F8; border-color: rgba(16,23,32,.12); border-left-color: rgba(16,23,32,.35); }
[data-theme="light"] .sp-ag-bloc-h, [data-theme="light"] .sp-ag-puce-h,
[data-theme="light"] .sp-ag-tete.auj .n, [data-theme="light"] .sp-ag-tete.auj .j { color: var(--pm-or-fonce); }
[data-theme="light"] .sp-ag-bloc.t-en_ligne .sp-ag-bloc-h, [data-theme="light"] .sp-ag-puce.t-en_ligne .sp-ag-puce-h { color: #0B8FB0; }
[data-theme="light"] .sp-ag-nav, [data-theme="light"] .sp-ag-vues { background: rgba(16,23,32,.04); }

/* ── Téléphone : le jour par défaut, la semaine glisse dans sa boîte ─ */
@media (max-width: 640px) {
  .sp-ce-barre { gap: 8px; }
  .sp-ce-ajout { width: 100%; justify-content: center; }
  .sp-ag-barre { gap: 8px; }
  .sp-ag-titre { flex-basis: 100%; order: -1; font-size: 14px; }
  .sp-ag-vues { margin-left: auto; }
  .sp-ag-legende small { flex-basis: 100%; margin-left: 0; }
  .sp-ag-grille { grid-template-columns: 46px repeat(var(--jours, 7), minmax(104px, 1fr)); }
  .sp-ag-grille.v-jour { grid-template-columns: 46px minmax(0, 1fr); }
  .sp-ag-h span { right: 5px; }
  .sp-ag-mois { gap: 3px; padding: 6px; }
  .sp-ag-mcase { min-height: 64px; padding: 3px; gap: 2px; }
  .sp-ag-mois .sp-ag-puce { justify-content: center; padding: 1px 2px; }
  .sp-ag-mois .sp-ag-puce-t { display: none; }
  .sp-ag-mois .sp-ag-puce:not(:has(.sp-ag-puce-h)) .sp-ag-puce-t { display: block; }
  .sp-ag-mplus { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-sc-l.sp-ce-neuf td, .sp-ag-bloc.sp-ce-neuf, .sp-ag-puce.sp-ce-neuf { animation: none; }
  .sp-ag-fleche, .sp-ag-vue, .sp-ag-case, .sp-ag-bloc, .sp-ag-choix-l, .sp-ag-mplus { transition: none; }
}

/* ── La page Agenda de l'OS : les rappels des commerciaux ──────────── */
/* Lecture seule, même famille que les rendez-vous — mais en retrait :
   un rappel est un coup de fil, pas une rencontre. */
.ag-event.ag-rappel {
  border-style: dashed; border-left-style: solid; opacity: .9;
  background: color-mix(in srgb, var(--dep) 9%, var(--bg-1));
}
.ag-pastille.ag-rappel { border-style: dashed; background: transparent; }
.mois-event.ag-rappel { border-left-style: dashed; background: color-mix(in srgb, var(--dep) 8%, transparent); }

/* =========================================================================
   55 — SPIDER : REFONTE, ÉTAPE 1 (18/09/2026)
   L'en-tête façon CERCLE 25 (`.cr3-hero` réutilisé tel quel), la barre
   d'onglets en pilule, le menu « ⋯ » de « Suivi clients », la note de
   bas de page de « L'équipe ». Jetons `--pm-*` de la section 49.
   Le minimum : la finition visuelle viendra dans une étape à part.
   ========================================================================= */

/* ── L'en-tête ── */
.spider .sp-hero .cr3-titre { margin: 8px 0 6px !important; line-height: 1 !important; }
.sp-hero-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* ── Les onglets : une pilule qui glisse ──
   Colonnes égales (sinon `--i` / `--n` ne tombent pas juste), et la
   barre défile à l'horizontale quand l'écran est plus étroit. */
.sp-vues-defile { overflow-x: auto; margin: 0 0 16px; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.sp-vues-defile::-webkit-scrollbar { display: none; }
.sp-vues.sp-vues-pilule {
  position: relative; display: grid; grid-auto-flow: column;
  grid-template-columns: repeat(var(--n, 7), minmax(0, 1fr));
  gap: 0; margin: 0; padding: 5px; min-width: calc(var(--n, 7) * 138px);
  border: 1px solid var(--pm-bord); border-radius: 999px;
  background: var(--pm-creux); box-shadow: var(--pm-lueur-haute);
}
.sp-vues-pilule::before {
  content: ""; position: absolute; top: 5px; bottom: 5px; z-index: 0;
  left: calc(5px + (100% - 10px) / var(--n, 7) * var(--i, 0));
  width: calc((100% - 10px) / var(--n, 7));
  border-radius: 999px; border: 1px solid var(--pm-bord-fort);
  background: var(--pm-surface-h); box-shadow: var(--pm-ombre);
  transition: left var(--pm-t) var(--pm-courbe);
}
.sp-vues-pilule .sp-vue {
  position: relative; z-index: 1; min-width: 0; flex: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 12px; border-radius: 999px; background: transparent; box-shadow: none;
  white-space: nowrap;
}
.sp-vues-pilule .sp-vue > span { overflow: hidden; text-overflow: ellipsis; }
.sp-vues-pilule .sp-vue.on { background: transparent; box-shadow: none; color: var(--n-tx); }
.sp-vues-pilule .sp-vue::after { display: none; }
.sp-vues-pilule .sp-vue:focus-visible { outline: 2px solid var(--pm-cyan); outline-offset: -2px; }
.sp-vue-pastille {
  flex: none; min-width: 18px; padding: 1px 6px; border-radius: 999px;
  font-family: inherit; font-size: 10.5px; font-weight: 700; line-height: 16px; font-style: normal; text-align: center;
  color: var(--pm-encre); background: var(--pm-or);
}

/* ── Suivi clients : un bouton, puis « ⋯ » ── */
.sp-sc-act .sp-sc-prim { min-height: 28px; padding: 3px 12px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; }
.sp-sc-act .sp-sc-plus { min-height: 28px; min-width: 32px; padding: 3px 8px; border-radius: 999px; font-weight: 700; letter-spacing: .05em; }
.sp-sc-act .sp-sc-plus[aria-expanded="true"] { border-color: var(--pm-bord-fort); }
.sp-sc-menu {
  position: fixed; z-index: 900; left: var(--x, 0); top: var(--y, 0); transform: translateX(-100%);
  display: flex; flex-direction: column; min-width: 164px; padding: 6px;
  border: 1px solid var(--pm-bord-fort); border-radius: var(--pm-r-s);
  background: var(--pm-surface); box-shadow: var(--pm-ombre-forte), var(--pm-lueur-haute);
}
.sp-sc-menu-i {
  display: block; width: 100%; padding: 8px 12px; border: 0; border-radius: 8px;
  background: transparent; color: var(--n-tx); font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1.3; text-align: left;
  text-decoration: none; cursor: pointer;
}
.sp-sc-menu-i:hover, .sp-sc-menu-i:focus-visible { background: var(--pm-creux); color: var(--pm-or-clair); outline: none; }

/* ── L'équipe : la note de bas de page ── */
.sp-note-bas { margin: 18px 2px 4px; max-width: 90ch; font-size: 11.5px; line-height: 1.5; color: var(--n-tx-2); opacity: .85; }

@media (max-width: 760px) {
  .sp-vues.sp-vues-pilule { min-width: calc(var(--n, 7) * 118px); }
  .sp-hero .cr3-stats { width: 100%; }
  .sp-hero .cr3-stat { flex: 1 1 0; min-width: 0; padding: 12px 14px; }
}
@media (prefers-reduced-motion: reduce) {
  .sp-vues-pilule::before { transition: none; }
}

/* =========================================================================
   56 — SPIDER : REFONTE, ÉTAPE 2 (18/09/2026)
   Vu au harnais (captures 1440 × 900 et 400 × 860, Direction et
   commerciale), puis corrigé ; et les onglets restants alignés sur le
   CERCLE 25 : panneaux en verre (`--pm-*`), un seul style de titre,
   tableaux compacts, une famille de tuiles, une hauteur de bouton,
   l'or pour ce qui compte. Tout est sous `.spider` (ou une classe
   `sp-` propre à SPIDER) : `.sp-vue` sert aussi à la page Équipe
   (`.equipe-une`), on ne le vise donc jamais seul.
   ========================================================================= */

/* ── 56.0 Les jetons qui manquaient ──
   `--n-tx-3` (73 usages dans ce fichier) et `--n-tx-1` ne sont
   définis nulle part : la couleur retombait sur l'héritage, et les
   textes « discrets » s'affichaient en blanc — les détails de tuile
   plus visibles que leur libellé. Définis ici pour SPIDER seulement. */
.spider, .sp-fond, .sp-fiche, .sp-sc-menu { --n-tx-3: #6F7B8E; --n-tx-1: var(--n-tx); }
[data-theme="light"] :is(.spider, .sp-fond, .sp-fiche, .sp-sc-menu) { --n-tx-3: #7A8696; }
/* Les contrôles natifs (cases, dates, listes) suivent le thème. */
.spider { color-scheme: dark; }
[data-theme="light"] .spider { color-scheme: light; }

/* ── 56.1 Les onglets ──
   `.sp-vue` porte un raccourci `font:` invalide (« … inherit ») : le
   bouton retombait sur la police du navigateur. Et sur téléphone,
   « Suivi clients » / « Présentation & devis » étaient coupés. */
.spider .sp-vue { font-family: var(--f-body); font-size: 12.5px; font-weight: 600; line-height: 1.3; }
.sp-vues-pilule .sp-vue > span { overflow: visible; text-overflow: clip; }
@media (max-width: 760px) {
  .sp-vues.sp-vues-pilule { min-width: calc(var(--n, 7) * 150px); }
  .sp-vues-pilule .sp-vue { min-height: 38px; padding: 8px 10px; }
}

/* ── 56.2 Suivi clients : le tableau tient, le « ⋯ » se voit ── */
.spider .sp-sc-table th, .spider .sp-sc-table td { padding-left: 10px; padding-right: 10px; }
.spider .sp-sc-note-td { min-width: 180px; }
.spider .sp-sc-client { min-width: 150px; max-width: 200px; }
/* La colonne des gestes se mesurait 11 px trop étroite (« Appeler » +
   « ⋯ ») : le « ⋯ » sortait du tableau. Largeur posée. */
.spider .sp-sc-table th.sp-rdv-th-act { width: 150px; }
/* « Fait » perdait son or dans l'OS : `.app .btn` (section 49.4, deux
   classes) passait devant `.sp-rdv-b-fait` (une seule). */
.app .sp-rdv-b-fait {
  border: 0; color: var(--pm-encre); font-weight: 700;
  background: linear-gradient(180deg, var(--pm-or-clair), var(--pm-or-fonce));
  box-shadow: 0 8px 20px -12px rgba(242,185,64,.9), inset 0 1px 0 rgba(255,255,255,.4);
}
.sp-sc-act .sp-sc-plus {
  min-width: 30px; min-height: 30px; padding: 0 8px; line-height: 1;
  font-size: 15px; color: var(--n-tx); border: 1px solid var(--pm-bord); background: var(--pm-creux);
}
.sp-sc-act .sp-sc-plus:hover { border-color: var(--pm-bord-fort); background: rgba(255,255,255,.07); }
/* Le menu était translucide (`--pm-surface` à 92 %) : les boutons des
   lignes du dessous se lisaient à travers. Un fond plein. */
.sp-sc-menu { background: linear-gradient(180deg, #141D29, #0B1119); }
[data-theme="light"] .sp-sc-menu { background: #FFFFFF; }
.sp-sc-menu-i:focus:not(:focus-visible) { background: transparent; color: var(--n-tx); }

/* ── 56.3 Les commandes segmentées : neutres. L'or reste au geste
   principal (« Client extérieur », « Répartir », la pastille). ── */
.spider .sp-sc-mode.on, .spider .sp-rdv-p.on, .spider .sp-ag-vue.on, .spider .sp-periode-choix .sp-vue.on {
  color: var(--n-tx); background: var(--pm-surface-h);
  box-shadow: inset 0 0 0 1px var(--pm-bord-fort), var(--pm-ombre);
}
.spider .sp-rdv-p.on i { color: var(--n-tx); background: rgba(255,255,255,.1); }
.spider .sp-sc-mode.sp-sc-mode-petit { padding: 7px 14px; font-size: 12px; }
.spider .sp-sc-puce.on { color: var(--n-tx); border-color: var(--pm-bord-fort); background: rgba(255,255,255,.07); }
.spider .sp-sc-puce.on i { color: var(--n-tx); background: rgba(255,255,255,.12); }
[data-theme="light"] .spider .sp-rdv-p.on i,
[data-theme="light"] .spider .sp-sc-puce.on i { background: rgba(16,23,32,.08); }

/* ── 56.4 L'équipe : la période en une commande segmentée ── */
.spider .sp-periode { gap: 10px; }
.spider .sp-periode-choix {
  display: inline-flex; gap: 3px; padding: 4px; border-radius: 999px;
  border: 1px solid var(--pm-bord); background: var(--pm-creux);
}
.spider .sp-periode .sp-vue {
  flex: none; min-width: 0; min-height: 0; padding: 7px 15px; border-radius: 999px;
  background: transparent; box-shadow: none; font-size: 12px;
}
.spider .sp-periode .sp-vue::after { display: none; }
.spider .sp-periode > .sp-vue { border: 1px solid var(--pm-bord); }
.spider .sp-periode-dates { display: inline-flex; align-items: center; gap: 8px; }
.spider .sp-periode .input[type="date"] { width: 150px; min-width: 0; min-height: 36px; }
@media (max-width: 640px) {
  .spider .sp-periode-choix { display: flex; width: 100%; }
  .spider .sp-periode-choix .sp-vue { flex: 1 1 0; }
  .spider .sp-periode-dates { width: 100%; }
  .spider .sp-periode > .sp-periode-sep { display: none; }
  .spider .sp-periode-dates .input[type="date"] { flex: 1 1 0; width: auto; }
}
/* Les cartes : le bord d'état reste, plus fin ; l'absence n'est pas
   un signal d'or. */
.spider .sp-col { border-left-width: 2px; }
.spider .sp-col-orange { border-left-color: rgba(242,185,64,.45); }
/* La liste d'appels débordait de la carte (cinq colonnes à largeur
   minimale = 608 px dans une carte de 500) : le commentaire passe
   dessous, sur toute la largeur. */
.spider .sp-appels { border-color: var(--pm-bord); border-radius: var(--pm-r-s); }
.spider .sp-appel-l { grid-template-columns: 64px minmax(0, 1fr) auto auto; gap: 4px 10px; align-items: center; }
.spider .sp-appel-r, .spider .sp-appel-t { grid-column: auto; }
.spider .sp-appel-c { grid-column: 1 / -1; padding-top: 0; font-size: 11.5px; }
.spider .sp-appel-c:empty { display: none; }

/* ── 56.5 Un seul titre de panneau ──
   Le couple du « Suivi clients » : un titre en phrase, une ligne
   grise. Plus de majuscules espacées d'un côté et de phrase en gras
   à droite de l'autre. */
.app .main > .page.spider:not(.dashboard-home):not(.ps-root) .sp-panneau > .panel-head h3 {
  font-size: 13.5px !important; font-weight: 650; letter-spacing: -.01em; text-transform: none;
}
.spider .sp-panneau > .panel-head .sp-note { font-size: 11.5px; font-weight: 400; color: var(--n-tx-2); text-align: right; }
.spider .sp-panneau { border-radius: var(--pm-r-l); }
@media (max-width: 640px) {
  .spider .sp-panneau > .panel-head { flex-direction: column; align-items: flex-start; gap: 3px; }
  .spider .sp-panneau > .panel-head .sp-note { margin-left: 0; text-align: left; }
}

/* ── 56.6 Une famille de tuiles (chaîne, étapes, piles, mesures) ──
   Le chiffre en blanc, le libellé en gris, le détail plus discret —
   l'ordre du `.cr3-stat`. */
.spider :is(.sp-maillon, .sp-etape, .sp-mini) {
  border-radius: 14px; border: 1px solid var(--pm-bord);
  background: var(--pm-creux); box-shadow: var(--pm-lueur-haute);
}
.spider :is(.sp-maillon, .sp-etape, .sp-mini) b { font-size: 20px; font-weight: 750; letter-spacing: -.03em; }
.spider :is(.sp-maillon, .sp-etape, .sp-mini) span { font-size: 11.5px; font-weight: 500; color: var(--n-tx-2); line-height: 1.3; }
.spider :is(.sp-maillon, .sp-etape) span { color: var(--n-tx); font-weight: 600; }
.spider :is(.sp-maillon, .sp-etape) small { font-size: 10.5px; font-weight: 400; color: var(--n-tx-2); }
.spider .sp-etape.on { border-color: var(--pm-bord-fort); background: rgba(255,255,255,.07); }
.spider .sp-mesures { gap: 6px; }

/* ── 56.7 Les tableaux : compacts, comme `.cr3-table` ── */
.spider .sp-defile { border-radius: var(--pm-r-xl); border: 1px solid var(--pm-bord); }
.app .main > .page.spider .sp-table th { height: 38px !important; }
.app .main > .page.spider .sp-table td { padding-top: 9px !important; padding-bottom: 9px !important; }
.spider .sp-table-sel input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--pm-or); }
.spider .sp-prov { font-family: var(--f-body); font-size: 10px; font-weight: 700; letter-spacing: .08em; }

/* ── 56.8 Les libellés : Inter partout, plus de mono ── */
.spider :is(.sp-champ > span, .sp-ligne-tete, .sp-l-lab > span) {
  font-family: var(--f-body); font-size: 10px; font-weight: 600; letter-spacing: .12em; color: var(--n-tx-2);
}
.spider .sp-l-lab > span { white-space: nowrap; }
.spider .sp-role { font-family: var(--f-body); font-size: 11px; letter-spacing: .02em; text-transform: none; color: var(--n-tx-2); }

/* ── 56.9 Présentation & devis : des champs, pas des cases du navigateur ── */
.spider .sp-champ :is(input, select, textarea) {
  display: block; width: 100%; box-sizing: border-box; min-height: 36px; padding: 8px 12px;
  border-radius: var(--pm-r-s); border: 1px solid var(--pm-bord); background: var(--pm-creux);
  color: var(--n-tx); font-family: var(--f-body); font-size: 12.5px; line-height: 1.4;
}
.spider .sp-champ textarea { min-height: 84px; resize: vertical; }
.spider .sp-champ :is(input, select, textarea):focus {
  outline: none; border-color: rgba(242,185,64,.5); box-shadow: 0 0 0 3px rgba(242,185,64,.12);
}
@media (max-width: 640px) { .spider .sp-champ :is(input, select, textarea) { font-size: 16px; } }

/* ── 56.10 Les boutons : une hauteur, un rayon ── */
.spider .btn { border-radius: 999px; }
.spider .btn:not(.btn-sm) { min-height: 36px; }
.spider .btn.btn-sm { min-height: 30px; }
/* Livraison client : un bouton d'or plein par ligne, c'était cinq
   lignes qui criaient. Le geste reste doré, en contour ; « Go to
   BORN » (ouvrir le projet) garde l'or plein. */
.spider .sp-pj .btn-primary.sp-pont-liv {
  color: var(--pm-or-clair); background: rgba(242,185,64,.08);
  border: 1px solid rgba(242,185,64,.45); box-shadow: none;
}
.spider .sp-pj .btn-primary.sp-pont-liv:hover { background: rgba(242,185,64,.16); }
[data-theme="light"] .spider .sp-pj .btn-primary.sp-pont-liv { color: var(--pm-or-fonce); }

/* ── 56.11 L'agenda : un bloc étroit montre le nom, pas l'heure
   (l'heure se lit sur la grille). Avant : « 09:30 · Su… ». ── */
.sp-ag-bloc { container-type: inline-size; }
@container (max-width: 90px) {
  .sp-ag-bloc-h { display: none; }
}

/* =========================================================================
   57 — CERCLE 25 : INSPIRATION & DOCUMENTS (18/09/2026)
   Direction : « demande khassha tzid fiha ila kan chi document ou la lien
   d'inspiration ». Une section dans « Nouvelle demande » et dans la fiche
   (liens + fichiers, vignette pour les images), et un trombone avec le
   nombre de pièces à côté du nom de la ligne. Même langage que `.cr3-*` :
   verre sombre, or pour ce qui compte, cyan pour les liens.
   ⚠ À 400 px : le champ et « Ajouter » restent sur une ligne, la zone de
   dépôt passe en colonne, les noms longs se coupent — jamais la page.
   ========================================================================= */

/* ── Le trombone de la ligne ── */
.cr-insp-badge {
  display: inline-flex; align-items: center; gap: 3px; flex: none;
  padding: 2px 8px 2px 6px; border-radius: 999px;
  font: 700 11px/1.3 var(--font, inherit); font-variant-numeric: tabular-nums;
  color: #F6D27C; background: rgba(242,185,64,.1); border: 1px solid rgba(242,185,64,.32);
  cursor: pointer; transition: background .18s ease, box-shadow .18s ease, transform .18s ease;
}
span.cr-insp-badge { cursor: inherit; }
button.cr-insp-badge:hover { background: rgba(242,185,64,.2); box-shadow: 0 0 14px rgba(242,185,64,.35); transform: translateY(-1px); }
.cr-insp-badge:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: 2px; }
.cr-insp-badge .ico { flex: none; }

/* ── La section ── */
.cr-insp {
  display: flex; flex-direction: column; gap: 10px;
  margin: 6px 0 14px; padding: 14px; border-radius: 18px;
  background: linear-gradient(180deg, rgba(242,185,64,.055), rgba(255,255,255,.02));
  border: 1px solid rgba(242,185,64,.18);
  scroll-margin-top: 12px;
  transition: box-shadow .4s ease, border-color .4s ease;
}
.cr-insp.eclaire { border-color: rgba(242,185,64,.7); box-shadow: 0 0 0 4px rgba(242,185,64,.14), 0 0 40px -12px rgba(242,185,64,.6); }
.cr-insp-tete { display: flex; align-items: center; gap: 8px; }
.cr-insp-titre {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: #F6D27C;
}
.cr-insp-facultatif, .cr-insp-compte {
  margin-left: auto; font-size: 11px; color: var(--n-tx-2, rgba(255,255,255,.6));
}
.cr-insp-compte:empty { display: none; }
.cr-insp-compte {
  min-width: 22px; padding: 1px 8px; border-radius: 999px; text-align: center;
  font-weight: 700; color: #1A1204; background: linear-gradient(180deg, #FAD377, #E9A92E);
}
.cr-insp-aide { margin: -4px 0 0; font-size: 12px; line-height: 1.45; color: var(--n-tx-2, rgba(255,255,255,.6)); }
.cr-insp-vide { font-size: 12.5px; color: var(--n-tx-2, rgba(255,255,255,.6)); }

/* ── La liste ── */
.cr-insp-liste { display: flex; flex-direction: column; gap: 6px; }
.cr-insp-liste[hidden] { display: none; }
.cr-insp-el {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  border-radius: 14px; background: rgba(255,255,255,.035); border: 1px solid rgba(255,255,255,.07);
  animation: cr-insp-entre .3s cubic-bezier(.22,1,.36,1) both;
}
.cr-insp-el.attente { border-style: dashed; border-color: rgba(242,185,64,.3); }
@keyframes cr-insp-entre { from { opacity: 0; transform: translateY(6px); } }
.cr-insp-corps {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  padding: 7px 10px 7px 7px; border-radius: 14px; color: var(--n-tx, #fff); text-decoration: none;
}
a.cr-insp-corps { transition: background .18s ease; }
a.cr-insp-corps:hover { background: rgba(255,255,255,.05); }
a.cr-insp-corps:hover .cr-insp-ouvrir { color: #F6D27C; transform: translateX(2px); }
a.cr-insp-corps:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: 1px; }
.cr-insp-corps.perdu { opacity: .55; }
.cr-insp-vignette {
  flex: none; display: grid; place-items: center; width: 38px; height: 38px; overflow: hidden;
  border-radius: 10px; color: #F6D27C; background: rgba(242,185,64,.1); border: 1px solid rgba(242,185,64,.22);
}
.cr-insp-vignette.lien { color: var(--n-cyan, #12D9FF); background: rgba(18,217,255,.08); border-color: rgba(18,217,255,.25); }
.cr-insp-vignette.image { background: rgba(0,0,0,.35); border-color: rgba(255,255,255,.12); }
.cr-insp-vignette img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cr-insp-texte { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cr-insp-texte b {
  font-size: 13px; font-weight: 600; line-height: 1.3;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cr-insp-texte span {
  font-size: 11px; color: var(--n-tx-2, rgba(255,255,255,.6));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cr-insp-ouvrir { flex: none; display: grid; color: var(--n-tx-2, rgba(255,255,255,.5)); transition: color .18s ease, transform .18s ease; }
.cr-insp-retirer {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px; margin-right: 6px;
  border-radius: 999px; border: 0; color: var(--n-tx-2, rgba(255,255,255,.6)); background: transparent; cursor: pointer;
}
.cr-insp-retirer:hover { color: #FF6B6B; background: rgba(255,107,107,.12); }
.cr-insp-retirer:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); }

/* ── Ajouter : un lien, des fichiers ── */
.cr-insp-saisie { display: flex; flex-direction: column; gap: 8px; }
.cr-insp-ajout { display: flex; gap: 8px; min-width: 0; }
.cr-insp-ajout .input { flex: 1; min-width: 0; }
.cr-insp-ajout .btn { flex: none; border-radius: 999px; }
.cr-insp-choix { display: none; }
.cr-insp-depot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: 14px;
  border: 1.5px dashed rgba(242,185,64,.32); background: rgba(242,185,64,.035);
  transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.cr-insp-depot.survol { border-color: rgba(242,185,64,.85); background: rgba(242,185,64,.1); box-shadow: 0 0 30px -10px rgba(242,185,64,.6); }
.cr-insp-depot.occupe { opacity: .75; }
.cr-insp-depot-ico { flex: none; display: grid; color: #F6D27C; }
.cr-insp-depot-t { flex: 1; min-width: 150px; display: flex; flex-direction: column; gap: 1px; }
.cr-insp-depot-t b { font-size: 13px; font-weight: 600; }
.cr-insp-depot-t span { font-size: 11px; color: var(--n-tx-2, rgba(255,255,255,.6)); }
.cr-insp-depot .btn { flex: none; border-radius: 999px; }
.cr-insp-envoi { flex-basis: 100%; font-size: 11.5px; color: #F6D27C; }
.cr-insp-envoi:empty { display: none; }

@media (max-width: 520px) {
  .cr-insp { padding: 12px; border-radius: 16px; }
  .cr-insp-depot { flex-direction: column; align-items: stretch; text-align: center; }
  .cr-insp-depot-ico { justify-self: center; margin: 0 auto; }
  .cr-insp-depot-t { min-width: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cr-insp-el { animation: none; }
  .cr-insp, .cr-insp-badge, .cr-insp-ouvrir { transition: none; }
  button.cr-insp-badge:hover { transform: none; }
}

/* =========================================================================
   58 — LISTES : L'ALIGNEMENT — 18 septembre 2026

   Direction : « les lignes rah 3awjin, chi dakhel ou chi kharej ».
   Trois causes, vues sur la liste du CERCLE 25 :
     1. la pastille « Vidéo » passait tantôt À CÔTÉ du titre, tantôt
        AU-DESSUS (selon la longueur du titre) → la colonne zigzaguait ;
     2. les boutons d'action n'avaient pas la même largeur (« C'est prêt »,
        « Commencer », « Je prends »…) et l'icône de dépôt n'existait que
        sur certaines lignes → la colonne de droite dansait ;
     3. « Libre — à prendre » passait sur deux lignes, pas les noms.
   Règle : la pastille et les badges TOUJOURS sur la première ligne, le
   titre TOUJOURS sur la seconde ; un bouton principal de largeur fixe,
   calé à droite ; une case réservée pour l'icône, même vide.
   ========================================================================= */
.cr3-table td { vertical-align: middle; }
.cr3-livrable-l { flex-wrap: wrap; row-gap: 5px; column-gap: 6px; }
.cr3-livrable-l > .cr3-livrable-t { order: 2; flex: 1 0 100%; line-height: 1.35; }
.cr3-livrable-l > :not(.cr3-livrable-t) { order: 1; }

td.cr3-actions { width: 1%; }
.cr3-actions-l { display: flex; justify-content: flex-end; align-items: center; gap: 6px; }
.cr3-table td.cr3-client b { white-space: nowrap; }
/* Le geste principal : toujours le dernier, toujours la même largeur. */
.cr3-actions-l > .cr3-btn:last-child { min-width: 132px; justify-content: center; }
.cr3-actions-l > .cr3-btn { flex: none; }

.cr3-qui .cr3-personne, .cr3-qui-l, .cr3-chef .cr3-qui-l { white-space: nowrap; }
.cr3-table td.cr3-quand { white-space: nowrap; }

/* SPIDER — même règle pour « Suivi clients » et les listes de livraison. */
.sp-sc-actions, .sp-suivi-actions { display: flex; justify-content: flex-end; align-items: center; gap: 6px; }
.sp-pj { align-items: center; }
.sp-pj > .btn:last-child { min-width: 118px; justify-content: center; }

/* =========================================================================
   59 — TABLEAUX : MÊME TAILLE, MÊME MESURE — 18 septembre 2026

   Direction : « machi nefss size, machi nafss la3bar f tableau, chi sghir
   chi kbir — khass kola ykon m9ad ou nafss la3bar f kolchi ».
   Une seule mesure pour toute la liste du CERCLE 25 :
     • chaque ligne a la même hauteur (64 px) ;
     • chaque cellule tient sur DEUX lignes au plus — un titre, un détail ;
       ce qui dépasse finit en « … », le texte entier est dans la fiche ;
     • un seul corps de texte (12,5 px), un seul corps de détail (11 px) ;
     • pastilles de statut, boutons et avatars à la même hauteur (30 px /
       24 px), « Je prends » compris.
   ========================================================================= */
.cr3-table tbody tr.cr3-l { height: 64px; }
.cr3-table tbody tr.cr3-l > td { padding-top: 8px; padding-bottom: 8px; font-size: 12.5px; line-height: 1.3; vertical-align: middle; }

/* Date : « 18 sept » sur une ligne, l'échéance dessous. */
:is(.app, body) .cr3-table .cr3-jour { font-size: 13px; line-height: 1.3; font-weight: 700; }
:is(.app, body) .cr3-table .cr3-mois { font-size: 11px; letter-spacing: .04em; margin-left: 4px; }
:is(.app, body) .cr3-table .cr3-ech { margin-top: 2px; font-size: 11px; }

/* Client : le nom, le projet dessous — une ligne chacun. */
:is(.app, body) .cr3-table .cr3-client b { font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 190px; }
:is(.app, body) .cr3-table .cr3-client span { font-size: 11px; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 190px; }

/* Livrable : pastilles sur la 1re ligne, titre sur la 2e, jamais plus. */
.cr3-table .cr3-livrable-l { flex-wrap: wrap; row-gap: 4px; }
.cr3-table .cr3-livrable-l > :not(.cr3-livrable-t) { order: 1; flex: none; }
:is(.app, body) .cr3-table .cr3-livrable-l > .cr3-livrable-t {
  order: 2; flex: 1 0 100%; display: block; font-size: 12.5px; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 340px;
}
.cr3-modif-puce {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 700; color: #F7A928;
  background: rgba(247,169,40,.12); border: 1px solid rgba(247,169,40,.35); cursor: help;
}

/* Petites pastilles de la 1re ligne : toutes à 20 px. */
.cr3-table .cr3-livrable-l > .cr-nature, .cr3-table .cr3-livrable-l > .cr-urgent,
.cr3-table .cr3-livrable-l > .cr3-final, .cr3-table .cr3-livrable-l > .cr3-attente-v,
.cr3-table .cr3-livrable-l > .cr-insp-badge {
  display: inline-flex; align-items: center; height: 20px; padding-block: 0; font-size: 10.5px; line-height: 1;
}

/* Personnes : avatar 24 px, prénom 12,5 px, une ligne. */
:is(.app, body) .cr3-table .cr3-avatar { width: 24px; height: 24px; font-size: 9.5px; }
.cr3-table .cr3-qui-l, .cr3-table .cr3-personne { font-size: 12.5px; white-space: nowrap; }

/* Statut et boutons : une seule hauteur. */
:is(.app, body) .cr3-table .cr3-pill { height: 30px; font-size: 11.5px; }
:is(.app, body) .cr3-table .cr3-btn,
:is(.app, body) .cr3-table .cr3-btn.cr3-prendre { height: 30px; padding: 0 14px; font-size: 12px; }
.cr3-table .cr3-icone { width: 30px; height: 30px; }
.cr3-actions-l > .cr3-btn:last-child { min-width: 128px; }

/* =========================================================================
   60 — TOUTES LES LISTES : UNE SEULE MESURE (18/09/2026)

   Direction : « f OS kaml ykono ga3 les listes m9aadinn ». La règle des
   sections 58-59 (CERCLE 25) s'étend à tout l'OS :
     • une hauteur de ligne par famille de tableau — 56 px pour les
       tableaux de données (`.tbl` des modules, `.sp-table`, Suivi
       clients, Contacts), 64 px pour la liste riche des RDV (SPIDER) ;
     • une cellule = deux lignes au plus (valeur 12,5 px, détail 11 px) ;
       ce qui dépasse finit en « … », le texte entier est dans la fiche
       ou dans l'infobulle ; seule la note garde deux lignes ;
     • pastilles 20 px, boutons 30 px, avatars 24 px, rayon 999 px ;
     • les lignes de liste (`.list-row`) : 52 px au moins, même marge,
       même motif titre / détail ;
     • à 400 px : c'est le tableau qui glisse dans sa boîte, jamais la page.
   `.cr3-table` n'est pas touchée (sections 58-59). La matrice de « Qui
   voit quoi » (`.qvq-matrice`) et la grille éditable du dossier
   (`.tdos-table`) ne sont pas des listes : hors champ. Un tableau de
   TEXTE (une explication, pas des données) porte `.tbl-texte` et garde
   ses phrases entières.
   ⚠ `!important` seulement là où master-v2 / 49.3 en posent déjà.
   ========================================================================= */

/* ── 60.1 L'en-tête : 10 px, majuscules espacées ── */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table, table.sp-rdv-table) > thead > tr > th {
  height: 40px !important; padding-top: 0; padding-bottom: 0;
  font-family: var(--f-body); font-size: 10px !important; font-weight: 600 !important;
  letter-spacing: .12em !important; text-transform: uppercase; white-space: nowrap; vertical-align: middle;
}

/* ── 60.2 Tableaux de données : 56 px, une valeur par ligne ── */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr:not(:has(> td[colspan])) { height: 56px; }
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td {
  padding-top: 8px !important; padding-bottom: 8px !important;
  padding-left: 14px; padding-right: 14px;
  font-size: 12.5px; line-height: 1.35; vertical-align: middle;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; max-width: 340px; overflow: hidden; text-overflow: ellipsis;
}
/* Les cellules qui portent un geste (bouton, menu « ⋯ », liste) ne
   coupent rien : le menu s'ouvre par-dessus la ligne suivante. */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td:has(button, select, input, .btn, [role="menu"]) {
  overflow: visible; max-width: none;
}
/* Lignes de groupe, lignes vides, tableaux de texte : le texte respire. */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td[colspan],
:is(.app, body) .main table.tbl-texte > tbody > tr > td {
  white-space: normal; max-width: none; overflow: visible;
}
:is(.app, body) .main table.tbl-texte > tbody > tr > td:last-child { min-width: 320px; }

/* Valeur et détail : 12,5 px puis 11 px, une ligne chacun. */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td :is(b, strong, .strong) {
  font-size: 12.5px; line-height: 1.35;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td :is(small, .muted, .fs-11, .fs-12, .hint) {
  display: block; max-width: 100%; font-size: 11px; line-height: 1.35;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td.muted { font-size: 11.5px; }
/* Les dates et les montants ne crient pas dans un tableau. */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td.mono { font-size: 12px; }

/* ── 60.3 Pastilles, boutons, avatars : une hauteur chacun ── */
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table, table.sp-rdv-table) > tbody > tr > td :is(.badge, .chip, .pill, .sp-rdv-type, .sp-sc-type, .sp-rdv-puce, .sp-rdv-lien, .sp-sc-wa, .sp-rdv-issue) {
  display: inline-flex; align-items: center; height: 20px; padding-block: 0; margin-block: 0;
  border-radius: 999px; font-size: 10.5px; line-height: 1; white-space: nowrap; vertical-align: middle;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table, table.sp-rdv-table) > tbody > tr > td :is(.btn, .btn-sm) {
  height: 30px; min-height: 30px; padding: 0 12px; font-size: 12px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; vertical-align: middle;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table, table.sp-rdv-table) > tbody > tr > td :is(.btn-icon, .sp-sc-plus) {
  width: 30px; min-width: 30px; padding: 0;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table, table.sp-rdv-table) > tbody > tr > td :is(.avatar, .cr3-avatar) {
  width: 24px; height: 24px; min-width: 24px; font-size: 9.5px;
}
:is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td :is(select, .select) {
  height: 30px; min-height: 30px; padding-block: 0; font-size: 12px; border-radius: 999px;
}
/* Le geste principal : même largeur d'une ligne à l'autre. */
:is(.app, body) .main table.tbl > tbody > tr > td.right > .btn:last-child { min-width: 84px; }

/* ── 60.4 Contacts (stock) : la même mesure ── */
:is(.app, body) .main table.stock-table .stock-nom b { display: block; max-width: 220px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
:is(.app, body) .main table.stock-table .col { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 2px; }
:is(.app, body) .main table.stock-table .col small { margin-top: 0; }

/* ── 60.5 Suivi clients (SPIDER) : 56 px, la note sur une ligne ── */
.sp-sc-table > tbody > tr.sp-sc-l { height: 56px; }
.sp-sc-table > tbody > tr.sp-sc-l > td { height: auto; padding-top: 8px; padding-bottom: 8px; font-size: 12.5px; line-height: 1.35; }
.sp-sc-table .sp-sc-nom { font-size: 12.5px; }
.sp-sc-table :is(.sp-sc-sous, .sp-sc-note-meta) { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-sc-table .sp-sc-note { font-size: 12.5px; line-height: 1.35; }
/* Avec sa ligne de détail (date · commercial), la note tient sur une ligne. */
.sp-sc-table .sp-sc-note:has(+ .sp-sc-note-meta) { -webkit-line-clamp: 1; }
.sp-sc-table .sp-sc-note-td { max-width: 320px; }
.sp-sc-table .sp-sc-date, .sp-sc-table .sp-sc-heure { font-size: 12.5px; font-variant-numeric: tabular-nums; }
.sp-sc-table .sp-sc-verif { font-size: 10px; line-height: 16px; }
.sp-sc-table .sp-sc-qui > span:last-child { font-size: 12.5px; }
:is(.app, body) .sp-sc-table .sp-sc-act .sp-sc-prim { min-width: 96px; }

/* ── 60.6 SPIDER · Liste des RDV : la ligne riche, 64 px ──
   Chaque cellule : la pastille (ou le nom) en haut, le détail dessous. */
.sp-rdv-table > tbody > tr.sp-rdv-l { height: 64px; }
.sp-rdv-table > tbody > tr.sp-rdv-l > td {
  padding-top: 8px; padding-bottom: 8px; vertical-align: middle; font-size: 12.5px; line-height: 1.35;
}
/* Quand : la pastille « En retard / Aujourd'hui / Demain » en haut,
   « jeu. 17/09 · 09:30 » sur UNE ligne dessous. */
.sp-rdv-table .sp-rdv-quand { width: 124px; }
:is(.app, body) .main table.sp-rdv-table > tbody > tr > td.sp-rdv-quand .sp-rdv-puce { display: flex; width: max-content; margin-bottom: 3px; }
.sp-rdv-table .sp-rdv-quand b { display: inline; font-size: 12.5px; font-weight: 700; }
.sp-rdv-table .sp-rdv-h { display: inline; margin: 0 0 0 6px; font-size: 12.5px; font-weight: 700; }
.sp-rdv-table .sp-rdv-h.vide { font-size: 11px; font-weight: 500; }
/* Client : le nom, puis téléphone et WhatsApp sur la même ligne. */
.sp-rdv-table .sp-rdv-nom {
  max-width: 210px; font-size: 12.5px; font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; overflow-wrap: normal;
}
.sp-rdv-table .sp-rdv-liens { flex-wrap: nowrap; gap: 5px; margin-top: 3px; }
.sp-rdv-table .sp-rdv-lien { padding: 0 8px; gap: 4px; }
/* Type : la pastille, l'adresse dessous en une ligne. */
.sp-rdv-table .sp-rdv-adresse { margin-top: 3px; white-space: nowrap; max-width: 170px; }
/* Commercial : avatar 24 px, prénom 12,5 px. */
.sp-rdv-table .sp-rdv-qui > span:last-child { font-size: 12.5px; }
/* Note : deux lignes ; une seule quand l'origine du rappel suit. */
.sp-rdv-table .sp-rdv-note-td { max-width: 320px; }
.sp-rdv-table .sp-rdv-note { font-size: 12.5px; line-height: 1.35; }
.sp-rdv-table .sp-rdv-note:has(+ .sp-rdv-origine) { -webkit-line-clamp: 1; }
.sp-rdv-table .sp-rdv-origine { margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Gestes : 30 px ; « Fait » a toujours la même largeur. */
.sp-rdv-table .sp-rdv-act { vertical-align: middle; }
:is(.app, body) .sp-rdv-table .sp-rdv-act .sp-rdv-b-fait { min-width: 76px; }
.sp-rdv-table .sp-rdv-issue { max-width: 240px; overflow: hidden; text-overflow: ellipsis; }

/* ── 60.7 Les lignes de liste : 52 px, titre / détail ── */
:is(.app, body) .main .page :is(.list-row, .presence-row) {
  min-height: 52px; padding-top: 8px; padding-bottom: 8px; padding-left: 16px; padding-right: 16px;
  align-items: center; box-sizing: border-box;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) > .grow { min-width: 0; overflow: hidden; }
:is(.app, body) .main .page :is(.list-row, .presence-row) > .grow.col { gap: 2px; }
:is(.app, body) .main .page :is(.list-row, .presence-row) > .grow :is(.strong, b, strong, h4) {
  display: block; font-size: 12.5px; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) > .grow :is(.muted, .fs-11, .fs-12, small, .hint) {
  display: block; margin-top: 0; font-size: 11px; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) > .grow.strong,
:is(.app, body) .main .page :is(.list-row, .presence-row) > .truncate {
  font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) > :is(.mono, .eyebrow) { flex: none; white-space: nowrap; font-size: 11px; }
:is(.app, body) .main .page :is(.list-row, .presence-row) > :is(.badge, .chip, .pill),
:is(.app, body) .main .page :is(.list-row, .presence-row) > * > .badge {
  height: 20px; padding-block: 0; font-size: 10.5px; line-height: 1; flex: none;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) :is(.btn, .btn-sm) {
  height: 30px; min-height: 30px; padding: 0 12px; font-size: 12px; flex: none;
}
:is(.app, body) .main .page :is(.list-row, .presence-row) > .avatar { width: 24px; height: 24px; min-width: 24px; font-size: 9.5px; flex: none; }
/* Les colonnes secondaires d'une ligne (poste, état…) : même motif. */
:is(.app, body) .main .page :is(.list-row, .presence-row) > .col:not(.grow) { gap: 2px; flex: none; }
:is(.app, body) .main .page :is(.list-row, .presence-row) > .col:not(.grow) > * { font-size: 12.5px; line-height: 1.35; white-space: nowrap; }
:is(.app, body) .main .page :is(.list-row, .presence-row) > .col:not(.grow) > :is(.muted, .fs-11, small) { font-size: 11px; }
:is(.app, body) .main .page :is(.list-row, .presence-row) :is(.icon-btn, .btn-icon) { width: 30px; height: 30px; min-width: 30px; padding: 0; }

/* ── 60.8 À 400 px : le tableau glisse, la ligne garde sa mesure ── */
@media (max-width: 640px) {
  :is(.app, body) .main :is(table.tbl, table.table, table.sp-table, table.stock-table) > tbody > tr > td {
    padding-top: 8px !important; padding-bottom: 8px !important; max-width: 260px;
  }
  .cadre-large, .sp-rdv-defile { overflow-x: auto; max-width: 100%; }
  /* Une ligne de liste : le titre et son détail sur la 1re rangée, les
     pastilles et gestes sur la 2de — jamais une troisième. */
  :is(.app, body) .main .page :is(.list-row, .presence-row) { flex-wrap: wrap; row-gap: 6px; padding-left: 14px; padding-right: 14px; }
  :is(.app, body) .main .page :is(.list-row, .presence-row) > .grow { flex: 1 1 calc(100% - 80px); }
}

/* =========================================================================
   61 — CERCLE 25 : COUVERTURE DE PROJET (18-19/09/2026)

   Direction : « f demande dir couverture de projet bach tla3 f dashboard
   ou tab9a tla3 f les demandes ou f les slides », puis « ya ajoutiwha mn
   l'OS, ya importiw nouveau photo mn desktop ». Le décor de la fenêtre
   vient de couvertures.css (`couv-`) ; ici, ce qui est propre à la
   couverture d'une demande (`cdm-`) et aux vignettes de la liste.
   ========================================================================= */

/* ── Le bloc dans « Nouvelle demande » et dans la fiche : 16/9 ── */
.cdm-bloc { margin: 0 0 14px; }
.cdm-bloc-cadre {
  position: relative; aspect-ratio: 16 / 9; max-height: 240px; width: 100%;
  border-radius: 16px; overflow: hidden; border: 1px solid rgba(255,255,255,.08);
  background: #0B121B;
}
.cdm-bloc-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cdm-bloc-voile { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(5,8,13,0) 40%, rgba(5,8,13,.85) 100%); }
.cdm-bloc-texte { position: absolute; left: 16px; bottom: 14px; right: 180px; display: grid; gap: 3px; }
.cdm-bloc-sur { font-size: 10px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: #E8C877; }
.cdm-bloc-etiquette { font-size: 12.5px; color: #F5F7FA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cdm-bloc-actions { position: absolute; right: 14px; bottom: 12px; }
.cdm-bloc-btn { height: 30px; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); background: rgba(10,16,24,.7); }
.cdm-bloc.par-defaut .cdm-bloc-etiquette { color: rgba(245,247,250,.7); font-style: italic; }

/* ── La fenêtre de choix : deux sources, bien visibles ── */
.cdm-onglets { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 14px 0 12px; }
.cdm-onglet {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; text-align: left; cursor: pointer;
  border-radius: 14px; border: 1px solid rgba(255,255,255,.09); background: rgba(255,255,255,.03);
  color: var(--n-tx); font: inherit; transition: border-color .2s ease, background .2s ease;
}
.cdm-onglet span { display: grid; gap: 2px; }
.cdm-onglet b { font-size: 13px; }
.cdm-onglet small { font-size: 11px; color: var(--n-tx-2); }
.cdm-onglet svg { flex: none; color: var(--n-tx-2); }
.cdm-onglet.on { border-color: rgba(242,185,64,.55); background: rgba(242,185,64,.08); }
.cdm-onglet.on svg { color: #F2B940; }
.cdm-onglet:focus-visible { outline: 2px solid var(--n-cyan, #12D9FF); outline-offset: 2px; }
.cdm-panneau { display: grid; gap: 14px; }
.cdm-groupe[hidden] { display: none; }
.cdm-grille { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.cdm-choix.is-on { outline: 2px solid #F2B940; outline-offset: 2px; }

.cdm-depot {
  display: grid; justify-items: center; gap: 6px; width: 100%; padding: 34px 18px; cursor: pointer;
  border-radius: 16px; border: 1.5px dashed rgba(242,185,64,.45); background: rgba(242,185,64,.04);
  color: var(--n-tx); font: inherit; text-align: center; transition: background .2s ease, border-color .2s ease;
}
.cdm-depot svg { color: #F2B940; }
.cdm-depot b { font-size: 14px; }
.cdm-depot span { font-size: 12.5px; color: var(--n-tx-2); }
.cdm-depot small { font-size: 11px; color: var(--n-tx-2); opacity: .8; }
.cdm-depot:hover, .cdm-survol .cdm-depot { background: rgba(242,185,64,.1); border-color: #F2B940; }
.cdm-retenu { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 12px; color: #7EE0A8; }
.cdm-retenu[hidden] { display: none; }
.cdm-survol .couv-corps { outline: 2px dashed rgba(242,185,64,.6); outline-offset: -8px; border-radius: 16px; }

/* ── La vignette dans la liste : 40 × 24, sur la ligne des pastilles ── */
.cr3-couv-mini {
  display: inline-block; flex: none; width: 40px; height: 24px; border-radius: 5px; overflow: hidden;
  border: 1px solid rgba(255,255,255,.1); vertical-align: middle;
}
.cr3-couv-mini img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cr3-table .cr3-livrable-l > .cr3-couv-mini { order: 0; height: 20px; width: 34px; }

/* ── La carte (vue Cartes) : la couverture en tête ── */
.cr2-carte-couv {
  display: block; aspect-ratio: 16 / 7; margin: -1px -1px 10px; border-radius: inherit;
  border-bottom-left-radius: 0; border-bottom-right-radius: 0; overflow: hidden;
}
.cr2-carte-couv img { display: block; width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 640px) {
  .cdm-onglets { grid-template-columns: 1fr; }
  .cdm-bloc-texte { right: 16px; bottom: 52px; }
  .cdm-bloc-actions { left: 14px; right: auto; }
  .cdm-grille { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) { .cdm-onglet, .cdm-depot { transition: none; } }

/* 61 bis — le bouton « Lien » de la ligne : doré quand un lien existe. */
.cr3-icone.cr3-lien.a-lien { color: #F2B940; border-color: rgba(242,185,64,.45); background: rgba(242,185,64,.08); }


/* ── LA CHAÎNE DU CERCLE, 21/09/2026 ─────────────────────────────
   Urgence, demande réservée, livraison promise : trois informations
   ajoutées aux lignes existantes, sans rien déplacer. */
.cr-urgence {
  display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; white-space: nowrap; border: 1px solid var(--n-bord);
}
.cr-urgence.u-standard { color: var(--brand); border-color: var(--brand-line); background: var(--brand-soft); }
.cr-urgence.u-tranquille { color: #9FB4CC; border-color: rgba(159,180,204,.35); }
.cr3-personne.reservee { color: var(--brand); font-style: normal; font-weight: 600; }
.cr-promis { font-family: var(--f-mono, ui-monospace, monospace); }
.cr-seg-b small { font-size: 11px; opacity: .72; }
.cr-seg-b.u-urgent.on { border-color: var(--n-rouge); background: rgba(239,68,68,.14); color: var(--n-tx); }
.cr-prise-regle { margin: 0; font-size: 13px; line-height: 1.5; color: var(--n-tx-2);
  padding: 9px 11px; border-radius: 10px; background: rgba(255,255,255,.03); border: 1px solid var(--n-bord); }
.cr-prise-erreur { margin: 0; min-height: 1em; font-size: 12.5px; color: var(--n-rouge); }
.cr3-heure { display: block; font-size: 12px; font-weight: 600; color: var(--brand); }
/* Un bouton principal bloqué doit AVOIR l'air bloqué (fenêtre « Je prends »). */
.modal .modal-foot .btn-primary:disabled { opacity: .42; cursor: not-allowed; filter: saturate(.4); }


/* ── LA CHAÎNE DU CERCLE, VERSION PREMIUM — 21/09/2026 ───────────
   « zid tala3 lih la quality ou zid animih kteer ».

   ⚠ LA RÈGLE DE CET OS (perf.css) : tout est mis en pause quand
   l'onglet passe en arrière-plan. Donc AUCUNE entrée qui partirait de
   l'invisible : on anime des OMBRES, des FONDS et des TRANSFORMATIONS
   légères, jamais l'opacité d'un contenu à lire. Une animation figée
   sur sa première image laisse ici une ligne teintée d'or, jamais un
   écran vide. */

/* Les pastilles d'urgence du formulaire */
.cr-seg-b.u-urgent::before, .cr-seg-b.u-standard::before, .cr-seg-b.u-tranquille::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none;
  transition: transform .25s ease, box-shadow .35s ease;
}
.cr-seg-b.u-urgent::before { background: var(--n-rouge); }
.cr-seg-b.u-standard::before { background: #E9A92E; }
.cr-seg-b.u-tranquille::before { background: #9FB4CC; }
.cr-seg-b.u-urgent, .cr-seg-b.u-standard, .cr-seg-b.u-tranquille {
  transition: transform .2s ease, background .3s ease, border-color .3s ease, box-shadow .3s ease, color .2s ease;
}
.cr-seg-b.u-urgent:hover, .cr-seg-b.u-standard:hover, .cr-seg-b.u-tranquille:hover { transform: translateY(-1px); }
.cr-seg-b.on::before { transform: scale(1.25); }
.cr-seg-b.u-urgent.on { box-shadow: 0 8px 24px -10px rgba(239,68,68,.9); }
.cr-seg-b.u-urgent.on::before { animation: cr-pouls-rouge 1.4s ease-in-out infinite; }
.cr-seg-b.u-standard.on { box-shadow: 0 8px 24px -10px rgba(233,169,46,.9); }
.cr-seg-b.u-tranquille.on { background: rgba(159,180,204,.14); border-color: rgba(159,180,204,.55); box-shadow: 0 8px 24px -12px rgba(159,180,204,.7); }

/* Les pastilles sur les lignes */
.cr-urgent { animation: cr-halo-rouge 2.6s ease-in-out infinite; }
.cr-urgence { transition: transform .2s ease; }
.cr3-l:hover .cr-urgence { transform: translateY(-1px); }
.cr3-personne.reservee { display: inline-flex; align-items: center; gap: 6px; }
.cr3-personne.reservee::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--brand);
  box-shadow: 0 0 0 3px rgba(212,169,79,.18); animation: cr-souffle-or 2.4s ease-in-out infinite;
}

/* L'heure promise */
.cr3-heure { transition: color .3s ease; }
.cr3-heure.bientot { color: var(--n-orange); }
.cr3-heure.bientot::after, .cr3-heure.retard::after {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-left: 6px; border-radius: 50%;
  vertical-align: middle; background: currentColor;
}
.cr3-heure.bientot::after { animation: cr-souffle-orange 1.8s ease-in-out infinite; }
.cr3-heure.retard { color: var(--n-rouge); }
.cr3-heure.retard::after { animation: cr-pouls-rouge 1s ease-in-out infinite; }

/* La ligne qu'on vient de prendre, ou dont le lien vient de partir */
.cr3-l.cr-eclat > td { animation: cr-eclat-or 1.6s cubic-bezier(.2,.7,.2,1) 1; }

/* Les deux gestes de la chaîne : un reflet qui traverse au survol */
.cr3-btn.cr3-prendre, .cr3-btn.cr3-poser { position: relative; overflow: hidden; isolation: isolate; }
.cr3-btn.cr3-prendre::after, .cr3-btn.cr3-poser::after {
  content: ""; position: absolute; inset: -40% auto -40% -60%; width: 45%; z-index: -1; pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.55), transparent);
  transform: translateX(0) skewX(-18deg); transition: transform .7s cubic-bezier(.2,.7,.2,1);
}
.cr3-btn.cr3-prendre:hover::after, .cr3-btn.cr3-poser:hover::after { transform: translateX(420%) skewX(-18deg); }

/* ── La fenêtre « Je prends » ── */
.modal.cr-prise-modal { width: min(560px, calc(100vw - 28px)); }
.cr-prise { display: grid; gap: 16px; }
.cr-prise-tete {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 14px;
  border: 1px solid var(--brand-line); background: linear-gradient(135deg, rgba(212,169,79,.14), rgba(212,169,79,0) 65%);
}
.cr-prise-tete.u-urgent { border-color: rgba(239,68,68,.45); background: linear-gradient(135deg, rgba(239,68,68,.18), rgba(239,68,68,0) 65%); }
.cr-prise-tete.u-tranquille { border-color: rgba(159,180,204,.4); background: linear-gradient(135deg, rgba(159,180,204,.16), rgba(159,180,204,0) 65%); }
.cr-prise-tete b { display: block; font-size: 14px; color: var(--n-tx); }
.cr-prise-tete span { font-size: 12.5px; color: var(--n-tx-2); }
.cr-prise-point { width: 11px; height: 11px; border-radius: 50%; flex: none; background: #E9A92E; animation: cr-souffle-or 2.2s ease-in-out infinite; }
.cr-prise-tete.u-urgent .cr-prise-point { background: var(--n-rouge); animation: cr-pouls-rouge 1.2s ease-in-out infinite; }
.cr-prise-tete.u-tranquille .cr-prise-point { background: #9FB4CC; animation: none; box-shadow: 0 0 0 4px rgba(159,180,204,.18); }

.cr-prise-resume {
  display: grid; gap: 3px; padding: 14px 16px; border-radius: 14px; border: 1px dashed var(--n-bord);
  transition: border-color .35s ease, background .35s ease, box-shadow .35s ease;
}
.cr-prise-resume b { font: 700 19px/1.2 var(--f-mono, ui-monospace, monospace); color: var(--n-tx-2); letter-spacing: -.01em; transition: color .3s ease, transform .3s cubic-bezier(.2,.7,.2,1); }
.cr-prise-resume span { font-size: 12px; color: var(--n-tx-2); }
.cr-prise-resume.pret { border-style: solid; border-color: var(--brand-line); background: var(--brand-soft); box-shadow: 0 14px 34px -18px rgba(233,169,46,.8); }
.cr-prise-resume.pret b { color: var(--n-tx); transform: translateX(2px); }

.cr-prise-bloc { display: grid; gap: 8px; }
.cr-prise-label { font: 600 10.5px/1 var(--f-mono, ui-monospace, monospace); letter-spacing: .14em; text-transform: uppercase; color: var(--n-tx-2); }
.cr-prise-jours { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 6px; scroll-snap-type: x mandatory; scrollbar-width: thin; }
.cr-jour {
  flex: 0 0 auto; scroll-snap-align: start; display: grid; justify-items: center; gap: 3px; min-width: 60px;
  padding: 9px 8px; border-radius: 13px; border: 1px solid var(--n-bord); background: rgba(255,255,255,.02);
  color: var(--n-tx-2); font: inherit; cursor: pointer;
  transition: transform .2s cubic-bezier(.2,.7,.2,1), border-color .2s ease, background .3s ease, color .2s ease, box-shadow .3s ease;
}
.cr-jour small { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; }
.cr-jour b { font: 700 19px/1 var(--f-mono, ui-monospace, monospace); color: var(--n-tx); }
.cr-jour:hover { transform: translateY(-2px); border-color: var(--brand-line); }
.cr-jour.on { transform: translateY(-3px); border-color: transparent; color: #1A1204;
  background: linear-gradient(180deg, #FAD377, #E9A92E); box-shadow: 0 12px 26px -10px rgba(233,169,46,.95); }
.cr-jour.on b { color: #1A1204; }
.cr-prise-heures { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.cr-heure {
  padding: 9px 0; border-radius: 10px; border: 1px solid var(--n-bord); background: transparent;
  color: var(--n-tx-2); font: 600 12.5px/1 var(--f-mono, ui-monospace, monospace); cursor: pointer;
  transition: transform .18s cubic-bezier(.2,.7,.2,1), background .25s ease, color .2s ease, border-color .2s ease, box-shadow .25s ease;
}
.cr-heure:hover:not(:disabled) { border-color: var(--brand-line); color: var(--n-tx); transform: translateY(-1px); }
.cr-heure.on { background: var(--brand-soft); border-color: var(--brand); color: var(--n-tx); transform: scale(1.06); box-shadow: 0 8px 18px -10px rgba(233,169,46,.9); }
.cr-heure:disabled { opacity: .22; cursor: not-allowed; text-decoration: line-through; }
@media (max-width: 480px) { .cr-prise-heures { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.modal .modal-foot .cr-prise-ok:not(:disabled) { box-shadow: 0 12px 28px -12px rgba(242,185,64,.95); }

/* Les boucles d'ambiance */
@keyframes cr-halo-rouge { 0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,.0); } 50% { box-shadow: 0 0 0 4px rgba(239,68,68,.22); } }
@keyframes cr-pouls-rouge { 0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,.55); } 60% { box-shadow: 0 0 0 7px rgba(239,68,68,0); } }
@keyframes cr-souffle-or { 0%, 100% { box-shadow: 0 0 0 0 rgba(233,169,46,.45); } 55% { box-shadow: 0 0 0 7px rgba(233,169,46,0); } }
@keyframes cr-souffle-orange { 0%, 100% { box-shadow: 0 0 0 0 rgba(251,146,60,.5); } 55% { box-shadow: 0 0 0 6px rgba(251,146,60,0); } }
@keyframes cr-eclat-or {
  0% { background-color: rgba(233,169,46,.30); box-shadow: inset 0 0 0 1px rgba(233,169,46,.55); }
  100% { background-color: transparent; box-shadow: inset 0 0 0 1px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .cr-urgent, .cr3-personne.reservee::before, .cr3-heure.bientot::after, .cr3-heure.retard::after,
  .cr-prise-point, .cr-seg-b.u-urgent.on::before, .cr3-l.cr-eclat > td { animation: none; }
  .cr-jour, .cr-heure, .cr-prise-resume b, .cr3-btn.cr3-prendre::after, .cr3-btn.cr3-poser::after { transition: none; }
}


/* ── LES TITRES DES ÉTAPES EN VALEUR — 21/09/2026 ────────────────
   Direction : « demande et production et livré, hadok des titres,
   khasshom ykono en valeur kter ». Ils faisaient 13 px dans la liste
   et 14 px dans la barre : on les lisait comme des légendes. Chaque
   étape porte maintenant SA couleur (--g : Demande corail, Production
   bleu, Livré or), un bandeau qui s'efface vers la droite, et un point
   qui respire. Une boucle d'ambiance seulement — aucune entrée animée,
   règle de perf.css. */
.cr3-groupe td { padding: 26px 16px 10px; }
.cr3-groupe-l {
  gap: 12px; flex-wrap: wrap; padding: 13px 18px; border-radius: 14px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--g) 17%, transparent), transparent 72%);
  border: 1px solid color-mix(in srgb, var(--g) 30%, transparent);
  box-shadow: 0 14px 34px -24px var(--g);
}
.cr3-groupe-l b { font-size: 19px; font-weight: 800; letter-spacing: -.01em; color: var(--n-tx); }
.cr3-groupe-point { width: 12px; height: 12px; background: var(--g); animation: cr-groupe-souffle 2.6s ease-in-out infinite; }
.cr3-groupe-n {
  font-size: 13px; font-weight: 700; padding: 3px 11px; color: var(--g);
  background: color-mix(in srgb, var(--g) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--g) 36%, transparent);
}
.cr3-groupe-qui { font-size: 12.5px; color: var(--n-tx-2); }
@keyframes cr-groupe-souffle {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--g) 60%, transparent); }
  60% { box-shadow: 0 0 0 8px transparent; }
}

/* La barre des trois étapes, en haut */
.cr3-pas-t b { font-size: 17px; font-weight: 750; letter-spacing: -.01em; transition: color .25s ease, text-shadow .35s ease; }
.cr3-pas.on .cr3-pas-t b { color: var(--n-tx); text-shadow: 0 0 20px rgba(242,185,64,.5); }
.cr3-pas-n { font-size: 13px; padding: 2px 9px; }
.cr3-pas-qui { font-size: 12px; }

@media (max-width: 640px) {
  .cr3-groupe td { padding: 18px 10px 8px; }
  .cr3-groupe-l { padding: 11px 13px; }
  .cr3-groupe-l b { font-size: 17px; }
  .cr3-pas-t b { font-size: 15px; }
}
@media (prefers-reduced-motion: reduce) { .cr3-groupe-point { animation: none; } }

/* ═══════════════════════════════════════════════════════════════
   21/09 SOIR — « METS TA DATE » ET « MODIF N°2 »
   Les lignes prises avant la règle « jour + heure » se voient, et
   leur monteur pose sa date en un geste. Les allers-retours de modif
   se comptent ; une modif qui attend plus de 24 h passe au rouge.
   Aucune entrée depuis opacity 0 (voir perf.css) : seulement des
   boucles d'ambiance sur box-shadow.
   ═══════════════════════════════════════════════════════════════ */
.cr3-rappel {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 0 0 14px; padding: 14px 16px; border-radius: 14px;
  background: linear-gradient(90deg, rgba(247,169,40,.16), rgba(247,169,40,.04) 70%);
  border: 1px solid rgba(247,169,40,.38);
  box-shadow: 0 16px 36px -26px #F7A928;
}
.cr3-rappel-ico {
  display: grid; place-items: center; flex: none; width: 38px; height: 38px; border-radius: 12px;
  color: #F7A928; background: rgba(247,169,40,.14); border: 1px solid rgba(247,169,40,.4);
  animation: cr-souffle-orange 2.4s ease-in-out infinite;
}
.cr3-rappel-t { display: grid; gap: 2px; flex: 1 1 260px; min-width: 0; }
.cr3-rappel-t b { font-size: 15px; font-weight: 750; color: var(--n-tx); }
.cr3-rappel-t span { font-size: 12.5px; color: var(--n-tx-2); }
.cr3-rappel-go {
  flex: none; height: 38px; padding: 0 18px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 13px; font-weight: 750; color: #1a1204;
  background: linear-gradient(180deg, #FFD27A, #F2B940); border: 1px solid rgba(255,210,122,.8);
  box-shadow: 0 8px 22px -12px #F2B940; transition: transform .15s ease, box-shadow .2s ease;
}
.cr3-rappel-go:hover { transform: translateY(-1px); box-shadow: 0 12px 26px -12px #F2B940; }
.cr3-rappel-go:focus-visible { outline: 2px solid #FFD27A; outline-offset: 3px; }

.cr3-sans-date {
  display: inline-flex; align-items: center; margin-top: 4px; height: 18px; padding: 0 7px;
  border-radius: 999px; font-size: 10.5px; font-weight: 700; white-space: nowrap;
  color: #F7A928; background: rgba(247,169,40,.12); border: 1px dashed rgba(247,169,40,.55);
}
:is(.app, body) .cr3-table .cr3-btn.cr3-mettre-date {
  color: #F7A928; background: rgba(247,169,40,.12); border-color: rgba(247,169,40,.5);
  animation: cr-souffle-orange 2.4s ease-in-out infinite;
}
:is(.app, body) .cr3-table .cr3-btn.cr3-mettre-date:hover { background: rgba(247,169,40,.2); }

.cr3-modif-puce.vieille {
  color: #FF5A63; background: rgba(255,90,99,.12); border-color: rgba(255,90,99,.45);
  animation: cr-pouls-rouge 1.6s ease-in-out infinite;
}
@media (max-width: 640px) {
  .cr3-rappel { padding: 12px; gap: 10px; }
  .cr3-rappel-go { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .cr3-rappel-ico, :is(.app, body) .cr3-table .cr3-btn.cr3-mettre-date, .cr3-modif-puce.vieille { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════
   21/09 NUIT — LA FENÊTRE DE LECTURE (core/lecture.js)
   « n9raw lmsg f OS ou 3ad ndokhlo » : le message en grand, comme
   l'écran verrouillé de la démo, puis on entre dans l'écran.
   Les entrées partent d'un état VISIBLE (glissement, échelle) —
   jamais d'opacity 0 : perf.css met les animations en pause dans un
   onglet caché.
   ═══════════════════════════════════════════════════════════════ */
@property --lec-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }

.lec-voile {
  position: fixed; inset: 0; z-index: 400;
  display: grid; place-items: center; padding: 18px; overflow-y: auto;
  background:
    radial-gradient(70% 55% at 50% 18%, rgba(242,185,64,.16), transparent 70%),
    radial-gradient(60% 50% at 50% 100%, rgba(18,217,255,.10), transparent 70%),
    rgba(3,6,10,.74);
  backdrop-filter: blur(12px) saturate(1.2);
}
.lec-voile.sort { animation: lec-voile-out .18s ease both; }
@keyframes lec-voile-out { to { opacity: 0; } }

.lec-carte {
  position: relative; isolation: isolate;
  width: min(440px, 100%); padding: 22px 22px 18px; border-radius: 30px;
  display: grid; gap: 14px; color: #F5F7FA;
  background: linear-gradient(165deg, rgba(34,28,52,.97), rgba(12,17,27,.98) 55%, rgba(7,9,13,.99));
  box-shadow: 0 40px 100px -30px rgba(0,0,0,.95), 0 0 0 1px rgba(255,255,255,.06), inset 0 1px 0 rgba(255,255,255,.08);
  animation: lec-carte-in .5s cubic-bezier(.2,.9,.25,1.15) both;
}
/* La bordure qui tourne : un anneau conique autour de la carte. */
.lec-carte::before {
  content: ""; position: absolute; inset: -1.5px; z-index: -1; border-radius: 31.5px; padding: 1.5px;
  background: conic-gradient(from var(--lec-angle), rgba(242,185,64,0), #F2B940 18%, rgba(18,217,255,.8) 36%, rgba(242,185,64,0) 55%, rgba(255,90,99,.55) 78%, rgba(242,185,64,0));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  animation: lec-tourne 6s linear infinite;
}
/* Un reflet qui traverse la carte. */
.lec-carte::after {
  content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; pointer-events: none;
  background: linear-gradient(110deg, transparent 35%, rgba(255,255,255,.06) 48%, transparent 60%);
  background-size: 250% 100%; animation: lec-reflet 5.5s ease-in-out .3s infinite;
}
.lec-halo {
  position: absolute; z-index: -1; left: 50%; top: -60px; width: 260px; height: 160px; margin-left: -130px;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(242,185,64,.30), transparent);
  filter: blur(8px); animation: lec-respire 4s ease-in-out infinite;
}
@keyframes lec-carte-in { from { transform: translateY(26px) scale(.94); } }
@keyframes lec-tourne { to { --lec-angle: 360deg; } }
@keyframes lec-reflet { 0% { background-position: 120% 0; } 45%, 100% { background-position: -40% 0; } }
@keyframes lec-respire { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }

.lec-tete { display: flex; align-items: center; gap: 9px; font-size: 12px; color: #8C98AA; letter-spacing: .03em; }
.lec-app {
  display: grid; place-items: center; width: 26px; height: 26px; border-radius: 8px; flex: none;
  color: #1A1204; background: linear-gradient(180deg, #FFD27A, #F2B940);
  box-shadow: 0 6px 16px -6px #F2B940; animation: lec-cloche 2.8s ease-in-out .6s infinite;
}
@keyframes lec-cloche { 0%, 70%, 100% { transform: rotate(0); } 74% { transform: rotate(14deg); } 80% { transform: rotate(-12deg); } 86% { transform: rotate(7deg); } 92% { transform: rotate(-4deg); } }
.lec-marque { font-weight: 700; color: #F5F7FA; letter-spacing: .08em; }
.lec-quand { margin-left: auto; display: inline-flex; gap: 6px; align-items: baseline; }
.lec-quand b { color: #F5F7FA; font-size: 13px; }
.lec-x {
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; flex: none; cursor: pointer;
  color: #8C98AA; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.08);
  transition: background .2s ease, color .2s ease, transform .2s ease;
}
.lec-x:hover { color: #F5F7FA; background: rgba(255,255,255,.12); transform: rotate(90deg); }

.lec-titre {
  margin: 2px 0 0; font-size: 25px; font-weight: 800; letter-spacing: -.02em; line-height: 1.15; text-wrap: balance;
  color: #FFE3A3;
  background: linear-gradient(90deg, #FFFFFF, #FFE3A3 55%, #F2B940); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ⚠ `grid-auto-rows: max-content` N'EST PAS DÉCORATIF — 23/09/2026
   Une grille dont la hauteur est BORNÉE (ici max-height + overflow)
   partage cette hauteur entre ses rangées au lieu de déborder : à
   partir de quelques lignes, chacune est écrasée à deux ou trois
   pixels et l'ascenseur ne sert à rien (scrollHeight = clientHeight).
   C'est le bug déjà vu sur `.s25-taches` dans le SPIDER. Toute
   grille qui défile doit porter ces deux lignes. */
.lec-corps { position: relative; z-index: 2; display: grid; gap: 14px; grid-auto-rows: max-content; align-content: start; max-height: min(58vh, 520px); overflow-y: auto; padding-right: 2px; }
.lec-bloc { display: grid; gap: 7px; }
.lec-bloc-t {
  margin: 0; font-size: 11px; font-weight: 800; letter-spacing: .16em; color: #F2B940;
  display: flex; align-items: center; gap: 10px;
  animation: lec-glisse .45s cubic-bezier(.2,.9,.25,1.1) both; animation-delay: calc(var(--i, 0) * 70ms + 150ms);
}
.lec-bloc-t::after { content: ""; flex: 1; height: 1px; background: linear-gradient(90deg, rgba(242,185,64,.45), transparent); }

.lec-ligne {
  --c: #12D9FF;
  display: grid; grid-template-columns: 58px 1fr; align-items: center; gap: 12px;
  padding: 10px 14px 10px 10px; border-radius: 16px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--c) 13%, transparent), rgba(255,255,255,.03) 70%);
  border: 1px solid color-mix(in srgb, var(--c) 26%, transparent);
  animation: lec-glisse .45s cubic-bezier(.2,.9,.25,1.1) both; animation-delay: calc(var(--i, 0) * 70ms + 150ms);
  transition: transform .2s ease, border-color .2s ease;
}
.lec-ligne:hover { transform: translateX(3px); border-color: color-mix(in srgb, var(--c) 50%, transparent); }
.lec-ligne.t-or { --c: #F2B940; }
.lec-ligne.t-orange { --c: #F7A928; }
.lec-ligne.t-rouge { --c: #FF5A63; }
.lec-ligne.t-cyan { --c: #12D9FF; }
.lec-ligne.t-zero { --c: #8C98AA; background: rgba(255,255,255,.025); border-color: rgba(255,255,255,.06); }
.lec-n {
  justify-self: center; font-size: 26px; font-weight: 800; line-height: 1; color: var(--c);
  text-shadow: 0 0 18px color-mix(in srgb, var(--c) 55%, transparent);
}
.lec-ligne.t-zero .lec-n { text-shadow: none; color: #6B7688; }
.lec-ligne.t-rouge .lec-n { animation: lec-pouls 1.8s ease-in-out infinite; }
.lec-l { font-size: 14.5px; font-weight: 600; line-height: 1.35; color: #F5F7FA; }
.lec-ligne.t-zero .lec-l { color: #8C98AA; font-weight: 500; }
.lec-ligne.texte { grid-template-columns: 14px 1fr; --c: #F7A928; }
.lec-ligne.texte p { margin: 0; font-size: 13.5px; line-height: 1.45; color: #F5F7FA; }
.lec-point { width: 8px; height: 8px; border-radius: 50%; background: var(--c); box-shadow: 0 0 10px var(--c); justify-self: center; }
.lec-phrase { margin: 0; font-size: 15px; line-height: 1.55; white-space: pre-line; color: #F5F7FA; animation: lec-glisse .45s ease both .15s; }
@keyframes lec-glisse { from { transform: translateY(12px) scale(.97); } }
@keyframes lec-pouls { 0%, 100% { text-shadow: 0 0 10px rgba(255,90,99,.4); } 50% { text-shadow: 0 0 26px rgba(255,90,99,.95); } }

.lec-pied { position: relative; z-index: 2; display: flex; gap: 10px; flex-wrap: wrap; padding-top: 4px; }
.lec-entrer {
  position: relative; overflow: hidden; flex: 1 1 200px;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 48px; padding: 0 20px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 15px; font-weight: 800; color: #1A1204;
  background: linear-gradient(180deg, #FFD98A, #F2B940 60%, #E0A020);
  border: 1px solid rgba(255,217,138,.9);
  box-shadow: 0 14px 34px -14px #F2B940, inset 0 1px 0 rgba(255,255,255,.55);
  transition: transform .15s ease, box-shadow .2s ease;
}
.lec-entrer::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(110deg, transparent 30%, rgba(255,255,255,.55) 48%, transparent 64%);
  transform: translateX(-120%); animation: lec-brille 3.2s ease-in-out 1s infinite;
}
.lec-entrer:hover { transform: translateY(-1px); box-shadow: 0 18px 40px -14px #F2B940, inset 0 1px 0 rgba(255,255,255,.55); }
.lec-entrer:hover .lec-fleche { transform: translateX(4px); }
.lec-fleche { display: inline-grid; transition: transform .2s ease; }
@keyframes lec-brille { 0%, 55% { transform: translateX(-120%); } 85%, 100% { transform: translateX(120%); } }
.lec-plus-tard {
  height: 48px; padding: 0 20px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 14px; font-weight: 600;
  color: #8C98AA; background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1);
  transition: background .2s ease, color .2s ease;
}
.lec-plus-tard:hover { color: #F5F7FA; background: rgba(255,255,255,.1); }
.lec-entrer:focus-visible, .lec-plus-tard:focus-visible, .lec-x:focus-visible { outline: 2px solid #FFD27A; outline-offset: 3px; }

@media (max-width: 520px) {
  .lec-voile { place-items: end center; padding: 10px; }
  .lec-carte { padding: 18px 16px 16px; border-radius: 26px; }
  .lec-titre { font-size: 22px; }
  .lec-ligne { grid-template-columns: 48px 1fr; }
  .lec-n { font-size: 23px; }
  .lec-pied { flex-direction: column-reverse; }
  .lec-entrer, .lec-plus-tard { width: 100%; flex: none; }
}
@media (prefers-reduced-motion: reduce) {
  .lec-carte, .lec-carte::before, .lec-carte::after, .lec-halo, .lec-app, .lec-bloc-t, .lec-ligne,
  .lec-n, .lec-phrase, .lec-entrer::after { animation: none !important; }
}

/* Point du matin (boutons WhatsApp) : le texte est une liste. */
.s25-quoi small.s25-texte-liste { display: block; white-space: pre-line; line-height: 1.5; }

/* ═══════════════════════════════════════════════════════════════
   21/09 NUIT — « DONNER À… » : répartir le travail d'un clic
   La cellule « Qui » devient un bouton (Direction, RT) ; la fenêtre
   liste l'atelier du moins chargé au plus chargé, avec une jauge.
   ═══════════════════════════════════════════════════════════════ */
.cr3-donner {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  padding: 3px 8px 3px 3px; margin: -3px 0 -3px -3px; border-radius: 999px; cursor: pointer;
  font: inherit; color: inherit; background: transparent; border: 1px dashed transparent;
  transition: background .2s ease, border-color .2s ease, transform .15s ease;
}
.cr3-donner:hover { background: rgba(242,185,64,.08); border-color: rgba(242,185,64,.4); }
.cr3-donner:active { transform: scale(.97); }
.cr3-donner-ico { display: inline-grid; color: #F2B940; opacity: .5; transition: opacity .2s ease, transform .2s ease; }
.cr3-donner:hover .cr3-donner-ico { opacity: 1; transform: translateY(1px); }
.cr3-donner:focus-visible { outline: 2px solid #FFD27A; outline-offset: 2px; }

.cr-donner { display: grid; gap: 12px; }
.cr-donner-quoi { margin: 0; font-size: 13px; color: #8C98AA; }
.cr-donner-quoi b { color: #F5F7FA; }
.cr-donner-liste { display: grid; gap: 8px; }
.cr-donner-p {
  position: relative; display: grid; grid-template-columns: 32px 1fr auto; align-items: center; gap: 12px;
  padding: 10px 14px 14px 10px; border-radius: 14px; cursor: pointer; text-align: left;
  font: inherit; color: #F5F7FA;
  background: rgba(255,255,255,.035); border: 1px solid rgba(255,255,255,.08);
  animation: donner-glisse .4s cubic-bezier(.2,.9,.25,1.1) both; animation-delay: calc(var(--i, 0) * 55ms);
  transition: transform .18s ease, border-color .2s ease, background .2s ease;
}
.cr-donner-p:hover { transform: translateX(3px); border-color: rgba(242,185,64,.45); background: rgba(242,185,64,.07); }
.cr-donner-p:disabled { opacity: .6; cursor: progress; }
.cr-donner-p.libre { border-color: rgba(36,217,129,.4); background: linear-gradient(90deg, rgba(36,217,129,.10), rgba(255,255,255,.03) 70%); }
.cr-donner-p .cr3-avatar { width: 32px; height: 32px; font-size: 11px; }
.cr-donner-nom { display: grid; gap: 1px; min-width: 0; }
.cr-donner-nom b { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cr-donner-nom small { font-size: 12px; color: #8C98AA; }
.cr-donner-tag {
  font-size: 10.5px; font-weight: 800; letter-spacing: .04em; padding: 3px 9px; border-radius: 999px;
  color: #24D981; background: rgba(36,217,129,.12); border: 1px solid rgba(36,217,129,.35);
}
.cr-donner-jauge { position: absolute; left: 54px; right: 14px; bottom: 6px; height: 3px; border-radius: 3px; background: rgba(255,255,255,.06); overflow: hidden; }
.cr-donner-jauge i { display: block; height: 100%; width: var(--p, 0%); border-radius: inherit; background: linear-gradient(90deg, #24D981, #F2B940); }
.cr-donner-p.plein .cr-donner-jauge i { background: linear-gradient(90deg, #F7A928, #FF5A63); }
@keyframes donner-glisse { from { transform: translateY(10px) scale(.98); } }
@media (prefers-reduced-motion: reduce) { .cr-donner-p { animation: none; } }

/* 22/09 — le rappel de modif : même bandeau que « Mets ta date », en rouge. */
.cr3-rappel.modif {
  background: linear-gradient(90deg, rgba(255,90,99,.16), rgba(255,90,99,.04) 70%);
  border-color: rgba(255,90,99,.42); box-shadow: 0 16px 36px -26px #FF5A63;
}
.cr3-rappel.modif .cr3-rappel-ico {
  color: #FF5A63; background: rgba(255,90,99,.14); border-color: rgba(255,90,99,.45);
  animation: cr-pouls-rouge 1.8s ease-in-out infinite;
}
.cr3-rappel-go.rouge {
  color: #fff; background: linear-gradient(180deg, #FF7A82, #E5484F); border-color: rgba(255,122,130,.8);
  box-shadow: 0 8px 22px -12px #FF5A63;
}
.cr3-rappel-go.rouge:hover { box-shadow: 0 12px 26px -12px #FF5A63; }
@media (prefers-reduced-motion: reduce) { .cr3-rappel.modif .cr3-rappel-ico { animation: none; } }

/* ═══════════════════════════════════════════════════════════════
   22/09 — MA JOURNÉE et CETTE SEMAINE (pages/ma-journee.js), posées
   sous l'en-tête de l'accueil. Même langage que la démo validée.
   Couleurs en dur : le bloc vit sur le fond sombre de l'accueil.
   ═══════════════════════════════════════════════════════════════ */
.mj-hote { display: grid; gap: 16px; margin: 4px 0 22px; }
.mj-hote:empty { display: none; }
.mj { display: grid; gap: 14px; color: #F5F7FA; }
.mj-salut {
  display: flex; justify-content: space-between; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 18px 20px; border-radius: 18px;
  background: linear-gradient(120deg, rgba(242,185,64,.14), rgba(18,217,255,.05) 70%);
  border: 1px solid rgba(242,185,64,.25);
}
.mj-salut small { font-size: 11px; font-weight: 800; letter-spacing: .14em; color: #F2B940; }
.mj-salut h2 { margin: 2px 0 0; font-size: 24px; font-weight: 800; letter-spacing: -.01em; color: #F5F7FA; }
.mj-salut p { margin: 2px 0 0; color: #C9CFD9; font-size: 14px; }
.mj-anneau {
  --p: 0%; flex: none; width: 76px; height: 76px; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(#F2B940 var(--p), rgba(255,255,255,.08) 0);
}
.mj-anneau span { width: 62px; height: 62px; border-radius: 50%; display: grid; place-items: center; background: #0C121C; font-weight: 700; font-size: 15px; color: #F5F7FA; }

.mj-cartes { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; }
.mj-carte {
  --c: #12D9FF; position: relative; overflow: hidden; display: grid; gap: 5px; padding: 14px 14px 12px;
  border-radius: 16px; background: #111925; border: 1px solid rgba(255,255,255,.08);
}
.mj-carte::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px; background: var(--c); }
.mj-carte.t-or { --c: #F2B940; } .mj-carte.t-rouge { --c: #FF5A63; } .mj-carte.t-orange { --c: #F7A928; }
.mj-carte.t-vert { --c: #24D981; } .mj-carte.t-cyan { --c: #12D9FF; } .mj-carte.t-gris { --c: #8C98AA; }
.mj-carte.t-zero { --c: #3A4558; }
.mj-n { font-size: 30px; font-weight: 700; line-height: 1; color: var(--c); }
.mj-carte.t-zero .mj-n { color: #5E6A7C; }
.mj-l { font-weight: 700; font-size: 14px; color: #F5F7FA; }
.mj-carte small { color: #8C98AA; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.mj-scene { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 14px; align-items: start; }
.mj-scene.seule { grid-template-columns: 1fr; }
@media (max-width: 900px) { .mj-scene { grid-template-columns: 1fr; } }
.mj-panneau { padding: 16px; border-radius: 18px; background: linear-gradient(180deg, #111925, #0C121C); border: 1px solid rgba(255,255,255,.08); min-width: 0; }
.mj-panneau h3, .mj-semaine-tete h3 { margin: 0 0 10px; font-size: 12px; font-weight: 800; letter-spacing: .14em; color: #8C98AA; text-transform: uppercase; }
.mj-taches { display: grid; gap: 8px; }
.mj-tache {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 11px 13px; border-radius: 14px; background: rgba(255,255,255,.035); border: 1px solid rgba(255,255,255,.08);
}
.mj-tache.t-rouge { border-color: rgba(255,90,99,.35); background: linear-gradient(90deg, rgba(255,90,99,.08), rgba(255,255,255,.02) 70%); }
.mj-tache.t-orange { border-color: rgba(247,169,40,.3); }
.mj-tache.t-vert { border-color: rgba(36,217,129,.3); }
.mj-tache.t-cyan { border-color: rgba(18,217,255,.3); background: linear-gradient(90deg, rgba(18,217,255,.06), rgba(255,255,255,.02) 70%); }
.mj-h { min-width: 46px; font-weight: 700; color: #F2B940; }
.mj-tache.t-rouge .mj-h { color: #FF5A63; }
.mj-tache.t-orange .mj-h { color: #F7A928; }
.mj-tache.t-vert .mj-h { color: #24D981; }
.mj-tache-t { min-width: 0; }
.mj-tache-t b { display: block; font-size: 13.5px; color: #F5F7FA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mj-tache-t small { display: block; color: #8C98AA; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mj-btn {
  height: 34px; padding: 0 14px; border-radius: 999px; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: 12.5px; font-weight: 700; color: #F5F7FA;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.14); transition: transform .12s ease, background .2s ease;
}
.mj-btn:hover { background: rgba(255,255,255,.1); }
.mj-btn:active { transform: scale(.97); }
.mj-btn.fort { color: #1A1204; background: linear-gradient(180deg, #FFD98A, #F2B940); border-color: transparent; box-shadow: 0 8px 20px -12px #F2B940; }
.mj-btn:focus-visible { outline: 2px solid #FFD27A; outline-offset: 2px; }
@media (max-width: 560px) {
  .mj-tache { grid-template-columns: auto minmax(0, 1fr); }
  .mj-tache .mj-btn { grid-column: 1 / -1; width: 100%; }
}
.mj-vide { margin: 0; color: #5E6A7C; font-size: 13px; padding: 10px 2px; }
.mj-note { margin: 10px 0 0; color: #8C98AA; font-size: 12px; }
.mj-charge { display: grid; gap: 8px; }
.mj-charge div { display: grid; grid-template-columns: 84px 1fr 28px; gap: 10px; align-items: center; font-size: 13px; color: #F5F7FA; }
.mj-charge i { display: block; height: 8px; border-radius: 8px; background: rgba(255,255,255,.07); overflow: hidden; }
.mj-charge i::after { content: ""; display: block; height: 100%; width: var(--w, 0%); border-radius: inherit; background: linear-gradient(90deg, #24D981, #F2B940); }
.mj-charge i.plein::after { background: linear-gradient(90deg, #F7A928, #FF5A63); }
.mj-charge .mono { text-align: right; }

.mj-semaine-tete { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.mj-semaine-tete h3 { margin: 0; }
.mj-semaine-tete .mj-note { margin: 0; }
.mj-podium { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
.mj-champion {
  display: grid; gap: 3px; padding: 14px 16px; border-radius: 16px;
  border: 1px solid rgba(242,185,64,.38); background: linear-gradient(160deg, rgba(242,185,64,.16), rgba(242,185,64,.02) 70%);
}
.mj-champion small { font-size: 10.5px; font-weight: 800; letter-spacing: .14em; color: #F2B940; }
.mj-champion b { font-size: 18px; color: #F5F7FA; }
.mj-champion span { color: #C9CFD9; font-size: 12.5px; }
.mj-details summary { cursor: pointer; color: #8C98AA; font-size: 12.5px; padding: 4px 0; }
.mj-details summary:hover { color: #F5F7FA; }
.mj-tables { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; margin-top: 8px; }
.mj-table-boite { overflow-x: auto; }
.mj-table { width: 100%; border-collapse: collapse; font-size: 13px; color: #F5F7FA; }
.mj-table th { text-align: left; font-size: 10.5px; letter-spacing: .1em; color: #5E6A7C; font-weight: 700; padding: 6px 8px; text-transform: uppercase; }
.mj-table td { padding: 8px; border-top: 1px solid rgba(255,255,255,.07); }
.mj-table td.mono { font-variant-numeric: tabular-nums; }
.mj-pill { display: inline-flex; height: 22px; align-items: center; padding: 0 9px; border-radius: 999px; font-size: 11px; font-weight: 700; }
.mj-pill.vert { color: #24D981; background: rgba(36,217,129,.12); border: 1px solid rgba(36,217,129,.35); }
.mj-pill.orange { color: #F7A928; background: rgba(247,169,40,.12); border: 1px solid rgba(247,169,40,.4); }
.mj-pill.gris { color: #8C98AA; background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.08); }

/* ═══════════════════════════════════════════════════════════════
   LA TÂCHE EN AVANT + LE DÉPÔT EXPRESS (monteur) — 04/10/2026

   Direction : « l'OS doit faire le travail à leur place » et
   « deposer la video dir lien bach ycompeh mn drive ». Une seule
   tâche prête en haut, et le dépôt d'un lien Drive juste au-dessus.
   Mêmes couleurs que « Ma Journée » : fond sombre, or en accent,
   rouge pour la reprise urgente, cyan pour le dépôt.
   ═══════════════════════════════════════════════════════════════ */
.mj-lead {
  position: relative; overflow: hidden; border-radius: 18px; padding: 16px 18px;
  background: linear-gradient(90deg, rgba(242,185,64,.10), rgba(255,255,255,.015) 75%);
  border: 1px solid rgba(242,185,64,.34);
}
.mj-lead::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: #F2B940; }
.mj-lead.t-rouge { background: linear-gradient(90deg, rgba(255,90,99,.10), rgba(255,255,255,.015) 75%); border-color: rgba(255,90,99,.38); }
.mj-lead.t-rouge::before { background: #FF5A63; }
.mj-lead.t-orange { background: linear-gradient(90deg, rgba(247,169,40,.10), rgba(255,255,255,.015) 75%); border-color: rgba(247,169,40,.34); }
.mj-lead.t-orange::before { background: #F7A928; }
.mj-lead-tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mj-lead-tag {
  font-family: var(--f-mono); font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: #F2B940; background: rgba(242,185,64,.12); border: 1px solid rgba(242,185,64,.4); border-radius: 999px; padding: 3px 10px;
}
.mj-lead.t-rouge .mj-lead-tag { color: #FF5A63; background: rgba(255,90,99,.1); border-color: rgba(255,90,99,.4); }
.mj-lead.t-orange .mj-lead-tag { color: #F7A928; background: rgba(247,169,40,.12); border-color: rgba(247,169,40,.4); }
.mj-lead-meta { font-size: 12px; color: #8C98AA; }
.mj-lead-titre { margin: 12px 0 0; font-size: 20px; font-weight: 800; letter-spacing: -.01em; color: #F5F7FA; }
.mj-lead-sous { margin: 3px 0 0; color: #C9CFD9; font-size: 13.5px; }
.mj-lead-brief { margin-top: 13px; padding: 11px 13px; border-radius: 12px; background: rgba(242,185,64,.08); border: 1px solid rgba(242,185,64,.22); }
.mj-lead.t-rouge .mj-lead-brief { background: rgba(255,90,99,.07); border-color: rgba(255,90,99,.22); }
.mj-lead-brief small { display: block; font-family: var(--f-mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: #F2B940; margin-bottom: 3px; }
.mj-lead.t-rouge .mj-lead-brief small { color: #FF5A63; }
.mj-lead-brief b { color: #F5F7FA; font-weight: 600; font-size: 14.5px; }
.mj-lead-btn { margin-top: 14px; }

.mj-depot {
  border-radius: 18px; padding: 15px 17px;
  background: linear-gradient(180deg, rgba(18,217,255,.05), rgba(255,255,255,.01));
  border: 1.5px dashed rgba(18,217,255,.34);
}
.mj-depot-tete { display: flex; align-items: center; gap: 9px; }
.mj-depot-tete b { font-size: 15px; font-weight: 800; color: #F5F7FA; }
.mj-depot-ic { color: #12D9FF; display: inline-flex; }
.mj-depot-np {
  margin-left: auto; font-family: var(--f-mono); font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: #12D9FF; border: 1px solid rgba(18,217,255,.4); border-radius: 6px; padding: 2px 7px;
}
.mj-depot-p { margin: 7px 0 12px; color: #C9CFD9; font-size: 13px; line-height: 1.5; }
.mjd-ligne { display: grid; gap: 8px; margin-bottom: 8px; }
.mjd-ligne.deux { grid-template-columns: 1fr 1fr; }
@media (max-width: 560px) { .mjd-ligne.deux { grid-template-columns: 1fr; } }
.mjd-in { width: 100%; }
.mjd-btn { margin-top: 4px; }

/* ═══════════════════════════════════════════════════════════════
   22/09 — proposition 3 : LA DISCUSSION DE LA VIDÉO (fiche du CERCLE)
   et proposition 5 : LE MESSAGE AU CLIENT après « Livré ✓ ».
   ═══════════════════════════════════════════════════════════════ */
.cr3-msg-puce {
  display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 10.5px; font-weight: 700; color: #12D9FF;
  background: rgba(18,217,255,.1); border: 1px solid rgba(18,217,255,.3);
}
.cr3-msg-puce:hover { background: rgba(18,217,255,.18); }
.cr-fil-boite { display: grid; gap: 10px; padding: 14px; border-radius: 16px; background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.08); }
/* Même piège que `.lec-corps` : sans ces deux lignes, la discussion
   d'un livrable se tasse en traits dès la dizaine de messages. */
.cr-fil { display: grid; gap: 10px; grid-auto-rows: max-content; align-content: start; max-height: 340px; overflow-y: auto; padding-right: 4px; }
.cr-fil-evt { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; text-align: center; font-size: 12px; color: #8C98AA; }
.cr-fil-evt small { color: #5E6A7C; }
.cr-fil-msg { display: grid; grid-template-columns: 30px minmax(0, 1fr); gap: 10px; }
.cr-fil-av { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center; font-size: 10.5px; font-weight: 800; color: #F5F7FA; background: #172131; border: 1px solid rgba(255,255,255,.1); }
.cr-fil-msg.moi .cr-fil-av { color: #1A1204; background: linear-gradient(180deg, #FFD98A, #F2B940); border: 0; }
.cr-fil-bulle { min-width: 0; padding: 8px 12px; border-radius: 4px 14px 14px 14px; background: rgba(255,255,255,.045); border: 1px solid rgba(255,255,255,.08); }
.cr-fil-msg.moi .cr-fil-bulle { background: rgba(242,185,64,.08); border-color: rgba(242,185,64,.25); }
.cr-fil-qui { display: flex; gap: 8px; align-items: baseline; font-size: 12px; color: #F5F7FA; }
.cr-fil-qui small { color: #5E6A7C; }
.cr-fil-bulle p { margin: 3px 0 0; font-size: 13.5px; line-height: 1.45; color: #F5F7FA; white-space: pre-wrap; overflow-wrap: anywhere; }
.cr-fil-mention { color: #12D9FF; font-weight: 700; }
.cr-fil-ecrire { display: flex; gap: 8px; }
.cr-fil-ecrire .input { flex: 1; min-width: 0; }
.cr-fil-puces { display: flex; gap: 6px; flex-wrap: wrap; }
.cr-fil-puce {
  height: 24px; padding: 0 9px; border-radius: 999px; cursor: pointer; font: inherit; font-size: 11.5px; font-weight: 600;
  color: #8C98AA; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
}
.cr-fil-puce:hover { color: #12D9FF; border-color: rgba(18,217,255,.35); }

.cr-wa { display: grid; gap: 8px; }
.cr-wa-l { font-size: 12px; font-weight: 600; color: #8C98AA; }
.cr-wa textarea { resize: vertical; min-height: 130px; }

/* ═══════════════════════════════════════════════════════════════
   LES VERSIONS ET LE RELAIS — 26 SEPTEMBRE 2026

   Direction : « ancien lien et nouveau lien », et « ya9der ykhdem
   monteur ou ya3ti l wahd akhor ykamal lih ».

   ⚠ Les grilles qui défilent portent `grid-auto-rows: max-content`
   et `align-content: start` — sans ça une grille à hauteur bornée
   partage sa hauteur entre ses rangées et les écrase à deux pixels
   (le bug du SPIDER, corrigé le 23/09).
   ═══════════════════════════════════════════════════════════════ */
.cr-vs-boite { display: grid; gap: 8px; padding: 13px 14px; border-radius: 14px;
  background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.08); }
.cr-vs { display: grid; gap: 8px; grid-auto-rows: max-content; align-content: start;
  max-height: 300px; overflow-y: auto; padding-right: 4px; }

.cr-v { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 10px 12px; border-radius: 12px; background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.07); }
.cr-v.courante { border-color: rgba(242,185,64,.4);
  background: linear-gradient(90deg, rgba(242,185,64,.08), rgba(255,255,255,.03) 70%); }
.cr-v-n { text-align: center; padding: 6px 0; border-radius: 8px; font-size: 13px; font-weight: 700;
  color: #FFE3A3; background: rgba(255,255,255,.05); }
.cr-v.courante .cr-v-n { background: linear-gradient(180deg, #FFD98A, #F2B940); color: #1A1204; }
.cr-v-t { min-width: 0; }
.cr-v-t b { display: block; font-size: 13.5px; }
.cr-v-t small { display: block; font-size: 11.5px; color: #5E6A7C; }
.cr-v-dem { margin: 5px 0 0; font-size: 12.5px; color: #C7D0DC; border-left: 2px solid #F2B940;
  padding-left: 9px; overflow-wrap: anywhere; }
.cr-v-a { font-size: 11.5px; font-weight: 600; color: #12D9FF; white-space: nowrap; }
.cr-v-a.muet { color: #5E6A7C; font-weight: 400; }

.cr-relais { display: grid; gap: 9px; padding: 13px 14px; border-radius: 14px;
  background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.08); }
.cr-rl-gens { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.cr-rl-main { display: flex; align-items: center; gap: 9px; min-width: 0; }
.cr-rl-main b { display: block; font-size: 13.5px; }
.cr-rl-main small { display: block; font-size: 11.5px; color: #5E6A7C; }
.cr-rl-rond { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font-size: 10.5px; font-weight: 800; color: #F5F7FA; background: #172131;
  border: 1px solid rgba(255,255,255,.1); flex: 0 0 auto; }
.cr-rl-rond.actif { color: #1A1204; background: linear-gradient(180deg, #FFD98A, #F2B940); border: 0; }
.cr-rl-rond.renfort { color: #0B1220; background: linear-gradient(180deg, #8FE9FF, #12D9FF); border: 0; }
.cr-rl-plus { color: #5E6A7C; font-size: 15px; }
.cr-rl-actions { display: flex; flex-wrap: wrap; gap: 8px; }

.cr-donner-p.choisi { border-color: rgba(242,185,64,.5);
  background: linear-gradient(90deg, rgba(242,185,64,.1), rgba(255,255,255,.03) 70%); }

.cr-acte { border-radius: 12px; padding: 11px 13px; border: 1px solid rgba(155,140,255,.28);
  background: rgba(155,140,255,.06); display: grid; gap: 7px; }
.cr-acte-aide { border-color: rgba(18,217,255,.28); background: rgba(18,217,255,.06); }
.cr-acte-tete { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline;
  justify-content: space-between; }
.cr-acte-tete b { font-size: 13px; color: #CFC6FF; }
.cr-acte-aide .cr-acte-tete b { color: #9BE9FF; }
.cr-acte-tete small { font-size: 11px; color: #5E6A7C; }
.cr-acte-corps { display: grid; gap: 4px; }
.cr-acte-corps p { margin: 0; font-size: 13px; color: #E8EDF4; overflow-wrap: anywhere; }
.cr-acte-cle { color: #8C98AA; font-weight: 600; margin-right: 5px; }

/* ═══════════════════════════════════════════════════════════════
   LA FICHE D'UNE PERSONNE — 26 SEPTEMBRE 2026

   Direction : « suivi avec chaque personne, lkhedma dialo ou yban
   lina l avancement ». Même langage que « Ma journée » (.mj-*) :
   les mêmes cartes, les mêmes tons, pour qu'on ne réapprenne rien.
   ═══════════════════════════════════════════════════════════════ */
.pf { display: grid; gap: 18px; }
.pf-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.pf-av { width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center;
  font-size: 17px; font-weight: 800; color: #1A1204; flex: 0 0 auto;
  background: linear-gradient(180deg, #FFD98A, #F2B940); }
.pf-qui { flex: 1; min-width: 200px; }
.pf-qui h1 { margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -.02em; }
.pf-qui p { margin: 2px 0 0; font-size: 13.5px; color: #8C98AA; text-transform: capitalize; }
.pf-sorti { display: inline-block; margin-top: 6px; font-size: 11.5px; padding: 3px 9px; border-radius: 999px;
  color: #FF5C7A; background: rgba(255,92,122,.1); border: 1px solid rgba(255,92,122,.3); }
.pf-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.pf-cartes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 900px) { .pf-cartes { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.pf-carte { display: grid; gap: 1px; padding: 14px 16px; border-radius: 14px; border-top: 2px solid var(--c, #8C98AA);
  background: rgba(255,255,255,.025); border-right: 1px solid rgba(255,255,255,.07);
  border-bottom: 1px solid rgba(255,255,255,.07); border-left: 1px solid rgba(255,255,255,.07); }
.pf-carte.t-or { --c: #F2B940; } .pf-carte.t-rouge { --c: #FF5C7A; } .pf-carte.t-vert { --c: #3ED598; }
.pf-carte.t-cyan { --c: #12D9FF; } .pf-carte.t-violet { --c: #9B8CFF; } .pf-carte.t-gris { --c: #8C98AA; }
.pf-carte.t-zero { --c: rgba(255,255,255,.12); }
.pf-n { font-size: 28px; font-weight: 700; line-height: 1; color: var(--c); font-variant-numeric: tabular-nums; }
.pf-carte.t-zero .pf-n { color: #5E6A7C; }
.pf-l { font-size: 13.5px; font-weight: 600; margin-top: 5px; }
.pf-carte small { font-size: 12px; color: #5E6A7C; }

.pf-semaine { margin: -6px 0 0; font-size: 13.5px; color: #8C98AA; }

.pf-bloc { display: grid; gap: 9px; }
.pf-bloc h3 { margin: 0; font-size: 15px; font-weight: 700; }
/* ⚠ Grille qui peut s'allonger : `grid-auto-rows` obligatoire (bug du 23/09). */
.pf-liste { display: grid; gap: 8px; grid-auto-rows: max-content; align-content: start; }
.pf-ligne { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: center;
  width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer;
  padding: 11px 13px; border-radius: 12px; background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.07); border-left: 3px solid rgba(255,255,255,.12);
  transition: border-color .16s, background .16s; }
.pf-ligne:hover { background: rgba(255,255,255,.05); border-left-color: #F2B940; }
.pf-ligne.t-rouge { border-left-color: #FF5C7A; background: rgba(255,92,122,.05); }
.pf-ligne.t-vert { border-left-color: #3ED598; }
.pf-ligne.t-cyan { border-left-color: #12D9FF; }
.pf-ligne-t { min-width: 0; }
.pf-ligne-t b { display: block; font-size: 14px; }
.pf-ligne-t small { display: block; font-size: 12.5px; color: #8C98AA; overflow-wrap: anywhere; }
.pf-etiq { font-size: 11px; font-weight: 600; white-space: nowrap; padding: 3px 9px; border-radius: 999px;
  color: #8C98AA; background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1); }
.pf-etiq.t-rouge { color: #FF5C7A; border-color: rgba(255,92,122,.35); background: rgba(255,92,122,.1); }
.pf-etiq.t-vert { color: #3ED598; border-color: rgba(62,213,152,.35); background: rgba(62,213,152,.1); }
.pf-etiq.t-cyan { color: #12D9FF; border-color: rgba(18,217,255,.35); background: rgba(18,217,255,.1); }
.pf-vide { margin: 0; font-size: 13px; color: #5E6A7C; }

/* ═══════════════════════════════════════════════════════════════
   LA PREUVE DE LIVRAISON — 26 SEPTEMBRE 2026
   144 vidéos sur 148 n'avaient aucune trace d'envoi. Elle se lit ici.
   ═══════════════════════════════════════════════════════════════ */
.cr-lv-boite { display: grid; gap: 8px; padding: 13px 14px; border-radius: 14px;
  background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.08); }
.cr-lv { display: grid; gap: 8px; grid-auto-rows: max-content; align-content: start;
  max-height: 300px; overflow-y: auto; padding-right: 4px; }
.cr-lv-envoi { display: grid; gap: 4px; padding: 10px 12px; border-radius: 12px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.07);
  border-left: 3px solid #12D9FF; }
.cr-lv-envoi.repondu { border-left-color: #3ED598; }
.cr-lv-tete { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; justify-content: space-between; }
.cr-lv-tete b { font-size: 13.5px; }
.cr-lv-canal { font-size: 11px; color: #12D9FF; background: rgba(18,217,255,.1);
  border: 1px solid rgba(18,217,255,.3); border-radius: 999px; padding: 2px 9px; }
.cr-lv-envoi small { font-size: 12px; color: #5E6A7C; }
.cr-lv-rep { margin: 4px 0 0; font-size: 13px; overflow-wrap: anywhere; }
.cr-lv-rep.ok { color: #3ED598; }
.cr-lv-rep.modif { color: #FF5C7A; }
.cr-lv-rep.attente { color: #8C98AA; }
.cr-lv-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }

/* ═══════════════════════════════════════════════════════════════
   TA JOURNÉE — LA PORTE D'ENTRÉE — 27 SEPTEMBRE 2026
   Le même texte que le message de 9 h. Une carte, pas un tableau :
   on la lit debout, le téléphone à la main.
   ═══════════════════════════════════════════════════════════════ */
.tj-carte {
  display: grid; gap: 14px;
  padding: 18px 18px 16px;
  border-radius: 16px;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.09);
}
.tj-tete { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.tj-salut { font-size: 1.18rem; font-weight: 700; letter-spacing: -.01em; }
.tj-lignes { display: grid; gap: 7px; grid-auto-rows: max-content; align-content: start; }
.tj-titre {
  font-size: .68rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  opacity: .62; margin-top: 6px;
}
.tj-titre:first-child { margin-top: 0; }
.tj-ligne { display: flex; gap: 10px; align-items: flex-start; }
.tj-puce {
  flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; opacity: .5; margin-top: .55em;
}
.tj-texte { min-width: 0; overflow-wrap: anywhere; line-height: 1.45; }
.tj-rien { opacity: .7; margin: 0; }
.tj-pied { font-size: .78rem; opacity: .48; margin: 2px 0 0; }
@media (max-width: 560px) {
  .tj-carte { padding: 15px 14px 13px; border-radius: 13px; }
  .tj-tete .btn { width: 100%; }
}

/* Le montant, dans la fiche de la vidéo — 27/09/2026 */
.cr-argent { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
.cr-argent .field { display: grid; gap: 5px; min-width: 150px; flex: 1 1 150px; }
.cr-argent .field > span { font-size: .74rem; letter-spacing: .08em; text-transform: uppercase; opacity: .6; }
.cr-argent .cr-check { display: flex; gap: 7px; align-items: center; padding-bottom: 9px; }

/* Cacher un champ que `.field` force en display:grid — 27/09/2026.
   `hidden` ne suffit pas : une règle de classe bat celle du navigateur. */
.cr-cache { display: none !important; }
