/* =====================================================================
 * MPermis, systeme visuel 2026.
 *
 * Parti pris : un REGISTRE, pas un tableau de bord. Le domaine est un
 * grand livre ou rien ne s'efface et ou une ecriture annulee reste
 * visible, barree. L'ecran dit la meme chose que le modele.
 *
 * Trois consequences tenues partout :
 *  - la reglure remplace l'ombre. Aucun halo, aucune ombre portee : ce
 *    sont des filets d'un pixel qui separent, comme sur un registre.
 *  - les colonnes de faits (date, code, montant) sont en chasse fixe et
 *    en chiffres tabulaires. Ce n'est pas un effet : une colonne mal
 *    alignee doit SE VOIR.
 *  - aucune police distante. La feuille du legacy appelait Google a
 *    chaque page, ce qui est une requete de trop pour un outil qui
 *    manipule des donnees d'eleves mineurs.
 * ===================================================================== */

:root {
  /* --- encres et papier. Navy et teal fixes par Anthony. --- */
  --encre: #141d29;
  --encre-douce: #4a5765;
  /* Recalibree 2026-08-03 (fondations typo/espacement) : #7c8896 ne passait
     que 3.33:1 / 3.61:1 sur --papier / --papier-blanc, sous le seuil AA texte
     (4.5:1), alors que 36 sites l'utilisent comme couleur de texte (labels,
     legendes, meta). Assombrie a teinte constante (meme famille bleu-slate,
     aucun changement d'identite) : 5.32:1 / 5.76:1, mesures par
     scripts/contraste-wcag.mjs. */
  --encre-pale: #5c6773;
  --marine: #1b2a4b;
  --marine-fonce: #152340;
  --teal: #116e77;
  --teal-clair: #17838e;
  --papier: #f4f6f8;
  --papier-blanc: #ffffff;
  --papier-creuse: #f4f6f8;

  /* --- reglures. Un seul filet, trois intensites. --- */
  --filet: #dce1e7;
  --filet-fort: #c3cbd4;
  --filet-tenu: #e6eaef;

  /* --- etats. Deux encres, pas davantage : du et solde. --- */
  --du: #8a6410;
  --du-fond: #fbf3e0;
  --solde: #3a6446;
  --solde-fond: #eaf2ec;
  --refus: #8f332c;
  --refus-fond: #faecea;

  /* --- rythme. Echelle de 4, sans valeur intermediaire.
       En rem (base navigateur, 16px par defaut) et non en px : un
       agrandissement de texte cote navigateur doit aussi elargir les
       marges et les espacements, pas seulement les lettres. --- */
  --e1: 0.25rem;
  --e2: 0.5rem;
  --e3: 0.75rem;
  --e4: 1rem;
  --e6: 1.5rem;
  --e8: 2rem;
  --e12: 3rem;

  /* Bordures fines et traits : restent en pixels a dessein (un filet de 1px
     doit rester 1px, cf. revue design 2026-08-03). Non concerne par la
     conversion en unites relatives. */
  --arrondi: 3px;
  --arrondi-large: 3px;
  --largeur: 1180px;
  /* Largeur du rail de navigation. Declaree ici parce que le calendrier a
     besoin de la connaitre pour sortir du gabarit de lecture. */
  --rail: 206px;

  /* --- caracteres. Deux roles, deux piles, aucune distante. --- */
  --texte: system-ui, -apple-system, 'Segoe UI', sans-serif;
  --titre: 'Avenir Next', Avenir, 'Segoe UI', system-ui, sans-serif;
  --faits: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* --- echelle typographique. Cinq tailles, cinq roles, plus onze
       (jusqu'a 22 valeurs mesurees dont 10.5px/11px illisibles au comptoir
       ou au soleil). En rem : suit l'agrandissement de texte du
       navigateur, contrairement a une taille en px qui reste figee.
       Plancher a 0.75rem (12px) : sous ce seuil le texte n'est plus tenable
       pour une secretaire debout ou un moniteur en plein soleil. --- */
  --tx-legale: 0.75rem; /* 12px, plancher. Mentions legales, libelles de colonnes, tags. */
  --tx-annotation: 0.8125rem; /* 13px. Annotations, meta, legendes de champ. */
  --tx-corps: 0.9375rem; /* 15px. Texte courant, valeur par defaut du corps. */
  --tx-section: 1.125rem; /* 18px. Titres de section, valeurs mises en avant. */
  --tx-ecran: 1.75rem; /* 28px. Titres d'ecran (h1), chiffres cles (KPI, solde). */

  /* --- mouvement. UNE courbe pour tout : c'est ce qui fait la
       coherence. Deux durees, pas trois. --- */
  --vite: 120ms;
  --pose: 240ms;
  --courbe: cubic-bezier(0.2, 0.6, 0.2, 1);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--papier);
  color: var(--encre);
  font-family: var(--texte);
  font-size: var(--tx-corps);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--teal);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: border-color var(--vite) var(--courbe);
}

a:hover {
  border-bottom-color: var(--teal);
}

/* Contour net, jamais un halo diffus. */
:focus-visible {
  outline: 2px solid var(--teal-clair);
  outline-offset: 2px;
  border-radius: 2px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.skip-link:focus {
  position: fixed;
  top: var(--e2);
  left: var(--e2);
  width: auto;
  height: auto;
  clip: auto;
  padding: var(--e2) var(--e3);
  background: var(--papier-blanc);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  z-index: 100;
}

/* =====================================================================
 * Bandeau et rail de gauche
 *
 * La barre du haut ne porte plus la navigation : elle garde la marque et
 * le profil. Toutes les destinations vivent dans le rail, visibles sans
 * ouvrir un menu. Douze menus deroulants du legacy sont devenus six
 * groupes, dans l'ordre de lecture d'une journee de secretariat.
 * ===================================================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--marine);
  border-bottom: 1px solid var(--marine-fonce);
}

.topbar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e4);
  min-height: 56px;
  padding: 0 var(--e6);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  color: #fff;
  border: 0;
  font-family: var(--titre);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.brand:hover {
  border: 0;
}

.brand-text {
  font-size: var(--tx-corps);
}

.user-zone {
  display: flex;
  align-items: center;
  gap: var(--e4);
}

.who {
  color: #cbd4e4;
  font-size: var(--tx-annotation);
}

.logout {
  padding: 0;
  background: none;
  border: 0;
  color: #98a5bd;
  font: inherit;
  font-size: var(--tx-annotation);
  cursor: pointer;
  transition: color var(--vite) var(--courbe);
}

.logout:hover {
  color: #fff;
}

.scene {
  display: grid;
  grid-template-columns: var(--rail) 1fr;
  align-items: start;
}

.rail {
  position: sticky;
  top: 56px;
  align-self: start;
  z-index: 20;
  width: var(--rail);
  height: calc(100vh - 56px);
  overflow-y: auto;
  padding: var(--e2) 0 var(--e6);
  background: var(--papier-creuse);
  border-right: 1px solid var(--filet);
}

.rail-groupe {
  padding: var(--e3) var(--e4) var(--e1);
}

.rail-eyebrow {
  font-family: var(--faits);
  font-size: var(--tx-legale);
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--encre-pale);
}

.rail a {
  display: block;
  padding: var(--e2) var(--e4);
  border: 0;
  border-left: 2px solid transparent;
  color: var(--encre-douce);
  font-size: var(--tx-annotation);
  transition:
    background var(--vite) var(--courbe),
    border-color var(--vite) var(--courbe),
    color var(--vite) var(--courbe);
}

.rail a:hover {
  background: var(--papier-blanc);
  border-left-color: var(--filet-fort);
  color: var(--encre);
}

.rail a.on {
  background: var(--papier-blanc);
  border-left-color: var(--teal);
  color: var(--encre);
  font-weight: 600;
}

.rail a:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

/* Sous 900 px, le rail passe au-dessus du contenu : un poste etroit ou
   une tablette garde toutes les destinations. */
@media (max-width: 900px) {
  .scene {
    grid-template-columns: 1fr;
  }

  .rail {
    position: static;
    width: auto;
    height: auto;
    display: flex;
    flex-wrap: wrap;
    /* 2px : sous le premier cran du rythme (--e1, 4px), au meme titre
       qu'un filet de bordure. Ce n'est plus de l'espacement de mise en
       page, c'est un espacement de trait, laisse en px a dessein (comme
       les autres occurrences sub-e1 de cette feuille : puces et badges
       compacts). */
    gap: 2px;
    padding: var(--e2) var(--e3);
    border-right: 0;
    border-bottom: 1px solid var(--filet);
  }

  .rail-groupe {
    flex: 0 0 100%;
    padding: var(--e2) var(--e1) 2px;
  }

  .rail a {
    padding: var(--e1) var(--e3);
    border-left: 0;
    border-bottom: 2px solid transparent;
  }

  .rail a.on {
    border-left: 0;
    border-bottom-color: var(--teal);
  }
}

/* =====================================================================
 * Page
 * ===================================================================== */

.container {
  /* Marge laterale a ZERO : sur un element de grille, `margin: auto`
     empeche l'etirement et comprime la page a la largeur de son contenu.
     Le legacy s'y etait fait prendre, l'ecran de connexion paraissait en
     version mobile sur un poste large. */
  min-width: 0;
  max-width: var(--largeur);
  margin: var(--e8) 0 var(--e12);
  padding: 0 var(--e6);
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--e6);
  flex-wrap: wrap;
  margin-bottom: var(--e6);
}

.eyebrow {
  margin: 0 0 var(--e1);
  color: var(--teal);
  font-size: var(--tx-legale);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

h1 {
  margin: 0;
  font-family: var(--titre);
  font-size: var(--tx-ecran);
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.15;
  color: var(--encre);
}

h2 {
  display: flex;
  align-items: baseline;
  gap: var(--e3);
  margin: var(--e8) 0 var(--e3);
  padding-bottom: var(--e2);
  border-bottom: 1px solid var(--filet);
  font-size: var(--tx-annotation);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--encre-douce);
}

h3 {
  margin: 0 0 var(--e3);
  font-family: var(--titre);
  font-size: var(--tx-corps);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--encre);
}

.h2-note {
  font-family: var(--faits);
  font-size: var(--tx-legale);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--encre-pale);
}

.sub {
  margin: var(--e1) 0 0;
  color: var(--encre-douce);
  font-size: var(--tx-corps);
}

.caption {
  display: block;
  color: var(--encre-pale);
  font-size: var(--tx-legale);
}

/* =====================================================================
 * Cartes et grilles
 * ===================================================================== */

.card {
  background: var(--papier-blanc);
  border: 1px solid var(--filet);
  border-radius: var(--arrondi-large);
  padding: var(--e6);
}

.card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--e3);
  margin-bottom: var(--e4);
}

.card-head h3 {
  margin: 0;
}

.grid {
  display: grid;
  gap: var(--e3);
}

.kpis {
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}

.split {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--e6);
  align-items: start;
  margin-top: var(--e6);
}

.grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e4);
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
}

@media (max-width: 860px) {
  .split,
  .grid-2 {
    grid-template-columns: 1fr;
  }
}

/* Cartouche de chiffre. Un filet a gauche porte l'etat : c'est la meme
   grammaire que la reglure de marge du registre. */
.kpi {
  display: block;
  position: relative;
  padding: var(--e4) var(--e4) var(--e4) var(--e6);
  background: var(--papier-blanc);
  border: 1px solid var(--filet);
  border-radius: var(--arrondi-large);
  transition:
    border-color var(--vite) var(--courbe),
    background var(--vite) var(--courbe);
}

.kpi::before {
  content: '';
  position: absolute;
  left: 0;
  top: var(--e3);
  bottom: var(--e3);
  width: 2px;
  border-radius: 2px;
  background: var(--filet-fort);
}

a.kpi {
  border-bottom: 1px solid var(--filet);
  cursor: pointer;
}

a.kpi:hover {
  border-color: var(--filet-fort);
  background: var(--papier-creuse);
}

.kpi .num {
  font-family: var(--faits);
  font-variant-numeric: tabular-nums;
  font-size: var(--tx-ecran);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.1;
  color: var(--encre);
}

.kpi .lab {
  margin-top: var(--e2);
  color: var(--encre-douce);
  font-size: var(--tx-annotation);
}

.kpi.ok::before {
  background: var(--solde);
}
.kpi.ok .num {
  color: var(--solde);
}
.kpi.warn::before {
  background: var(--du);
}
.kpi.warn .num {
  color: var(--du);
}
.kpi.info::before {
  background: var(--teal);
}

/* =====================================================================
 * Le registre. Coeur du systeme.
 * ===================================================================== */

.table-wrapper {
  position: relative;
  overflow-x: auto;
  border: 1px solid var(--filet);
  border-radius: var(--arrondi-large);
  background: var(--papier-blanc);
}

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

th {
  padding: var(--e3) var(--e4);
  font-family: var(--faits);
  text-align: left;
  background: var(--papier-creuse);
  border-bottom: 1px solid var(--filet);
  color: var(--encre-douce);
  font-size: var(--tx-legale);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}

td {
  padding: var(--e3) var(--e4);
  border-bottom: 1px solid var(--filet-tenu);
  font-size: var(--tx-corps);
  vertical-align: baseline;
}

tbody tr:last-child td {
  border-bottom: 0;
}

tbody tr {
  transition: background var(--vite) var(--courbe);
}

tbody tr:hover {
  background: var(--papier-creuse);
}

/* Les faits sont en chasse fixe : une colonne mal alignee se voit. */
td.code,
td.right,
th.right {
  font-family: var(--faits);
  font-variant-numeric: tabular-nums;
}

td.code {
  color: var(--encre-pale);
  font-size: var(--tx-annotation);
  white-space: nowrap;
}

td.right,
th.right {
  text-align: right;
}

td.center,
th.center {
  text-align: center;
}

.t-name {
  font-weight: 500;
}

.cell-empty,
.cell-muted {
  color: var(--encre-pale);
  font-size: var(--tx-annotation);
}

/* Colonnes de CHIFFRES : meme famille, meme chasse, pour que les montants et
   les numeros s'alignent verticalement d'une ligne a l'autre. Sans
   `tabular-nums`, un 1 est plus etroit qu'un 8 et la colonne ondule. */
.num-du,
.num-tel {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.num-du {
  font-weight: 600;
  color: var(--du);
}

/* Le telephone reste un lien (composer d'un clic depuis un mobile) sans en
   avoir l'air : souligne au survol seulement, pour ne pas transformer la
   liste en pelote de liens bleus. */
.num-tel a {
  color: inherit;
  text-decoration: none;
}

.num-tel a:hover,
.num-tel a:focus-visible {
  text-decoration: underline;
  color: var(--teal);
}

.th-tri {
  color: inherit;
  text-decoration: none;
}

.th-tri:hover,
.th-tri:focus-visible {
  color: var(--teal);
}

tfoot td {
  padding-top: var(--e4);
  padding-bottom: var(--e4);
  border-top: 2px solid var(--filet-fort);
  background: var(--papier-creuse);
  font-weight: 600;
}

/*
 * Reglure de marge : le filet vertical qui longe la colonne des soldes.
 * Revue motion 2026-08-03 : ce filet se tracait auparavant de haut en bas a
 * l'arrivee sur la page (520ms, donc deja hors doctrine des 300ms). Corrige
 * en filet statique. Un geste qui rejoue a CHAQUE ouverture de fiche eleve
 * (l'ecran le plus consulte du comptoir) ne confirme aucune action, ne
 * montre la provenance de rien, et ne rend aucune attente supportable : ce
 * sont les trois seuls emplois legitimes du mouvement ici. La couleur du
 * filet (du/solde) porte l'information vraie ; l'animer n'ajoutait rien,
 * seulement du bruit revu a chaque interruption du comptoir.
 */
.registre {
  position: relative;
}

.registre::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 3px;
  background: var(--filet-fort);
}

.registre.est-du::after {
  background: var(--du);
}

.registre.est-solde::after {
  background: var(--solde);
}

/* Une ligne annulee reste lisible et barree : elle a existe. */
tr.annulee td {
  color: var(--encre-pale);
}

tr.annulee .t-name {
  text-decoration: line-through;
  text-decoration-color: var(--refus);
  text-decoration-thickness: 1px;
}

/* Revue motion 2026-08-03 : l'ancienne arrivee en cascade des lignes de
   tableau (jusqu'a 440ms cumules sur les premieres lignes) rejouait sur
   CHAQUE tableau de l'application a CHAQUE navigation, sans rien confirmer
   ni rien montrer : une pure decoration de chargement, precisement ce que
   la doctrine mouvement interdit. Supprimee. Le keyframe `poser` reste
   utilise ailleurs (bandeau `.flash`, ou une brieve apparition confirme
   qu'un message vient d'arriver : cf. plus bas). */

@keyframes poser {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* =====================================================================
 * Fiche eleve
 * ===================================================================== */

.detail-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--e6);
  flex-wrap: wrap;
  margin-bottom: var(--e6);
  padding-bottom: var(--e4);
  border-bottom: 1px solid var(--filet);
}

.detail-meta {
  display: flex;
  gap: var(--e3);
  flex-wrap: wrap;
  margin-top: var(--e1);
  font-family: var(--faits);
  font-size: var(--tx-annotation);
  color: var(--encre-pale);
}

.solde-box {
  min-width: 190px;
  padding: var(--e3) var(--e4);
  text-align: right;
  border-right: 3px solid var(--filet-fort);
}

.solde-box.est-du {
  border-right-color: var(--du);
}

.solde-box.est-solde {
  border-right-color: var(--solde);
}

.solde-box .lab {
  color: var(--encre-pale);
  font-size: var(--tx-legale);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.big-solde {
  margin-top: var(--e1);
  font-family: var(--faits);
  font-variant-numeric: tabular-nums;
  font-size: var(--tx-ecran);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1;
}

.solde-box.est-du .big-solde {
  color: var(--du);
}

.solde-box.est-solde .big-solde {
  color: var(--solde);
}

/* =====================================================================
 * Formulaires. Champs contraints, listes plutot que texte libre.
 * ===================================================================== */

.field {
  margin-bottom: var(--e4);
}

label {
  display: block;
  margin-bottom: var(--e1);
  color: var(--encre-douce);
  font-size: var(--tx-annotation);
  font-weight: 600;
}

input,
select,
textarea {
  width: 100%;
  min-height: 40px;
  padding: var(--e2) var(--e3);
  background: var(--papier-blanc);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  color: var(--encre);
  font-family: inherit;
  font-size: var(--tx-corps);
  transition: border-color var(--vite) var(--courbe);
}

input[inputmode='decimal'],
input[inputmode='tel'],
input[type='date'],
input[type='month'] {
  font-family: var(--faits);
  font-variant-numeric: tabular-nums;
}

input:hover,
select:hover,
textarea:hover {
  border-color: var(--encre-pale);
}

/* Le filet s'epaissit, rien ne rayonne. */
input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--teal);
  box-shadow: inset 0 0 0 1px var(--teal);
}

input::placeholder,
textarea::placeholder {
  color: var(--encre-pale);
}

select {
  appearance: none;
  padding-right: var(--e8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%237b8599' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--e3) center;
}

input[type='checkbox'] {
  width: 17px;
  min-height: 0;
  height: 17px;
  margin: 0;
  accent-color: var(--teal);
}

.hint {
  display: block;
  margin-top: var(--e1);
  color: var(--encre-pale);
  font-size: var(--tx-legale);
  line-height: 1.4;
}

.req {
  margin-left: 2px;
  color: var(--refus);
}

.fieldset {
  margin: 0 0 var(--e6);
  padding: var(--e4) var(--e4) 0;
  border: 1px solid var(--filet);
  border-radius: var(--arrondi-large);
}

.fieldset legend {
  padding: 0 var(--e2);
  color: var(--teal);
  font-size: var(--tx-legale);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.check-row {
  display: flex;
  align-items: center;
  gap: var(--e2);
  margin: var(--e3) 0 var(--e4);
  font-size: var(--tx-corps);
  font-weight: 400;
  cursor: pointer;
}

.form-narrow {
  max-width: 660px;
}

/* =====================================================================
 * Actions
 * ===================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: var(--e2) var(--e4);
  background: var(--marine);
  border: 1px solid var(--marine);
  border-radius: var(--arrondi);
  color: #fff;
  font: inherit;
  font-size: var(--tx-corps);
  font-weight: 500;
  cursor: pointer;
  transition:
    background var(--vite) var(--courbe),
    border-color var(--vite) var(--courbe),
    transform var(--vite) var(--courbe);
}

.btn:hover {
  background: var(--marine-fonce);
  border-color: var(--marine-fonce);
}

/* Enfoncement d'un pixel : le seul retour tactile, et il est honnete. */
.btn:active {
  transform: translateY(1px);
}

/* Revue design 2026-08-03 : un bouton desactive ("Rien a lancer", passe deja
   a jour, ou passe en cours d'envoi) n'avait auparavant AUCUN traitement
   visuel distinct. Statique, pas de mouvement : l'opacite et le curseur
   suffisent a dire qu'il n'y a rien a cliquer, et le libelle du bouton
   (jamais la seule couleur) porte deja l'etat en toutes lettres. */
.btn:disabled,
.btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

.btn:disabled:hover,
.btn[disabled]:hover {
  background: var(--marine);
  border-color: var(--marine);
}

.btn-teal {
  background: var(--teal);
  border-color: var(--teal);
}

.btn-teal:hover {
  background: #1a5059;
  border-color: #1a5059;
}

.btn-line {
  background: var(--papier-blanc);
  border-color: var(--filet-fort);
  color: var(--encre);
}

.btn-line:hover {
  background: var(--papier-creuse);
  border-color: var(--encre-pale);
}

.btn-block {
  width: 100%;
}

.btn-xs {
  min-height: 30px;
  padding: var(--e1) var(--e2);
  font-size: var(--tx-annotation);
}

a.btn {
  border-bottom-width: 1px;
}

a.btn:hover {
  border-bottom-color: inherit;
}

/* =====================================================================
 * Messages. Un filet a gauche, jamais un aplat criard.
 * ===================================================================== */

.flash {
  display: flex;
  gap: var(--e3);
  margin-bottom: var(--e6);
  padding: var(--e3) var(--e4);
  border: 1px solid var(--filet);
  border-left: 3px solid var(--filet-fort);
  border-radius: var(--arrondi);
  background: var(--papier-blanc);
  font-size: var(--tx-corps);
  animation: poser 260ms var(--courbe) both;
}

.flash p {
  margin: var(--e1) 0 0;
}

.flash ul {
  margin: var(--e2) 0 0;
  padding-left: var(--e4);
}

.flash.ok {
  background: var(--solde-fond);
  border-color: #bfe6d3;
  border-left-color: var(--solde);
  color: var(--solde);
}

.flash.warn {
  background: var(--du-fond);
  border-color: #ecd9a6;
  border-left-color: var(--du);
  color: var(--du);
}

.flash.bad {
  background: var(--refus-fond);
  border-color: #eab8b8;
  border-left-color: var(--refus);
  color: var(--refus);
}

.flash.info {
  background: var(--papier-creuse);
  border-left-color: var(--teal);
}

.empty-state {
  margin: 0;
  padding: var(--e6);
  border: 1px dashed var(--filet-fort);
  border-radius: var(--arrondi-large);
  color: var(--encre-douce);
  font-size: var(--tx-corps);
  text-align: center;
}

.pill {
  display: inline-block;
  padding: 1px var(--e2);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  font-size: var(--tx-legale);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--encre-douce);
  white-space: nowrap;
}

.pill.ok {
  border-color: #bfe6d3;
  background: var(--solde-fond);
  color: var(--solde);
}

.pill.info {
  border-color: #c3cddd;
  background: var(--papier-creuse);
  color: var(--teal);
}

.pill.neutre {
  color: var(--encre-pale);
}

.pill.warn {
  border-color: #ecd9ad;
  background: var(--du-fond);
  color: var(--du);
}

.pill.bad {
  border-color: #e8c4bf;
  background: var(--refus-fond);
  color: var(--refus);
}

/* =====================================================================
 * Planning reel (Klaxo) : la grille heures x jours, une par moniteur
 * ===================================================================== */

.creneau-reel {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--e2) 0;
  font-size: var(--tx-annotation);
}

/* Un filet fin separe deux creneaux d'une meme journee. Pas d'ombre : la
   lecture se fait par la ligne, pas par le relief. */
.creneau-reel + .creneau-reel {
  border-top: 1px solid var(--filet);
}

.creneau-reel .hint {
  margin-top: 0;
}

/* Un creneau cliquable reste un bloc, pas un lien souligne : c'est la case
   entiere qui s'ouvre, et le soulignement hacherait quatre lignes de texte. */
a.creneau-reel {
  color: inherit;
  text-decoration: none;
  padding-left: var(--e2);
  padding-right: var(--e2);
  border-left: 2px solid var(--teal);
}

a.creneau-reel:hover,
a.creneau-reel:focus-visible {
  background: var(--papier-creuse);
}

.grille-planning {
  table-layout: fixed;
}

/* Colonne des heures : etroite et fixe, pour que les sept jours se partagent
   le reste a egalite quelle que soit la longueur des noms d'eleves. */
.grille-planning th:first-child {
  width: 62px;
  text-align: right;
  vertical-align: top;
  padding-top: var(--e3);
  color: var(--encre-pale);
  font-weight: 500;
}

.grille-planning thead th .hint {
  display: block;
  margin-top: 0;
}

.grille-planning td {
  vertical-align: top;
  padding: 0;
  height: 44px;
}

/* Une heure deja couverte par le creneau du dessus. Fond a peine marque : elle
   doit se lire « prise » sans attirer l'oeil autant qu'un vrai creneau. */
.grille-planning .case-suite {
  background: var(--papier-creuse);
}

.grille-planning .cell-muted {
  display: block;
  padding: var(--e2);
  font-size: var(--tx-legale);
  color: var(--encre-pale);
}

/* Fiche d'un creneau : une information par ligne, etiquette a gauche. La bande
   de metadonnees (.detail-meta) mettrait tout sur une seule ligne, ou libelles
   et valeurs se confondraient des que le nom de l'eleve s'allonge. */
.fiche-creneau {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: var(--e2) var(--e4);
  margin: var(--e3) 0 0;
}

.fiche-creneau dt {
  color: var(--encre-pale);
  font-size: var(--tx-annotation);
}

.fiche-creneau dd {
  margin: 0;
}

@media (max-width: 860px) {
  .fiche-creneau {
    grid-template-columns: 1fr;
    gap: var(--e1);
  }

  .fiche-creneau dd {
    margin-bottom: var(--e3);
  }
}

/* Le « + » d'une case libre : discret au repos, franc au survol. Toute la case
   est cliquable, pour viser sans precision a la souris comme au doigt. */
.creneau-libre {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  color: var(--encre-pale);
  font-size: var(--tx-corps);
  text-decoration: none;
}

.creneau-libre:hover,
.creneau-libre:focus-visible {
  background: var(--papier-creuse);
  color: var(--teal);
}

/* =====================================================================
 * Ecran de connexion
 * ===================================================================== */

.connexion {
  max-width: 380px;
  margin: 12vh auto 0;
}

.connexion .marque {
  margin-bottom: var(--e6);
  padding-bottom: var(--e4);
  border-bottom: 2px solid var(--teal);
  text-align: left;
}

.connexion .marque h1 {
  font-size: var(--tx-ecran);
  letter-spacing: -0.03em;
}

/* =====================================================================
 * Mouvement desactive. Non negociable : ces animations ne portent
 * aucune information, elles n'ont donc aucune raison d'etre imposees.
 * ===================================================================== */


/* Onglets de filtre (effectif actif / archive). Bordure basse, jamais d'ombre :
   le registre visuel reste celui des tableaux, pas celui des boutons. */
.onglets {
  display: flex;
  gap: var(--e6);
  border-bottom: 1px solid var(--filet);
  margin-bottom: var(--e6);
}
.onglet {
  padding: var(--e2) 0;
  color: var(--encre-douce);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.onglet:hover {
  color: var(--encre);
}
.onglet.actif {
  color: var(--encre);
  border-bottom-color: var(--teal);
  font-weight: 600;
}


/* Ligne de ventilation des sources sous chaque mois des Finances. Repliee par
   defaut (details natif), filet fin, jamais d'ombre. */
.rang-detail td {
  padding: 0;
  border-top: 0;
}
.rang-detail summary {
  cursor: pointer;
  color: var(--encre-douce);
  font-size: var(--tx-annotation);
  padding: var(--e1) var(--e3);
}
.rang-detail summary:hover {
  color: var(--encre);
}
.detail-sources {
  padding: var(--e1) var(--e3) var(--e3);
  border-top: 1px solid var(--filet-tenu);
  display: grid;
  gap: var(--e2);
}
.detail-source p {
  margin: var(--e1) 0;
}


/* Barre de filtres de la Caisse (modes de paiement). Pastilles a bordure fine,
   etat actif en teal, jamais d'ombre. */
.filtres {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
  margin: 0 0 var(--e6);
}
.filtre {
  padding: var(--e1) var(--e3);
  border: 1px solid var(--filet-fort);
  border-radius: 3px;
  color: var(--encre-douce);
  text-decoration: none;
  font-size: var(--tx-corps);
  font-variant-numeric: tabular-nums;
}
.filtre:hover {
  color: var(--encre);
  border-color: var(--encre-douce);
}
.filtre.actif {
  color: #ffffff;
  background: var(--teal);
  border-color: var(--teal);
}
.filtre.vide {
  color: var(--encre-pale);
}


/* Suggestions sous la barre de recherche : liste absolue sous le champ,
   bordure fine, jamais d'ombre. Le champ vit dans un .field positionne. */
.field {
  position: relative;
}
.suggestions {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  z-index: 20;
  background: var(--papier-blanc);
  border: 1px solid var(--filet-fort);
  border-radius: 3px;
  max-height: 20rem;
  overflow-y: auto;
}
.suggestions ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.suggestions a {
  display: flex;
  align-items: baseline;
  gap: var(--e2);
  padding: var(--e2) var(--e3);
  color: var(--encre);
  text-decoration: none;
  border-bottom: 1px solid var(--filet-tenu);
}
.suggestions li:last-child a {
  border-bottom: 0;
}
.suggestions a:hover,
.suggestions a:focus {
  background: var(--papier-creuse);
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
  }
}


/* =====================================================================
 * Calendrier du planning : vraie grille horaire, blocs positionnes
 *
 * Porte du planning des postes de l'ecole. Un bloc occupe SA duree, et
 * deux blocs qui se chevauchent se partagent la largeur de la colonne :
 * se recouvrir cacherait precisement ce qu'il faut voir. Reglure et
 * filets, aucune ombre : un agenda reste un registre.
 * ===================================================================== */

.cal-actions,
.cal-vues {
  margin: 0 0 var(--e3);
}

/* Le calendrier SORT du gabarit de lecture (1180 px). Une colonne de jour
   trop etroite se paie en noms d'eleves tronques, c'est-a-dire en creneau
   qu'on ne sait plus attribuer d'un coup d'oeil. Un gouttiere de var(--e6)
   est laissee a droite : elle absorbe la barre de defilement des systemes
   qui en dessinent une, sans quoi la page entiere defilerait de travers. */
.cal-cadre {
  width: calc(100vw - var(--rail) - 3 * var(--e6));
  max-width: calc(100vw - var(--rail) - 3 * var(--e6));
  margin-bottom: var(--e4);
}

.cal-cadre-tete > * {
  margin-bottom: var(--e3);
}

/* Plein ecran : la grille prend la fenetre entiere. C'est une CLASSE et non
   le plein ecran natif du navigateur, parce que deplacer une lecon recharge
   la page : le plein ecran natif tomberait a chaque geste, la classe se
   repose au chargement. Le natif est demande en plus quand il existe. */
.cal-cadre.cal-plein {
  position: fixed;
  inset: 0;
  z-index: 60;
  width: auto;
  max-width: none;
  margin: 0;
  padding: var(--e3) var(--e4) var(--e4);
  background: var(--papier);
  overflow: auto;
}

body.cal-plein-actif {
  overflow: hidden;
}

/* Sous la barre des jours, la journee defile s'il le faut : les entetes,
   eux, ne quittent jamais l'ecran. */
.cal-plein .cal-rangee-tetes,
.cal-plein .cal-rangee-groupes {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--papier-blanc);
}

.cal-plein .table-wrapper {
  border: 0;
  border-radius: 0;
  background: transparent;
}

.cal {
  --cal-h: 46px;
  --cal-mini: 150px;
  --cal-n: 6;
  /* La toile de la grille est aussi large que ses colonnes le demandent, et
     defile dans son cadre. Calculee ICI et non en dur cote serveur : la
     largeur minimale d'une colonne change avec la taille de l'ecran, et le
     serveur ne la connait pas. */
  min-width: calc(46px + var(--cal-n) * var(--cal-mini));
}

/* Une semaine par moniteur multiplie les colonnes : chacune se resserre pour
   qu'une journee entiere reste lisible d'un coup d'oeil. */
.cal-semaine-moniteur {
  --cal-mini: 84px;
}

.cal-nav {
  align-items: flex-end;
  gap: var(--e3);
}

.cal-nav-titre {
  text-align: right;
}

.cal-nav-titre strong {
  font-family: var(--titre);
  font-size: var(--tx-section);
  color: var(--marine);
}

.cal-saut {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
}

.cal-saut input[type='date'] {
  padding: var(--e1) var(--e2);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  font-family: var(--faits);
  font-size: var(--tx-annotation);
}

.cal-rangee {
  display: flex;
}

.cal-axe-tete {
  width: 46px;
  flex: none;
}

.cal-rangee-tetes {
  border-bottom: 2px solid var(--filet-fort);
}

.cal-groupe,
.cal-tete {
  flex: 1;
  min-width: var(--cal-mini);
  padding: var(--e1) var(--e1);
  text-align: center;
  font-size: var(--tx-legale);
  font-weight: 600;
  color: var(--marine);
  border-left: 1px solid var(--filet);
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-groupe {
  font-weight: 700;
  border-left: 2px solid var(--filet-fort);
}

.cal-groupe.cal-auj,
.cal-tete.cal-auj {
  background: var(--papier-creuse);
  color: var(--teal);
}

.cal-trous {
  display: block;
  font-weight: 400;
  font-size: var(--tx-legale);
  color: var(--du);
}

.cal-puce {
  display: inline-block;
  width: 9px;
  height: 9px;
  border: 1px solid var(--filet-fort);
  border-radius: 2px;
  vertical-align: -1px;
}

.cal-corps {
  position: relative;
}

.cal-axe {
  width: 46px;
  flex: none;
  position: relative;
}

.cal-heure {
  position: absolute;
  right: var(--e2);
  font-family: var(--faits);
  font-size: var(--tx-legale);
  color: var(--encre-pale);
}

/* Une reglure par heure, dessinee au degrade : un seul element pour
   quatorze filets, plutot que quatorze divs par colonne. */
.cal-col {
  flex: 1;
  min-width: var(--cal-mini);
  position: relative;
  border-left: 1px solid var(--filet);
  background: repeating-linear-gradient(
    180deg,
    var(--papier-blanc),
    var(--papier-blanc) calc(var(--cal-h) - 1px),
    var(--filet-tenu) calc(var(--cal-h) - 1px),
    var(--filet-tenu) var(--cal-h)
  );
}

.cal-col.cal-auj {
  background: repeating-linear-gradient(
    180deg,
    var(--papier-creuse),
    var(--papier-creuse) calc(var(--cal-h) - 1px),
    var(--filet-tenu) calc(var(--cal-h) - 1px),
    var(--filet-tenu) var(--cal-h)
  );
}

/* Plage vide : un lien de pose, invisible au repos, franc au survol. Sous
   les blocs, pour ne jamais voler leur clic. */
.cal-libre {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  display: block;
  text-decoration: none;
}

.cal-libre:hover,
.cal-libre:focus-visible {
  background: rgba(17, 110, 119, 0.08);
  outline: 1px solid var(--teal);
  outline-offset: -1px;
}

/* Rectangle dessine en glissant sur une plage vide : preview de la duree
   avant relachement. Le geste navigue au pointerup, cet element ne recoit
   donc jamais de clic lui-meme. */
.cal-libre-dessin {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 3;
  pointer-events: none;
  background: rgba(17, 110, 119, 0.16);
  border: 1px solid var(--teal);
  border-radius: 2px;
}

.cal-ev {
  position: absolute;
  z-index: 2;
  border-left: 3px solid var(--filet-fort);
  border-radius: var(--arrondi);
  padding: 2px var(--e1);
  font-size: var(--tx-legale);
  line-height: 1.25;
  overflow: hidden;
}

.cal-ev-serre {
  padding: 1px 3px;
  font-size: var(--tx-legale);
  line-height: 1.2;
}

.cal-ev-examen {
  border-left-width: 4px;
}

.cal-ev-activite {
  border-left-style: dashed;
}

/* Bloc lu chez Klaxo seul, pas encore recopie dans le planning MPermis (cf.
   ecrans/pose-directe.ts, `BlocPoseDirecte.source`). Meme famille de couleur,
   juste un filet pointille pour marquer la provenance, jamais un halo. */
.cal-ev-klaxo-seul {
  border-left-style: dotted;
  opacity: 0.85;
}

.cal-ev-conflit {
  outline: 2px solid var(--refus);
  outline-offset: -2px;
}

.cal-ev-lien {
  display: block;
  color: inherit;
  text-decoration: none;
}

/* La croix de suppression flotte en haut a droite du bloc : on lui reserve sa
   place, sinon elle vient mordre le nom du moniteur. */
.cal-ev-tete {
  display: flex;
  justify-content: space-between;
  gap: var(--e1);
  padding-right: var(--e4);
  font-family: var(--faits);
  font-weight: 600;
  color: var(--marine);
}

.cal-ev-mon {
  font-weight: 400;
  color: var(--encre-douce);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cal-ev-eleve {
  display: block;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-ev-note {
  display: block;
  font-size: var(--tx-legale);
  color: var(--encre-douce);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cal-ev-alerte {
  display: inline-block;
  font-size: var(--tx-legale);
  font-weight: 600;
  color: var(--refus);
}

.cal-ev-move {
  cursor: grab;
  touch-action: none;
  /* Brieve transition d'opacite a la saisie/relache (--vite, 120ms) : montre
     que le bloc vient d'etre pris. Volontairement limitee a l'opacite : un
     bloc peut cumuler ce role avec `.cal-ev-conflit` (contour rouge fixe),
     et animer le contour ici finirait par l'ecraser au repos. */
  transition: opacity var(--vite) var(--courbe);
}

.cal-ev-saisi {
  z-index: 30;
  opacity: 0.92;
  cursor: grabbing;
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

.cal-ev-suppr {
  position: absolute;
  top: 0;
  right: 0;
}

.cal-ev-del {
  border: 0;
  background: transparent;
  color: var(--refus);
  cursor: pointer;
  font-size: var(--tx-legale);
  line-height: 1;
  padding: 1px 3px;
}

.cal-ev-del:hover,
.cal-ev-del:focus-visible {
  background: var(--refus-fond);
}

.cal-ev-etirer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 7px;
  cursor: ns-resize;
}

.cal-legende {
  margin-top: var(--e3);
}

.cal-legende-ex {
  display: inline-block;
  width: 12px;
  height: 10px;
  border-left: 3px solid var(--filet-fort);
  vertical-align: -1px;
}

.cal-legende-ex.cal-ev-lecon {
  border-left-color: #1a6675;
}

.cal-legende-ex.cal-ev-examen {
  border-left-color: #7a2e54;
}

/* =====================================================================
 * Pose directe (docs/conception/kano-planning-pose-directe.md). L'eleve se
 * choisit en tete, panneau colle en haut de la grille : bordure fine,
 * aucun halo ni ombre portee, meme discipline que le reste du gabarit.
 * ===================================================================== */

.pd-panneau {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--e4);
  margin-bottom: var(--e3);
}

.pd-eleve {
  flex: 1 1 320px;
  min-width: 280px;
}

.pd-recherche {
  display: flex;
  gap: var(--e2);
  margin-bottom: var(--e2);
}

.pd-recherche input {
  flex: 1;
  padding: var(--e2) var(--e2);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
}

.pd-candidats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
}

.pd-eleve-choisi {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--e2);
}

/* L'attribut `hidden` seul perd face a `display:flex` ci-dessus (une regle de
   classe l'emporte sur le UA stylesheet) : sans cette ligne, la banniere
   d'eleve choisi resterait visible meme masquee, et se superposerait a la
   recherche. Meme piege potentiel pour tout futur bloc `.pd-*` avec un
   `display` explicite : NE PAS oublier son pendant `[hidden]`. */
.pd-eleve-choisi[hidden] {
  display: none;
}

.pd-reglages {
  flex: 1 1 320px;
  min-width: 280px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--e2);
}

.pd-reglages .field {
  flex: 1 1 220px;
  margin: 0;
}

.pd-examen {
  display: inline-flex;
  align-items: center;
  gap: var(--e1);
  font-size: var(--tx-annotation);
  white-space: nowrap;
}

.pd-hint-eleve {
  flex-basis: 100%;
  margin: 0;
  color: var(--refus);
}

/* Meme piege que `.pd-eleve-choisi` ci-dessus : la classe generique `.hint`
   fixe `display:block`, qui l'emporte sur l'attribut `hidden` seul. */
.pd-hint-eleve[hidden] {
  display: none;
}

/* Poste etroit : la grille defile horizontalement dans .table-wrapper
   plutot que d'ecraser six jours dans une largeur de telephone. */
@media (max-width: 900px) {
  /* Le rail passe au-dessus du contenu : la grille n'a plus a lui reserver
     sa colonne, elle prend simplement la largeur qu'on lui donne. */
  .cal-cadre {
    width: auto;
    max-width: none;
  }
}

@media (max-width: 860px) {
  .cal,
  .cal-semaine-moniteur {
    --cal-mini: 76px;
  }

  .cal-nav {
    flex-direction: column;
    align-items: stretch;
  }

  .cal-nav-titre {
    text-align: left;
  }
}

/* =====================================================================
 * Projets : le tableau facon Trello (docs/spec-kanban-projets.md).
 *
 * Meme parti pris que le reste de l'application : reglure plutot qu'ombre,
 * aucun halo, aucune ombre portee. Les colonnes sont des blocs a bordure
 * fine, les cartes aussi.
 * ===================================================================== */

.kan-tableau {
  display: grid;
  grid-template-columns: repeat(3, minmax(240px, 1fr));
  gap: var(--e4);
  align-items: start;
}

.kan-colonne {
  background: var(--papier-blanc);
  border: 1px solid var(--filet);
  border-radius: var(--arrondi);
  padding: var(--e3);
  min-height: 120px;
}

.kan-colonne-titre {
  display: flex;
  align-items: baseline;
  gap: var(--e2);
  margin: 0 0 var(--e3);
  font-size: var(--tx-corps);
  font-weight: 700;
  color: var(--marine);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.kan-compte {
  font-family: var(--faits);
  font-weight: 400;
  color: var(--encre-pale);
}

.kan-pile {
  display: flex;
  flex-direction: column;
  gap: var(--e2);
}

.kan-vide {
  margin: 0;
}

.kan-carte {
  display: block;
  background: var(--papier-blanc);
  border: 1px solid var(--filet);
  border-left: 3px solid var(--filet-fort);
  border-radius: var(--arrondi);
  padding: var(--e2) var(--e3);
  cursor: grab;
  touch-action: none;
  /* Brieve transition d'opacite a la saisie/relache (--vite, 120ms) : montre
     qu'on vient de prendre la carte. Volontairement limitee a l'opacite,
     jamais au contour : la carte peut aussi porter l'etat retard, et un
     contour anime empieterait sur ce signal, pas seulement sur le grabbing. */
  transition: opacity var(--vite) var(--courbe);
}

.kan-carte-saisie {
  z-index: 10;
  opacity: 0.92;
  cursor: grabbing;
  outline: 2px solid var(--teal);
  outline-offset: -2px;
}

.kan-carte-retard {
  border-left-color: var(--refus);
}

.kan-titre {
  display: block;
  color: var(--marine);
  font-weight: 600;
  text-decoration: none;
}

.kan-titre:hover,
.kan-titre:focus-visible {
  text-decoration: underline;
}

.kan-etiquettes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e1);
  margin-bottom: var(--e1);
}

.kan-etiquette {
  display: inline-block;
  padding: 1px 6px;
  border-radius: var(--arrondi);
  font-size: var(--tx-legale);
  font-weight: 600;
  color: #fff;
}

.kan-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e2);
  margin-top: var(--e2);
  font-size: var(--tx-legale);
}

.kan-priorite {
  font-family: var(--faits);
  font-weight: 600;
  color: var(--encre-douce);
}

.kan-priorite-haute {
  color: var(--refus);
}

.kan-echeance {
  color: var(--encre-douce);
}

.kan-echeance-bientot {
  color: var(--du);
  font-weight: 600;
}

.kan-echeance-retard {
  color: var(--refus);
  font-weight: 600;
}

.kan-choix-etiquettes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e2);
}

.kan-choix-etiquette {
  display: flex;
  align-items: center;
  gap: var(--e1);
  cursor: pointer;
}

.kan-archiver {
  margin-top: var(--e3);
}

@media (max-width: 860px) {
  .kan-tableau {
    grid-template-columns: 1fr;
  }
}

/* =====================================================================
 * Livret d'apprentissage : saisie rapide.
 *
 * Le facteur d'adoption numero un (cf. docs/conception/kano-livret-numerique.md)
 * est la vitesse de saisie au pouce, sur telephone, entre deux lecons. Chaque
 * niveau est un bouton directement tapable, jamais une liste deroulante a
 * ouvrir : la grille passe donc de deux colonnes par ligne a quatre boutons
 * empiles, qui s'alignent sur deux colonnes des que l'ecran le permet.
 * ===================================================================== */

.livret-mode {
  display: flex;
  gap: var(--e2);
  margin-bottom: var(--e4);
}

.livret-mode .btn {
  flex: 1 1 0;
}

.livret-liste-rapide {
  list-style: none;
  margin: 0;
  padding: 0;
}

.livret-ligne {
  padding: var(--e4) 0;
  border-bottom: 1px solid var(--filet);
  /* Laisse la barre superieure fixe (topbar) decouvrir la ligne visee au lieu
     de la cacher derriere elle quand la redirection saute a l'ancre #obj-*. */
  scroll-margin-top: var(--e6);
}

.livret-ligne:last-child {
  border-bottom: none;
}

.livret-ligne-tete {
  display: flex;
  align-items: baseline;
  gap: var(--e2);
  margin-bottom: var(--e1);
}

.livret-code {
  flex: 0 0 auto;
  color: var(--encre-pale);
  font-family: var(--faits);
  font-size: var(--tx-annotation);
  font-variant-numeric: tabular-nums;
}

.livret-libelle {
  font-size: var(--tx-corps);
}

.livret-ligne-etat {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-bottom: var(--e2);
}

.livret-ligne-etat .hint {
  margin: 0;
}

.hint-discret {
  color: var(--encre-pale);
}

/* Mention de provenance Klaxo, sobre : un mot en toutes lettres, jamais la
   seule couleur porteuse d'info. Volontairement discrete (pas une pill pleine
   comme les niveaux) pour rester lisible avec 32 objectifs sur un telephone. */
.tag-klaxo {
  display: inline-block;
  padding: 0 var(--e1);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  font-size: var(--tx-legale);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--teal);
  white-space: nowrap;
}

.niveau-strip {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--e2);
}

@media (min-width: 640px) {
  .niveau-strip {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Cible tactile confortable (44px minimum), distinguee par son LIBELLE en
   toutes lettres, jamais par la seule couleur : un daltonien lit le meme
   texte que tout le monde. La couleur d'etat actif ne fait que le confirmer. */
.niveau-btn {
  min-height: 44px;
  padding: var(--e2);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  background: var(--papier-blanc);
  color: var(--encre-douce);
  font: inherit;
  font-size: var(--tx-annotation);
  font-weight: 500;
  line-height: 1.15;
  text-align: center;
  cursor: pointer;
  transition:
    background var(--vite) var(--courbe),
    border-color var(--vite) var(--courbe),
    transform var(--vite) var(--courbe);
}

.niveau-btn:active {
  transform: translateY(1px);
}

.niveau-btn.actif {
  border-width: 2px;
  font-weight: 700;
  color: var(--encre);
}

.niveau-btn-null.actif {
  background: var(--papier-creuse);
  border-color: var(--filet-fort);
}

.niveau-btn-broached.actif {
  background: var(--papier-creuse);
  border-color: #c3cddd;
  color: var(--teal);
}

.niveau-btn-covered.actif {
  background: var(--du-fond);
  border-color: #ecd9ad;
  color: var(--du);
}

.niveau-btn-assimilated.actif {
  background: var(--solde-fond);
  border-color: #bfe6d3;
  color: var(--solde);
}

/* Grille de consultation et saisie avancee : repliees, cf. vues/livret.ts. */
.livret-grille > summary,
.card > summary {
  cursor: pointer;
  color: var(--encre-douce);
  font-size: var(--tx-annotation);
  font-weight: 500;
}

.livret-grille > summary:hover,
.card > summary:hover {
  color: var(--encre);
}

.livret-grille-corps,
.livret-avance-corps {
  margin-top: var(--e4);
  display: grid;
  gap: var(--e4);
}

/* -------------------------------------------------------- Ma journee (moniteur) */

/* Ecran lu au telephone, en voiture, en plein jour : une seule colonne,
   jamais de grille qui retrecirait les cibles. */
.mj-ecran {
  display: grid;
  gap: var(--e4);
  max-width: 640px;
}

.mj-liste {
  display: grid;
  gap: var(--e4);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Cible tactile large (bien au-dela des 44px minimum) : pas de survol, tout
   se lit et se distingue au repos, doigt ou non. Bordure fine, jamais
   d'ombre portee ni de halo. */
.mj-carte {
  display: grid;
  gap: var(--e2);
  padding: var(--e4);
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  background: var(--papier-blanc);
}

.mj-heure {
  font-size: var(--tx-section);
  font-weight: 700;
  color: var(--teal);
  font-variant-numeric: tabular-nums;
}

.mj-corps {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e2);
}

.mj-eleve {
  font-size: var(--tx-section);
  font-weight: 600;
  color: var(--encre);
}

.mj-note {
  margin: 0;
  color: var(--encre-douce);
  font-size: var(--tx-corps);
}

/* -------------------------------------------------------- Recu de paiement */

/* Deux exemplaires IDENTIQUES sur une seule feuille A4, decoupables au
   milieu (docs/conception/kano-justificatif-encaissement.md). A l'ecran,
   les deux moities restent visibles l'une sous l'autre pour verification
   avant impression ; a l'impression, `@page` force le format et empeche
   tout debordement sur une seconde page. */
.recu-feuille {
  display: flex;
  flex-direction: column;
  max-width: 720px;
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  overflow: hidden;
  background: var(--papier-blanc);
}

.recu-copie {
  padding: var(--e6);
  display: grid;
  gap: var(--e3);
}

.recu-trait-decoupe {
  border-top: 1px dashed var(--encre-pale);
  margin: 0;
  position: relative;
}

/* Ciseaux textuels : un reperage sobre, sans icone ni emoji. */
.recu-trait-decoupe::after {
  content: '\2702 decouper ici';
  position: absolute;
  left: var(--e4);
  top: -9px;
  background: var(--papier-blanc);
  padding: 0 var(--e2);
  font-size: var(--tx-legale);
  color: var(--encre-pale);
  letter-spacing: 0.02em;
}

.recu-entete {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--e4);
  border-bottom: 1px solid var(--filet);
  padding-bottom: var(--e2);
}

.recu-titre {
  font-size: var(--tx-corps);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--marine);
}

.recu-ecole {
  font-size: var(--tx-annotation);
  color: var(--encre-douce);
  line-height: 1.5;
}

.recu-ecole strong {
  color: var(--encre);
}

.recu-corps {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e3) var(--e6);
  font-size: var(--tx-corps);
}

.recu-champ .lab {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
}

.recu-champ .val {
  font-variant-numeric: tabular-nums;
  color: var(--encre);
}

.recu-montant {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--filet);
  padding-top: var(--e2);
}

.recu-montant .val {
  font-size: var(--tx-section);
  font-weight: 700;
  color: var(--teal);
}

.recu-annulee {
  grid-column: 1 / -1;
  border: 1px solid var(--refus);
  background: var(--refus-fond);
  color: var(--refus);
  padding: var(--e2) var(--e3);
  border-radius: var(--arrondi);
  font-weight: 600;
  font-size: var(--tx-annotation);
}

.recu-pied {
  grid-column: 1 / -1;
  font-size: var(--tx-legale);
  color: var(--encre-pale);
}

@media print {
  /* Rien d'autre que le recu ne s'imprime : barre du haut, rail de
     navigation, actions d'ecran, flashs de message. */
  .topbar,
  .rail,
  .no-print {
    display: none !important;
  }

  .scene {
    display: block !important;
  }

  .container {
    max-width: none !important;
    padding: 0 !important;
    margin: 0 !important;
  }

  .recu-feuille {
    border: none;
    border-radius: 0;
    max-width: none;
  }

  .recu-copie {
    /* Chaque moitie occupe exactement la moitie de la hauteur utile de la
       page : c'est ce qui garantit que les deux exemplaires tiennent sur
       une seule feuille A4, jamais deux. */
    height: 133mm;
    box-sizing: border-box;
    break-inside: avoid;
  }

  .recu-trait-decoupe {
    break-before: avoid;
    break-after: avoid;
  }

  @page {
    size: A4 portrait;
    margin: 10mm;
  }
}

/* ------------------------------------------------------------------ Facture */

/* Une SEULE page s'imprime (pas de double decoupable, a la difference du
   recu ci-dessus) : une facture part chez un tiers, elle est unique
   (docs/conception/kano-facturation.md, Lot B). */
.fact-cadre {
  max-width: 720px;
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  overflow: hidden;
  background: var(--papier-blanc);
}

.fact-feuille {
  padding: var(--e6);
  display: grid;
  gap: var(--e4);
}

.fact-entete {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--e4);
  border-bottom: 1px solid var(--filet);
  padding-bottom: var(--e2);
}

.fact-titre {
  font-size: var(--tx-corps);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--marine);
}

.fact-ecole {
  font-size: var(--tx-annotation);
  color: var(--encre-douce);
  line-height: 1.5;
  text-align: right;
}

.fact-ecole strong {
  color: var(--encre);
}

.fact-destinataire .lab,
.fact-champ .lab {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
}

.fact-destinataire .val,
.fact-champ .val {
  font-variant-numeric: tabular-nums;
  color: var(--encre);
}

.fact-champ {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: var(--e1) 0;
  border-bottom: 1px solid var(--filet);
}

.fact-avoir-bandeau {
  border: 1px solid var(--refus);
  background: var(--refus-fond);
  color: var(--refus);
  padding: var(--e2) var(--e3);
  border-radius: var(--arrondi);
  font-size: var(--tx-annotation);
}

.fact-lignes {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--tx-corps);
}

.fact-lignes th {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
  text-align: left;
  padding-bottom: var(--e1);
  border-bottom: 1px solid var(--filet);
}

.fact-lignes td {
  padding: var(--e2) 0;
  border-bottom: 1px solid var(--filet);
  color: var(--encre);
}

.fact-total td {
  font-weight: 700;
  font-size: var(--tx-section);
  color: var(--teal);
  border-bottom: none;
  padding-top: var(--e3);
}

.fact-pied {
  font-size: var(--tx-legale);
  color: var(--encre-pale);
}

.fact-cachet {
  justify-self: end;
  max-width: 140px;
  height: auto;
  /*
   * Masquage du numero RCS errone du cachet (Anthony, 2026-08-02, cf. le
   * commentaire dans apps/web/src/vues/facture.ts). Le cachet
   * (apps/web/public/cachet.png) porte « 998 608 258 R.C.S. Créteil », deux
   * chiffres faux par rapport au Kbis (988 608 253). Aucun outil d'edition
   * d'image disponible, retoucher les pixels d'un cachet serait douteux :
   * on decoupe donc la SEULE bande horizontale qui porte le numero, entre
   * 57,5% et 65% de la hauteur de l'image (bornes mesurees pixel par pixel
   * sur cachet.png, 600x400 : la ligne « 998 608 258 R.C.S. Créteil » couvre
   * y=235 a y=254, les lignes voisines s'arretent avant y=230 et ne
   * reprennent qu'a partir de y=261, d'ou la marge des deux cotes). La
   * signature et la denomination, au-dessus et en dessous, restent visibles.
   * Le decoupage est un simple clip-path sur la boite de l'image (pas de
   * filtre, pas de transformation de pixels) : il tient a l'impression
   * comme a l'ecran. NE PAS RETIRER cette regle sans reintroduire le
   * numero errone sur les factures.
   */
  clip-path: polygon(0 0, 100% 0, 100% 57.5%, 0 57.5%, 0 65%, 100% 65%, 100% 100%, 0 100%);
}

@media print {
  .fact-cadre {
    border: none;
    border-radius: 0;
    max-width: none;
  }
}

/* ---------------------------------------- Contrat et attestation de suivi */

/* Partagee par le contrat de formation et l'attestation de suivi
   (docs/conception/kano-contrat-formation.md) : contrairement au recu et a
   la facture, ce document peut deborder sur PLUSIEURS pages A4 a
   l'impression (un contrat detaille ou une attestation avec les 32
   objectifs) : pas de contrainte de hauteur fixe comme .recu-copie, chaque
   section peut se couper proprement entre deux pages. */
.contrat-cadre {
  max-width: 760px;
  border: 1px solid var(--filet-fort);
  border-radius: var(--arrondi);
  overflow: hidden;
  background: var(--papier-blanc);
}

.contrat-feuille {
  padding: var(--e6);
  display: grid;
  gap: var(--e4);
}

.contrat-entete {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--e4);
  border-bottom: 1px solid var(--filet);
  padding-bottom: var(--e2);
}

.contrat-titre {
  font-size: var(--tx-corps);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--marine);
}

.contrat-ecole {
  font-size: var(--tx-annotation);
  color: var(--encre-douce);
  line-height: 1.5;
  text-align: right;
}

.contrat-ecole strong {
  color: var(--encre);
}

/* Bandeau "document de travail" : sobre, jamais alarmant (ce n'est pas une
   erreur, c'est l'etat normal tant que Klaxo est detenteur). Meme famille
   visuelle que .fact-avoir-bandeau, teinte neutre plutot que refus. */
.contrat-detenteur {
  border: 1px solid var(--filet-fort);
  background: var(--papier);
  color: var(--encre-douce);
  padding: var(--e2) var(--e3);
  border-radius: var(--arrondi);
  font-size: var(--tx-annotation);
}

.contrat-parties {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e4);
}

.contrat-partie .lab {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
}

.contrat-partie .val {
  font-size: var(--tx-corps);
  font-weight: 600;
  color: var(--encre);
}

.contrat-lignes {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--tx-corps);
}

.contrat-lignes th {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
  text-align: left;
  padding-bottom: var(--e1);
  border-bottom: 1px solid var(--filet);
}

.contrat-lignes td {
  padding: var(--e2) 0;
  border-bottom: 1px solid var(--filet);
  color: var(--encre);
}

.contrat-total td {
  font-weight: 700;
  font-size: var(--tx-corps);
  color: var(--teal);
  border-bottom: none;
  padding-top: var(--e2);
}

.contrat-mentions {
  font-size: var(--tx-annotation);
  color: var(--encre);
  line-height: 1.6;
}

.contrat-mentions p {
  margin: 0 0 var(--e2) 0;
}

/* Marque visible d'une mention obligatoire absente de l'application
   (docs/conception/kano-contrat-formation.md, "a eviter" : ne jamais
   fabriquer une donnee manquante). Volontairement voyante, meme registre que
   .flash.warn, jamais confondue avec le texte normal du document. */
.a-valider {
  color: var(--refus);
  font-style: italic;
}

.contrat-signatures {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e6);
  margin-top: var(--e4);
}

.contrat-signature .lab {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
  margin-bottom: var(--e2);
}

.contrat-signature-zone {
  height: 60px;
  border: 1px dashed var(--encre-pale);
  border-radius: var(--arrondi);
}

.contrat-pied {
  font-size: var(--tx-legale);
  color: var(--encre-pale);
}

.contrat-progression {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--filet);
  border-bottom: 1px solid var(--filet);
  padding: var(--e2) 0;
}

.contrat-progression .lab {
  font-size: var(--tx-legale);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--encre-pale);
}

.contrat-progression .val {
  font-size: var(--tx-section);
  font-weight: 700;
  color: var(--teal);
}

@media print {
  .contrat-cadre {
    border: none;
    border-radius: 0;
    max-width: none;
  }

  .contrat-lignes tr,
  .contrat-signatures,
  .contrat-partie {
    break-inside: avoid;
  }
}
