/* Jobcrible — feuille de style unique (spec 13 § 4, docs/ux/03-fondations.md et 04-composants.md).
 * Réécrite de zéro pour la tranche « socle » (S4-T0) : l'ancienne feuille n'est pas reprise.
 * Un seul fichier, cinq couches, dans cet ordre déclaré une fois pour toutes. Aucune règle de
 * priorité forcée, aucun mode sombre (décision produit du 23/09).
 */

@layer jetons, base, composants, mise-en-page, utilitaires;

@layer jetons {
  :root {
    /* Vert profond — habillage par défaut (fondations § 1) */
    --jobcrible-fond: #eef3f1;
    --jobcrible-surface: #ffffff;
    --jobcrible-bordure: #d2ddd9;
    --jobcrible-bordure-champ: #7c8a86;
    --jobcrible-separateur: #e4ebe8;
    --jobcrible-texte: #1a201e;
    --jobcrible-texte-2: #586662;
    --jobcrible-texte-3: #82908b;
    --jobcrible-accent: #0f6e63;
    --jobcrible-accent-presse: #0b574e;
    --jobcrible-accent-pale: #e3f1ee;

    /* Couleurs de sens — jamais redéfinies par un habillage (fondations § 2) */
    --jobcrible-succes: #2b752f;
    --jobcrible-succes-fond: #e6f4e6;
    --jobcrible-attention: #9a4d00;
    --jobcrible-attention-fond: #fdefd9;
    --jobcrible-danger: #8f2222;
    --jobcrible-danger-fond: #fbe7e7;
    --jobcrible-info: #1e5fb3;
    --jobcrible-info-fond: #e6effb;
    --jobcrible-reexamen: #5b2d9b;
    --jobcrible-reexamen-fond: #efe8fb;
    --jobcrible-neutre: #3d4652;
    --jobcrible-neutre-fond: #eceef1;
    --jobcrible-compteur: #c2410c;
    --jobcrible-chiffre-chaud: #b3400d;

    /* Espaces — sept pas, multiples de 4 (fondations § 4) */
    --jobcrible-e-1: 0.25rem; /* 4px */
    --jobcrible-e-2: 0.5rem; /* 8px */
    --jobcrible-e-3: 0.75rem; /* 12px */
    --jobcrible-e-4: 1rem; /* 16px */
    --jobcrible-e-5: 1.5rem; /* 24px */
    --jobcrible-e-6: 2rem; /* 32px */
    --jobcrible-e-7: 3rem; /* 48px */

    /* Formes (fondations § 5) */
    --jobcrible-r-controle: 4px;
    --jobcrible-r-cadre: 6px;

    /* Texte (fondations § 3) */
    --jobcrible-t-13: 0.8125rem;
    --jobcrible-t-14: 0.875rem;
    --jobcrible-t-15: 0.9375rem;
    --jobcrible-t-17: 1.0625rem;
    --jobcrible-t-22: 1.375rem;
    --jobcrible-t-26: 1.625rem;
    --jobcrible-t-32: 2rem;

    /* Mouvement (fondations § 8) */
    --jobcrible-d-etat: 150ms;
    --jobcrible-d-apparition: 200ms;

    /* Mise en page (fondations § 7) */
    --jobcrible-menu: 248px;
    --jobcrible-menu-replie: 64px;
    --jobcrible-contenu-max: 1240px;
    --jobcrible-champ-max: 480px;
    --jobcrible-assistant-max: 800px;
  }

  [data-habillage="vert-profond"] {
    --jobcrible-fond: #eef3f1;
    --jobcrible-surface: #ffffff;
    --jobcrible-bordure: #d2ddd9;
    --jobcrible-bordure-champ: #7c8a86;
    --jobcrible-separateur: #e4ebe8;
    --jobcrible-texte: #1a201e;
    --jobcrible-texte-2: #586662;
    --jobcrible-texte-3: #82908b;
    --jobcrible-accent: #0f6e63;
    --jobcrible-accent-presse: #0b574e;
    --jobcrible-accent-pale: #e3f1ee;
  }

  [data-habillage="bleu-ardoise"] {
    --jobcrible-fond: #eef1f5;
    --jobcrible-surface: #ffffff;
    --jobcrible-bordure: #d5dbe3;
    --jobcrible-bordure-champ: #7f8894;
    --jobcrible-separateur: #e6eaef;
    --jobcrible-texte: #1b1f27;
    --jobcrible-texte-2: #5b6470;
    --jobcrible-texte-3: #848c99;
    --jobcrible-accent: #2b4c7e;
    --jobcrible-accent-presse: #213c65;
    --jobcrible-accent-pale: #e6edf6;
  }

  [data-habillage="bordeaux"] {
    --jobcrible-fond: #f4f0ec;
    --jobcrible-surface: #ffffff;
    --jobcrible-bordure: #ddd5cf;
    --jobcrible-bordure-champ: #8a817b;
    --jobcrible-separateur: #ebe5e0;
    --jobcrible-texte: #1f1d1a;
    --jobcrible-texte-2: #605c55;
    --jobcrible-texte-3: #8a857c;
    --jobcrible-accent: #7a2e3f;
    --jobcrible-accent-presse: #632432;
    --jobcrible-accent-pale: #f5e9ec;
  }

  [data-habillage="anthracite"] {
    --jobcrible-fond: #f0f1f3;
    --jobcrible-surface: #ffffff;
    --jobcrible-bordure: #d7d9de;
    --jobcrible-bordure-champ: #83878f;
    --jobcrible-separateur: #e7e8eb;
    --jobcrible-texte: #1c1e23;
    --jobcrible-texte-2: #5d616a;
    --jobcrible-texte-3: #878b94;
    --jobcrible-accent: #3a3f4b;
    --jobcrible-accent-presse: #2b2f38;
    --jobcrible-accent-pale: #e9eaee;
  }
}

@layer base {
  @font-face {
    font-family: "IBM Plex Sans";
    src: url("../fonts/ibm-plex-sans-400.92957c9effb0.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: "IBM Plex Sans";
    src: url("../fonts/ibm-plex-sans-500.fb00e026363b.woff2") format("woff2");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
  }

  @font-face {
    font-family: "IBM Plex Sans";
    src: url("../fonts/ibm-plex-sans-600.6fe5a646c961.woff2") format("woff2");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
  }

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

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

  body {
    margin: 0;
    font-family: "IBM Plex Sans", system-ui, sans-serif;
    font-size: var(--jobcrible-t-15);
    line-height: 1.5;
    background: var(--jobcrible-fond);
    color: var(--jobcrible-texte);
  }

  h1,
  h2,
  h3 {
    margin: 0;
    font-weight: 600;
  }

  h1 {
    font-size: var(--jobcrible-t-26);
    line-height: 1.2;
  }

  h2 {
    font-size: var(--jobcrible-t-22);
    line-height: 1.25;
  }

  h3 {
    font-size: var(--jobcrible-t-17);
    line-height: 1.3;
  }

  p {
    margin: 0;
  }

  a {
    color: var(--jobcrible-accent);
    text-decoration: none;
  }

  /* Un lien mêlé à du texte courant doit se distinguer sans compter sur la seule couleur (WCAG
     1.4.1, axe-core `link-in-text-block`) — fiches 09/10 (S4-U3), premier endroit du dépôt où un
     lien vit AU MILIEU d'une phrase plutôt que seul (bouton, pied de page, fil d'Ariane) : dans
     un `<p>` (RGPD, fiche 09) ou dans le texte de la case notice (fiche 10, libellé de la case
     à cocher). */
  p a,
  label a {
    text-decoration: underline;
  }

  a:hover {
    color: var(--jobcrible-accent-presse);
  }

  img {
    max-width: 100%;
    display: block;
  }

  table {
    border-collapse: collapse;
  }

  ul,
  ol {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  button {
    font-family: "IBM Plex Sans", system-ui, sans-serif;
  }

  code,
  pre,
  kbd {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  }

  [role="tablist"] a,
  .bouton,
  .filtre,
  a.pastille-lien {
    transition:
      background-color var(--jobcrible-d-etat) ease,
      color var(--jobcrible-d-etat) ease,
      border-color var(--jobcrible-d-etat) ease;
  }

  ::backdrop {
    background: rgb(20 28 24 / 45%);
  }

  dialog[open] {
    animation: jobcrible-apparition var(--jobcrible-d-apparition) ease;
  }

  @keyframes jobcrible-apparition {
    from {
      opacity: 0;
    }

    to {
      opacity: 1;
    }
  }

  body:has(dialog[open]) {
    overflow: hidden;
  }

  [role="status"]:empty {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
  }
}

@layer composants {
  /* -- lien d'évitement --------------------------------------------------------------- */
  .evitement {
    position: absolute;
    inset-block-start: -100px;
    inset-inline-start: var(--jobcrible-e-2);
    z-index: 100;
    padding: var(--jobcrible-e-2) var(--jobcrible-e-4);
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    border-radius: var(--jobcrible-r-controle);
    font-weight: 600;
  }

  .evitement:focus {
    inset-block-start: var(--jobcrible-e-2);
  }

  /* -- bouton --------------------------------------------------------------------------- */
  .bouton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--jobcrible-e-2);
    min-height: 40px;
    padding-inline: var(--jobcrible-e-4);
    border-radius: var(--jobcrible-r-controle);
    border: 1px solid transparent;
    font: inherit;
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
  }

  .bouton--principal {
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    border-color: var(--jobcrible-accent);
  }

  .bouton--principal:hover {
    background: var(--jobcrible-accent-presse);
    border-color: var(--jobcrible-accent-presse);
    color: var(--jobcrible-surface);
  }

  .bouton--secondaire {
    background: var(--jobcrible-surface);
    color: var(--jobcrible-accent);
    border-color: var(--jobcrible-accent);
  }

  .bouton--secondaire:hover {
    color: var(--jobcrible-accent-presse);
    border-color: var(--jobcrible-accent-presse);
  }

  .bouton--discret {
    background: transparent;
    color: var(--jobcrible-accent);
    border-color: transparent;
  }

  .bouton--discret:hover {
    color: var(--jobcrible-accent-presse);
  }

  .bouton--danger {
    background: var(--jobcrible-surface);
    color: var(--jobcrible-danger);
    border-color: var(--jobcrible-danger);
  }

  .bouton--danger-plein {
    background: var(--jobcrible-danger);
    color: var(--jobcrible-surface);
    border-color: var(--jobcrible-danger);
  }

  .bouton--40 {
    min-height: 40px;
  }

  .bouton--32 {
    min-height: 32px;
    padding-inline: var(--jobcrible-e-3);
    font-size: var(--jobcrible-t-14);
  }

  .bouton--44 {
    min-height: 44px;
    padding-inline: var(--jobcrible-e-5);
  }

  /* Fiches 09/10 (S4-U3) : « Déposer ma candidature » — 48 px partout où le geste est demandé
     (spec 12 § B.9/B.10), jamais 44 (`.bouton--44`, une taille différente déjà utilisée
     ailleurs). `.bouton.bouton--48` (deux classes, spécificité plus haute que `.bouton` seule) :
     sinon la règle mobile `.bouton { min-height: 44px }` plus bas dans la feuille l'emporterait
     par ORDRE de source sous 640 px (même spécificité qu'un `.bouton--48` seul), ramenant ce
     bouton précis SOUS 48 px — constaté en écrivant cette tranche. */
  .bouton.bouton--48 {
    min-height: 48px;
    padding-inline: var(--jobcrible-e-5);
  }

  .bouton[aria-busy="true"] {
    cursor: progress;
  }

  .bouton .icon {
    animation: none;
  }

  .bouton[aria-busy="true"] .icon--chargement {
    animation: jobcrible-roue 900ms linear infinite;
  }

  @keyframes jobcrible-roue {
    to {
      transform: rotate(360deg);
    }
  }

  /* -- champ de saisie -------------------------------------------------------------------- */
  .champ-groupe {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    max-width: var(--jobcrible-champ-max);
  }

  .champ-groupe--large {
    max-width: none;
  }

  .champ-groupe--court {
    max-width: 12rem;
  }

  .champ-groupe label,
  .champ-groupe-titre {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
  }

  /* Fiche 07, Mon compte : « Mot de passe » suit un bouton Enregistrer (Alertes) — un peu plus
     d'écart que les autres, comme dans la maquette (`ecran-07-compte.html`, un bouton pleine
     largeur occupe cet espace là-bas ; ici Identité et Alertes ont chacune le leur, propre). */
  .compte-separation {
    margin-top: 4rem;
  }

  .logo-apercu {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    flex-shrink: 0;
    border-radius: var(--jobcrible-r-controle);
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    font-weight: 700;
  }

  .champ-aide {
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
    margin: 0;
  }

  .champ,
  .select {
    width: 100%;
    min-height: 40px;
    padding: var(--jobcrible-e-2) var(--jobcrible-e-3);
    border: 1px solid var(--jobcrible-bordure-champ);
    border-radius: var(--jobcrible-r-controle);
    background: var(--jobcrible-surface);
    color: var(--jobcrible-texte);
    font: inherit;
    font-size: var(--jobcrible-t-15);
  }

  textarea.champ {
    min-height: 6.5rem;
    resize: vertical;
  }

  .champ[aria-invalid="true"] {
    border-color: var(--jobcrible-danger);
    border-width: 2px;
  }

  .champ-erreur {
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-2);
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-danger);
    font-weight: 500;
    margin: 0;
  }

  /* Écran 03 (S4-U3) : voir le commentaire de `champ()` dans jobcrible.js — hors du flux pour ne
     jamais déplacer un bouton juste en dessous pendant le geste qui déclenche l'erreur. */
  .champ-erreur--flottante {
    position: absolute;
    top: 100%;
    inset-inline-start: 0;
    padding-block-start: var(--jobcrible-e-1);
  }

  .select {
    appearance: none;
    padding-inline-end: 2.25rem;
    background-repeat: no-repeat;
    background-position: right var(--jobcrible-e-2) center;
  }

  .select--attention {
    color: var(--jobcrible-attention);
  }

  .select--info {
    color: var(--jobcrible-info);
  }

  .select--neutre {
    color: var(--jobcrible-neutre);
  }

  /* -- cases et boutons radio --------------------------------------------------------------- */
  .groupe-cases,
  .groupe-radios {
    border: 0;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
  }

  .groupe-cases legend,
  .groupe-radios legend {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    padding: 0;
    margin: 0 0 var(--jobcrible-e-2) 0;
  }

  .option-case,
  .option-radio {
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-3);
    min-height: 40px;
    cursor: pointer;
    font-size: var(--jobcrible-t-15);
  }

  .option-case input,
  .option-radio input {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    margin-top: 2px;
    accent-color: var(--jobcrible-accent);
  }

  .option-aide {
    display: block;
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  /* -- sélecteur d'habillage (fiche 07, quatre cartes avec extrait) --------------------- */
  .groupe-habillages {
    border: 0;
    margin: 0;
    padding: 0;
  }

  .groupe-habillages > legend {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    padding: 0;
    margin: 0 0 var(--jobcrible-e-2) 0;
  }

  .grille-habillages {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--jobcrible-e-3);
  }

  .carte-habillage {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    padding: var(--jobcrible-e-3);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    cursor: pointer;
  }

  .carte-habillage--choisie {
    border: 2px solid var(--jobcrible-accent);
  }

  .carte-habillage .option-radio {
    min-height: 0;
  }

  /* Chaque extrait est scopé à SON propre habillage (`[data-habillage]`, tête de fichier) —
     mini-rendu construit avec les mêmes jetons que la vraie page, jamais des couleurs en dur
     dupliquées ici : quatre couleurs à maintenir à un seul endroit. */
  .extrait-habillage {
    display: flex;
    height: 5.5rem;
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-controle);
    background: var(--jobcrible-fond);
    overflow: hidden;
  }

  .extrait-habillage-menu {
    width: 34%;
    background: var(--jobcrible-surface);
    border-right: 1px solid var(--jobcrible-bordure);
  }

  .extrait-habillage-menu::before {
    content: "";
    display: block;
    margin: var(--jobcrible-e-2);
    height: var(--jobcrible-e-2);
    width: 60%;
    border-radius: 2px;
    background: var(--jobcrible-accent);
  }

  .extrait-habillage-contenu {
    flex-grow: 1;
    margin: var(--jobcrible-e-2);
    border-radius: 2px;
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
  }

  @media (width < 900px) {
    .grille-habillages {
      grid-template-columns: 1fr;
    }
  }

  /* -- fichier -------------------------------------------------------------------------- */
  .fichier-cadre {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-3);
    border: 1px solid var(--jobcrible-bordure-champ);
    border-radius: var(--jobcrible-r-controle);
    background: var(--jobcrible-surface);
  }

  .fichier-cadre input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
  }

  .fichier-nom {
    font-size: var(--jobcrible-t-15);
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .fichier-poids {
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }

  /* -- messages ------------------------------------------------------------------------- */
  .message {
    display: flex;
    gap: var(--jobcrible-e-3);
    align-items: flex-start;
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    border: 1px solid;
    border-radius: var(--jobcrible-r-cadre);
    color: var(--jobcrible-texte);
  }

  .message-titre {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    margin: 0;
  }

  .message-texte {
    font-size: var(--jobcrible-t-14);
    margin: 0;
  }

  .message-liens {
    margin: var(--jobcrible-e-1) 0 0 0;
    padding-inline-start: var(--jobcrible-e-4);
    list-style: disc;
  }

  .message-liens a {
    font-weight: 600;
  }

  .message-fermer {
    margin-inline-start: auto;
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: var(--jobcrible-e-1);
    display: flex;
    flex-shrink: 0;
  }

  .message--erreur {
    background: var(--jobcrible-danger-fond);
    border-color: var(--jobcrible-danger);
  }

  .message--erreur .message-titre,
  .message--erreur .message-fermer {
    color: var(--jobcrible-danger);
  }

  .message--succes {
    background: var(--jobcrible-succes-fond);
    border-color: var(--jobcrible-succes);
  }

  .message--succes .message-titre,
  .message--succes .message-fermer {
    color: var(--jobcrible-succes);
  }

  .message--attention {
    background: var(--jobcrible-attention-fond);
    border-color: var(--jobcrible-attention);
  }

  .message--attention .message-titre,
  .message--attention .message-fermer {
    color: var(--jobcrible-attention);
  }

  .message--info {
    background: var(--jobcrible-info-fond);
    border-color: var(--jobcrible-info);
  }

  .message--info .message-titre,
  .message--info .message-fermer {
    color: var(--jobcrible-info);
  }

  /* -- pastilles d'état ------------------------------------------------------------------- */
  .pastille {
    display: inline-block;
    padding: 3px var(--jobcrible-e-2);
    border-radius: var(--jobcrible-r-controle);
    font-size: var(--jobcrible-t-13);
    font-weight: 600;
    white-space: nowrap;
  }

  .pastille--green {
    background: var(--jobcrible-succes-fond);
    color: var(--jobcrible-succes);
  }

  .pastille--orange {
    background: var(--jobcrible-attention-fond);
    color: var(--jobcrible-attention);
  }

  .pastille--red {
    background: var(--jobcrible-danger-fond);
    color: var(--jobcrible-danger);
  }

  .pastille--blue {
    background: var(--jobcrible-info-fond);
    color: var(--jobcrible-info);
  }

  .pastille--purple {
    background: var(--jobcrible-reexamen-fond);
    color: var(--jobcrible-reexamen);
  }

  .pastille--gray {
    background: var(--jobcrible-neutre-fond);
    color: var(--jobcrible-neutre);
  }

  .pastille--struck {
    text-decoration: line-through;
  }

  /* -- cartes --------------------------------------------------------------------------- */
  .carte {
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    padding: var(--jobcrible-e-5);
  }

  .carte-chiffre {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
  }

  .carte-chiffre-titre {
    font-size: var(--jobcrible-t-14);
    font-weight: 600;
    color: var(--jobcrible-texte-2);
  }

  .carte-chiffre-valeur {
    font-size: var(--jobcrible-t-32);
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
  }

  .chiffre--chaud {
    color: var(--jobcrible-chiffre-chaud);
  }

  .carte-chiffre-phrase {
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  .carte-chiffre-lien {
    display: inline-flex;
    align-items: center;
    gap: var(--jobcrible-e-1);
    font-size: var(--jobcrible-t-14);
    font-weight: 600;
    margin-top: var(--jobcrible-e-1);
  }

  /* Fiche 02 (S4-U3) : cartes de brouillon — « entre deux cartes : 20px » (composant Cartes,
     § 3) donne l'écart de la liste elle-même, pas seulement le padding intérieur de `.carte`.
     Largeur plafonnée (maquette ecran-02-brouillons : 920px sur un contenu de 1440px) — une
     liste de brouillons n'a jamais besoin de la pleine largeur du tableau des postes. */
  .liste-brouillons {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
    list-style: none;
    margin: 0;
    padding: 0;
    max-width: 50rem;
  }

  .carte-brouillon {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
  }

  .carte-brouillon-titre {
    margin: 0;
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
  }

  .carte-brouillon-avancement {
    margin: 0;
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  .carte-brouillon-actions {
    display: flex;
    gap: var(--jobcrible-e-2);
    margin-block-start: var(--jobcrible-e-1);
  }

  .carte-section {
    padding: 0;
    overflow: hidden;
  }

  .carte-section-entete {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-4) var(--jobcrible-e-5) var(--jobcrible-e-2);
  }

  .carte-section-corps {
    padding: var(--jobcrible-e-3) var(--jobcrible-e-5);
    border-top: 1px solid var(--jobcrible-separateur);
  }

  .carte-cliquable {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    padding: var(--jobcrible-e-4);
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    color: var(--jobcrible-texte);
    min-height: 44px;
  }

  /* -- tableau de bord : postes en cours, activité (spec 12 § B.1) ----------------------- */
  .liste-postes a {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--jobcrible-e-3);
    font-weight: 600;
    color: var(--jobcrible-texte);
    text-decoration: none;
  }

  .liste-postes-comptes {
    display: block;
    margin-top: var(--jobcrible-e-1);
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  /* S4-U2 (revue-ui, écran 01) : `.liste-postes a` met tout son contenu en 600 (titre du poste
     ET métadonnée confondus) — la maquette réserve le gras au titre, cette métadonnée est
     secondaire (gris, 13 px, une ligne — comme les en-têtes de `.tableau`). */
  .liste-postes-depuis {
    font-weight: 400;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    white-space: nowrap;
  }

  .activite li {
    display: flex;
    gap: var(--jobcrible-e-3);
    font-size: var(--jobcrible-t-14);
  }

  .activite time {
    flex-shrink: 0;
    width: 3.5rem;
    color: var(--jobcrible-texte-2);
    font-variant-numeric: tabular-nums;
  }

  /* -- tableau -------------------------------------------------------------------------- */
  .tableau-cadre {
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    overflow: hidden;
  }

  .tableau {
    width: 100%;
    font-size: var(--jobcrible-t-15);
  }

  .tableau caption {
    text-align: left;
  }

  .tableau th {
    text-align: left;
    font-size: var(--jobcrible-t-13);
    font-weight: 600;
    color: var(--jobcrible-texte-2);
    padding: var(--jobcrible-e-2) var(--jobcrible-e-4);
    white-space: nowrap;
    position: sticky;
    top: 0;
    background: var(--jobcrible-surface);
  }

  /* S4-U2 (revue-ui, écran 01) : une durée relative (« à l'instant », « il y a 2 jours ») ne
     doit jamais se plier, contrairement au nom d'un candidat ou d'un poste (colonnes qui, elles,
     peuvent légitimement être longues) — `data-libelle` (déjà posé par _tableau.html pour la
     vue mobile ci-dessous) identifie la colonne sans coupler ce composant générique à un
     tableau en particulier. */
  .tableau td[data-libelle="Depuis"] {
    white-space: nowrap;
  }

  .tableau th.droite {
    text-align: right;
  }

  .tableau td {
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    border-top: 1px solid var(--jobcrible-separateur);
  }

  .tableau tbody tr:hover {
    background: var(--jobcrible-accent-pale);
  }

  .tableau td.nom {
    font-weight: 600;
  }

  .tableau td.nom a {
    display: flex;
    flex-direction: column;
    gap: 2px;
    color: var(--jobcrible-texte);
    text-decoration: none;
  }

  /* Fiche 02 (S4-U3) : client final sous le titre du poste, en secondaire — jamais montré côté
     candidat (CLAUDE.md). */
  .tableau td.nom .client {
    font-size: var(--jobcrible-t-13);
    font-weight: 500;
    color: var(--jobcrible-texte-2);
  }

  .droite {
    text-align: right;
  }

  .tableau .chiffre-lien {
    display: inline-flex;
    justify-content: flex-end;
    min-width: 32px;
    min-height: 32px;
    align-items: center;
    padding: 0 var(--jobcrible-e-1);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .tableau .chiffre-zero {
    color: var(--jobcrible-texte-2);
    font-variant-numeric: tabular-nums;
  }

  /* Fiche 04 (S4-U3) : « Correspondance au poste » — le mot d'abord (gras, coloré), le chiffre
     ensuite (atténué, sous le mot) — un texte simple, jamais une pastille pilule (`{% badge %}`
     reste réservé aux ÉTATS). Couleurs mot pour mot sur la maquette validée
     (`ecran-04-fiche-poste.html`) : Très bonne/Bonne en succès (même teinte pour les deux),
     Partielle en texte par défaut, Insuffisante atténuée. */
  .correspondance {
    display: block;
    font-size: var(--jobcrible-t-14);
    font-weight: 600;
    color: var(--jobcrible-texte);
  }

  .correspondance--positive {
    color: var(--jobcrible-succes);
  }

  .correspondance--attenue {
    color: var(--jobcrible-texte-2);
  }

  .correspondance-chiffre {
    display: block;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    font-variant-numeric: tabular-nums;
  }

  /* Téléphone seulement (fiche 04) : « Afficher les N suivantes » remplace le pager complet —
     visible seulement sous 640px, voir `@media (width < 640px)` plus bas qui le passe en
     `inline-flex` et masque `.pagination-controles`. */
  .lien-suivantes-tel {
    display: none;
  }

  .tableau-pied {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    border-top: 1px solid var(--jobcrible-separateur);
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  .pagination-controles {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
  }

  .pagination-nav {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding-inline: var(--jobcrible-e-3);
    border-radius: var(--jobcrible-r-controle);
    border: 1px solid var(--jobcrible-accent);
    color: var(--jobcrible-accent);
    font-weight: 600;
  }

  .pagination-nav[aria-disabled="true"] {
    border-color: var(--jobcrible-bordure);
    color: var(--jobcrible-texte-2);
    opacity: 0.6;
  }

  /* -- filtres ---------------------------------------------------------------------------- */
  .filtres {
    display: flex;
    gap: var(--jobcrible-e-2);
    flex-wrap: wrap;
  }

  .filtre {
    display: inline-flex;
    align-items: center;
    gap: var(--jobcrible-e-2);
    min-height: 36px;
    padding-inline: var(--jobcrible-e-3);
    border-radius: var(--jobcrible-r-controle);
    font-size: var(--jobcrible-t-14);
    font-weight: 600;
    background: var(--jobcrible-surface);
    color: var(--jobcrible-texte);
    border: 1px solid var(--jobcrible-bordure);
  }

  .filtre .filtre-compteur {
    font-weight: 500;
    color: var(--jobcrible-texte-2);
  }

  .filtre--actif {
    background: var(--jobcrible-accent-pale);
    color: var(--jobcrible-accent);
    border-color: var(--jobcrible-accent);
  }

  .filtre--actif .filtre-compteur {
    color: var(--jobcrible-accent);
  }

  /* Fiches 02/04 (S4-U3) : ligne filtres + recherche, séparée du tableau par un trait — même
     motif que `.en-tete-page`, jamais un deuxième composant « barre » dédié. */
  .filtres-barre {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--jobcrible-e-3);
    padding-block-end: var(--jobcrible-e-3);
    margin-block-end: var(--jobcrible-e-4);
    border-bottom: 1px solid var(--jobcrible-bordure);
  }

  .recherche-postes {
    width: 100%;
    max-width: 20rem;
  }

  .champ-recherche {
    display: block;
  }

  /* -- onglets ------------------------------------------------------------------------- */
  .onglets {
    display: flex;
    gap: var(--jobcrible-e-5);
    border-bottom: 1px solid var(--jobcrible-bordure);
    overflow-x: auto;
  }

  .onglet {
    display: inline-flex;
    align-items: center;
    gap: var(--jobcrible-e-2);
    padding-inline: var(--jobcrible-e-1);
    min-height: 40px;
    color: var(--jobcrible-texte-2);
    font-weight: 500;
    border-bottom: 2px solid transparent;
  }

  .onglet[aria-selected="true"] {
    color: var(--jobcrible-texte);
    font-weight: 600;
    border-bottom-color: var(--jobcrible-accent);
  }

  .onglet-compteur {
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    font-weight: 500;
  }

  /* -- dialogue --------------------------------------------------------------------------- */
  .dialogue {
    width: 480px;
    max-width: calc(100% - var(--jobcrible-e-4));
    box-sizing: border-box;
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    padding: var(--jobcrible-e-6) var(--jobcrible-e-6) var(--jobcrible-e-5);
    color: var(--jobcrible-texte);
  }

  /* Fiche 08 (S4-U3) : dialogue « Transmettre le dossier » — résumé (zone de texte), case,
     trois radios, plus haut que `.dialogue` par défaut. */
  .dialogue--large {
    width: 560px;
  }

  .dialogue--large textarea {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
  }

  .dialogue--large fieldset {
    border: none;
    padding: 0;
    margin: var(--jobcrible-e-3) 0;
  }

  .dialogue--large fieldset label {
    display: block;
    margin-block-end: var(--jobcrible-e-2);
  }

  .dialogue-titre {
    margin: 0 0 var(--jobcrible-e-3) 0;
  }

  .dialogue-texte {
    margin: 0 0 var(--jobcrible-e-5) 0;
    line-height: 1.6;
  }

  .dialogue-actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--jobcrible-e-2);
  }

  /* -- états vides ----------------------------------------------------------------------- */
  .vide {
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    padding: var(--jobcrible-e-6);
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
  }

  /* S4-U2 (revue-ui, écran 01) : la maquette (ecran-01-dashboard-vide) limite ce bloc à 720px
     (lisibilité du paragraphe) plutôt que de l'étirer pleine largeur — écart de largeur relative
     mesuré (règle d). Scopé à `#tableau-de-bord` (jamais `.vide` globalement, dont les deux
     autres cas — spec 12 § A.4 — n'ont pas été vérifiés contre leur propre maquette ici). */
  /* Fiche 06 (S4-U3, `ecran-06-a-traiter-vide`) : MÊME largeur que l'état vide du tableau de
     bord (720px, lisibilité du paragraphe) — classe partagée plutôt qu'un second sélecteur scopé
     par id, pour ne pas répéter la valeur à chaque nouvel écran qui aurait le même besoin. */
  #tableau-de-bord .vide,
  .vide--etroit {
    max-width: 720px;
  }

  .vide-entete {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
  }

  .vide--positif .vide-entete {
    color: var(--jobcrible-succes);
  }

  /* -- menu ----------------------------------------------------------------------------- */
  .menu {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: var(--jobcrible-menu);
    flex-shrink: 0;
    padding: var(--jobcrible-e-3);
    background: var(--jobcrible-surface);
    border-inline-end: 1px solid var(--jobcrible-bordure);
  }

  .menu--replie {
    width: var(--jobcrible-menu-replie);
    align-items: center;
  }

  .menu-marque {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-1) var(--jobcrible-e-2) var(--jobcrible-e-4);
  }

  .menu-badge {
    width: 32px;
    height: 32px;
    border-radius: var(--jobcrible-r-controle);
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: var(--jobcrible-t-13);
    flex-shrink: 0;
  }

  .menu-repli {
    border: 0;
    background: transparent;
    cursor: pointer;
    color: var(--jobcrible-texte-2);
    padding: var(--jobcrible-e-2);
    align-self: flex-end;
  }

  .menu-lien {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    padding: 9px var(--jobcrible-e-3);
    border-radius: var(--jobcrible-r-controle);
    color: var(--jobcrible-texte);
    font-weight: 500;
    min-height: 40px;
  }

  .menu-lien[aria-current="page"] {
    background: var(--jobcrible-accent-pale);
    color: var(--jobcrible-accent);
    font-weight: 600;
  }

  /* S4-U2 (revue-ui, écran 01) : `.menu-lien` porte aussi bien des `<a>` (la plupart) que le
     bouton « Se déconnecter » (`<form><button>`, seule façon de soumettre une déconnexion) —
     un `<button>` garde ses styles par défaut (bordure, fond, police) tant qu'ils ne sont pas
     réinitialisés explicitement ; un `<a>` n'en a aucun à annuler. Sans ce reset, ce seul lien
     du menu ressort comme un bouton bordé au lieu d'une entrée de menu comme les autres
     (maquette : icône + libellé, rien d'autre). */
  button.menu-lien {
    width: 100%;
    border: 0;
    background: transparent;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .menu-sous-lien {
    padding-inline-start: 42px;
  }

  .menu-compteur {
    margin-inline-start: auto;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    font-weight: 500;
  }

  .menu-compteur--rond {
    background: var(--jobcrible-compteur);
    color: var(--jobcrible-surface);
    border-radius: 999px;
    padding: 1px var(--jobcrible-e-2);
    font-size: 0.75rem;
    font-weight: 700;
  }

  .menu-pied {
    margin-top: var(--jobcrible-e-3);
    padding-top: var(--jobcrible-e-3);
    border-top: 1px solid var(--jobcrible-bordure);
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  .menu--replie .menu-lien {
    width: 44px;
    height: 44px;
    justify-content: center;
    padding: 0;
  }

  .menu--replie .menu-label,
  .menu--replie .menu-sous-lien,
  .menu--replie .menu-compteur {
    display: none;
  }

  /* -- barre (téléphone) ------------------------------------------------------------------ */
  .barre {
    display: none;
    align-items: center;
    gap: var(--jobcrible-e-3);
    height: 56px;
    padding-inline: var(--jobcrible-e-4);
    border-bottom: 1px solid var(--jobcrible-bordure);
    background: var(--jobcrible-surface);
  }

  .barre-bas {
    display: none;
    align-items: stretch;
    height: 64px;
    padding-inline: var(--jobcrible-e-1);
    border-top: 1px solid var(--jobcrible-bordure);
    background: var(--jobcrible-surface);
    position: sticky;
    bottom: 0;
  }

  .barre-bas a {
    position: relative;
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--jobcrible-e-1);
    color: var(--jobcrible-texte-2);
    font-size: 0.6875rem;
    font-weight: 500;
  }

  .barre-bas a[aria-current="page"] {
    color: var(--jobcrible-accent);
    font-weight: 600;
  }

  .barre-bas .menu-compteur--rond {
    position: absolute;
    top: 6px;
    left: calc(50% + 6px);
    min-width: 16px;
    height: 16px;
    font-size: 0.625rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 4px;
  }

  /* -- composants de parcours -------------------------------------------------------------- */
  .fil-etapes {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    overflow-x: auto;
  }

  .fil-etapes li {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-2);
  }

  /* Trait de connexion entre deux étapes : pseudo-élément plutôt qu'un `<li>` décoratif — un
     `<ol>` ne doit contenir que ses vrais éléments (spec 12 § A.4, composant « fil d'étapes »),
     jamais un nœud supplémentaire qui fausserait un `:nth-child`/le compte des étapes. */
  .fil-etapes li:not(:first-child)::before {
    content: "";
    display: inline-block;
    width: 32px;
    height: 1px;
    flex-shrink: 0;
    background: var(--jobcrible-bordure-champ);
    margin-inline-end: var(--jobcrible-e-2);
  }

  .fil-etapes-rond {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--jobcrible-t-13);
    font-weight: 700;
    border: 1px solid var(--jobcrible-bordure-champ);
    background: var(--jobcrible-surface);
    color: var(--jobcrible-texte-2);
  }

  .fil-etapes li.etape--faite .fil-etapes-rond,
  .fil-etapes li.etape--courante .fil-etapes-rond {
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    border-color: var(--jobcrible-accent);
  }

  .fil-etapes li.etape--courante span:last-child {
    color: var(--jobcrible-texte);
    font-weight: 600;
  }

  .fil-etapes li:not(.etape--courante):not(.etape--faite) span:last-child {
    color: var(--jobcrible-texte-2);
  }

  /* Fiche 03 (S4-U3) : barre de boutons de bas de formulaire (Retour/Enregistrer/Continuer) —
     défile horizontalement sur téléphone plutôt que d'empiler trois boutons pleine largeur
     (cas admis, composant Onglets et filtres § 4 : même principe que `.filtres.defile-x`). */
  .barre-boutons {
    display: flex;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  .fil-ariane {
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
    display: flex;
    gap: var(--jobcrible-e-2);
  }

  .fil-ariane a {
    color: var(--jobcrible-texte-2);
  }

  .fil-ariane [aria-current="page"] {
    color: var(--jobcrible-texte-2);
  }

  .progression-ligne {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  progress.progression-piste {
    flex-grow: 1;
    appearance: none;
    border: none;
    width: 100%;
    height: 6px;
    border-radius: 3px;
    background: var(--jobcrible-separateur);
    overflow: hidden;
  }

  progress.progression-piste::-webkit-progress-bar {
    background: var(--jobcrible-separateur);
    border-radius: 3px;
  }

  progress.progression-piste::-webkit-progress-value {
    background: var(--jobcrible-accent);
    border-radius: 3px;
    transition: none;
  }

  progress.progression-piste::-moz-progress-bar {
    background: var(--jobcrible-accent);
    border-radius: 3px;
  }

  .chargement {
    display: flex;
    gap: var(--jobcrible-e-3);
    align-items: center;
    padding: var(--jobcrible-e-4) var(--jobcrible-e-5);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    background: var(--jobcrible-surface);
  }

  .chargement .icon {
    color: var(--jobcrible-accent);
    animation: jobcrible-roue 900ms linear infinite;
  }

  .question-repliable {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
  }

  .question-repliable--a_venir {
    border-style: dashed;
  }

  .question-repliable-entete {
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-3);
  }

  .question-repliable-numero {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--jobcrible-bordure-champ);
    color: var(--jobcrible-texte-2);
  }

  .question-repliable--repondue .question-repliable-numero {
    background: var(--jobcrible-accent);
    color: var(--jobcrible-surface);
    border-color: var(--jobcrible-accent);
  }

  .question-repliable-resume {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--jobcrible-e-3);
    padding-inline-start: 36px;
  }

  .question-repliable-debut {
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
  }

  .bandeau-decision {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
    padding: var(--jobcrible-e-4) var(--jobcrible-e-5);
    border: 1px solid;
    border-radius: var(--jobcrible-r-cadre);
  }

  .bandeau-decision-actions {
    display: flex;
    gap: var(--jobcrible-e-2);
    flex-wrap: wrap;
  }

  .bandeau--reexamen {
    border-color: var(--jobcrible-reexamen);
    background: var(--jobcrible-reexamen-fond);
  }

  .bandeau--reexamen .bandeau-decision-titre {
    color: var(--jobcrible-reexamen);
  }

  .bandeau--rejet_a_valider {
    border-color: var(--jobcrible-attention);
    background: var(--jobcrible-attention-fond);
  }

  .bandeau--rejet_a_valider .bandeau-decision-titre {
    color: var(--jobcrible-attention);
  }

  .bandeau--qualifiee {
    border-color: var(--jobcrible-succes);
    background: var(--jobcrible-succes-fond);
  }

  .bandeau--qualifiee .bandeau-decision-titre {
    color: var(--jobcrible-succes);
  }

  .bandeau-decision-titre {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    margin: 0;
  }

  .bandeau-decision-texte {
    font-size: var(--jobcrible-t-14);
    margin: 0;
  }

  /* Fiche 05 (S4-U3) : classes RÉELLEMENT posées par `application_detail.html`
     (`bandeau-decision bandeau-decision--<etat>`) — distinctes de `bandeau--<etat>` ci-dessus
     (composant `_bandeau_decision.html`, jamais inclus nulle part, laissé tel quel). Mêmes
     jetons de couleur que les trois autres écrans qui parlent déjà de réexamen/attention/succès
     (`--jobcrible-reexamen`, `--jobcrible-attention`, `--jobcrible-succes`). */
  .bandeau-decision--reexamen {
    border-color: var(--jobcrible-reexamen);
    background: var(--jobcrible-reexamen-fond);
  }

  .bandeau-decision--reexamen .bandeau-decision-titre {
    color: var(--jobcrible-reexamen);
  }

  .bandeau-decision--attention {
    border-color: var(--jobcrible-attention);
    background: var(--jobcrible-attention-fond);
  }

  .bandeau-decision--attention .bandeau-decision-titre {
    color: var(--jobcrible-attention);
  }

  .bandeau-decision--succes {
    border-color: var(--jobcrible-succes);
    background: var(--jobcrible-succes-fond);
  }

  .bandeau-decision--succes .bandeau-decision-titre {
    color: var(--jobcrible-succes);
  }

  /* -- fiche candidature (fiche 05, S4-U3) ------------------------------------------------- */
  .resume {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    text-align: end;
    flex-shrink: 0;
  }

  .resume-mot {
    font-size: var(--jobcrible-t-15);
    font-weight: 600;
    color: var(--jobcrible-succes);
  }

  .resume-detail {
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    font-variant-numeric: tabular-nums;
  }

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

  .critere {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    padding-block: var(--jobcrible-e-3);
    border-top: 1px solid var(--jobcrible-separateur);
  }

  .critere-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  .critere-nom {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-2);
  }

  .critere-nom strong {
    font-size: var(--jobcrible-t-15);
  }

  .critere-resultat {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-2);
  }

  .critere-points {
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
    font-variant-numeric: tabular-nums;
  }

  /* `<progress>` natif (S4-U3, fiche 05) — jamais une largeur en style inline (spec 13 § 1) :
     `value`/`max` portent le pourcentage, la couleur de remplissage vient du modificateur posé
     sur le `<li>` englobant (`.critere--partiel`/`--non-couvert`), comme `.progression-piste`
     (composant partagé) mais avec trois couleurs plutôt qu'une seule — jamais fusionné avec lui,
     qui reste à un seul usage (accent) ailleurs. */
  progress.critere-jauge {
    appearance: none;
    border: none;
    width: 100%;
    height: 6px;
    border-radius: 3px;
    background: var(--jobcrible-separateur);
    overflow: hidden;
  }

  progress.critere-jauge::-webkit-progress-bar {
    background: var(--jobcrible-separateur);
    border-radius: 3px;
  }

  progress.critere-jauge::-webkit-progress-value {
    background: var(--jobcrible-succes);
    border-radius: 3px;
    transition: none;
  }

  progress.critere-jauge::-moz-progress-bar {
    background: var(--jobcrible-succes);
    border-radius: 3px;
  }

  .critere--partiel progress.critere-jauge::-webkit-progress-value,
  .critere--partiel progress.critere-jauge::-moz-progress-bar {
    background: var(--jobcrible-attention);
  }

  .critere--non-couvert progress.critere-jauge::-webkit-progress-value,
  .critere--non-couvert progress.critere-jauge::-moz-progress-bar {
    background: var(--jobcrible-danger);
  }

  .extrait {
    display: flex;
    gap: var(--jobcrible-e-2);
    align-items: flex-start;
    padding: var(--jobcrible-e-2) var(--jobcrible-e-3);
    background: var(--jobcrible-fond);
    border-radius: var(--jobcrible-r-controle);
    margin: 0;
  }

  .extrait-texte {
    font-size: var(--jobcrible-t-14);
    line-height: 1.5;
  }

  .critere-reponse {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
  }

  .critere-historique {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--jobcrible-e-2);
    margin: 0;
  }

  .extrait-source {
    display: block;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }

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

  .reponse {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
    padding-block: var(--jobcrible-e-3);
    border-top: 1px solid var(--jobcrible-separateur);
  }

  .reponse-question {
    font-size: var(--jobcrible-t-14);
    font-weight: 600;
    color: var(--jobcrible-texte-2);
  }

  .reponse-entiere {
    margin: 0;
  }

  /* Fiche 05 (S4-U3) : pastille d'état + date de dépôt, remplace `.en-tete-page` sur téléphone
     (voir le modificateur `.masque-mobile` en `mise-en-page`) — masqué par défaut, ce bloc n'a
     de sens qu'à cette largeur. */
  .contexte-mobile {
    display: none;
  }

  .chronologie {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  .chronologie li {
    display: flex;
    gap: var(--jobcrible-e-3);
    align-items: flex-start;
    padding-block: var(--jobcrible-e-2);
  }

  .chronologie-puce {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--jobcrible-texte-3);
    flex-shrink: 0;
    margin-block-start: 6px;
  }

  .chronologie-corps {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
    min-width: 0;
  }

  .chronologie-quand {
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }

  .chronologie-citation {
    font-size: var(--jobcrible-t-14);
    line-height: 1.5;
    padding: var(--jobcrible-e-2) var(--jobcrible-e-3);
    background: var(--jobcrible-reexamen-fond);
    border-radius: var(--jobcrible-r-controle);
    margin: 0;
  }

  /* -- icônes --------------------------------------------------------------------------- */
  .icon {
    width: 20px;
    height: 20px;
    stroke-width: 1.75;
    flex-shrink: 0;
  }

  .icon--18 {
    width: 18px;
    height: 18px;
  }

  .icon--24 {
    width: 24px;
    height: 24px;
  }

  .icon--36 {
    width: 36px;
    height: 36px;
  }
}

@layer mise-en-page {
  .pile {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-4);
  }

  .grappe {
    display: flex;
    flex-wrap: wrap;
    gap: var(--jobcrible-e-3);
  }

  /* Écran 03 (S4-U3) : champs les uns sous les autres (formulaires de la création de poste) —
     l'écart entre deux groupes est aussi la marge qui absorbe un message d'erreur flottant
     (`.champ-erreur--flottante`) sans jamais recouvrir le champ suivant. */
  .grappe-verticale {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-6);
  }

  /* Fiche 03 (S4-U3, maquettes `ecran-03*`) : le fil d'étapes et son formulaire restent
     plafonnés, jamais la pleine largeur de `.contenu` (règle d de la revue mécanique) — une
     grille de cinq critères sur toute la largeur du contenu ordinateur (1240px) serait plus
     difficile à balayer d'un regard, pas plus lisible. Gap propre (20px, règle c) plutôt que
     `.grappe-verticale` (32px, hors tolérance ±8px mesurée ici). */
  .assistant-etapes {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
    max-width: var(--jobcrible-assistant-max);
  }

  /* Fiche 03 (S4-U3, maquettes `ecran-03*`) : une étape du poste = une carte, titrée (h2) et
     sous-titrée, jamais un formulaire nu — `.carte` seule seule ne prévoit pas ce bloc titre
     empilé (elle sert aussi à des cartes sans titre, ex. `.carte-chiffre`). */
  .carte-etape {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
  }

  .carte-etape-entete {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
  }

  .carte-etape-entete h2 {
    margin: 0;
    font-size: var(--jobcrible-t-17);
    font-weight: 600;
  }

  .carte-etape-entete p {
    margin: 0;
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  /* Fiche 04 (S4-U3), section Suivi : un délégué = nom, puis son droit en dessous (maquette
     `ecran-04-reglages.html`) — jamais sur la même ligne, jamais un pastille (un droit n'est pas
     un état). */
  #delegues li {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
    padding-block: var(--jobcrible-e-2);
    border-top: 1px solid var(--jobcrible-separateur);
  }

  #delegues li:first-child {
    border-top: 0;
  }

  .delegue-nom {
    font-weight: 600;
  }

  .delegue-droit {
    font-size: var(--jobcrible-t-14);
    color: var(--jobcrible-texte-2);
  }

  /* Fiche 03 (S4-U3, maquette ecran-03-nouveau-poste) : Client final/Type de contrat/Lieu/
     Télétravail par paires — jamais empilés un par un sur ordinateur (repassent à une colonne
     sous 640px, comme tout le reste de l'écran 03, règle ci-dessous). */
  .grille-champs-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--jobcrible-e-5);
  }

  /* Fiche 03 (S4-U3) : adresse de l'annonce — une URL complète, sans espace, déborderait le
     conteneur d'une largeur qui varie avec `public_id` (aléatoire, ADR-0014 étendue D2) plutôt
     que de se couper : constaté aux captures téléphone (largeur instable d'une passe à l'autre).
     `overflow-wrap: anywhere` autorise la coupure n'importe où plutôt que d'étendre la page. */
  .url-longue {
    overflow-wrap: anywhere;
  }

  .contenu {
    max-width: var(--jobcrible-contenu-max);
    margin-inline: auto;
    padding-block-start: var(--jobcrible-e-6);
    padding-inline: var(--jobcrible-e-6);
  }

  .deux-colonnes {
    display: grid;
    /* S4-U2 (revue-ui, écran 01) : la maquette (ecran-01-dashboard) partage les deux colonnes
       3fr/2fr (~60/40 %), pas une colonne droite figée à 320px — la largeur relative de la
       colonne gauche s'en écartait de plus de 15 % (règle d). */
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    gap: var(--jobcrible-e-6);
    align-items: start;
  }

  /* Fiche 05 (S4-U3) : colonne évaluation/pourquoi/réponses contre colonne candidat/chronologie
     — ratio propre à cette fiche (maquette ecran-05-candidature : 3fr/1.4fr, plus resserré que
     `.deux-colonnes` ci-dessus), jamais réutilisé ici pour ne pas coupler les deux écrans. */
  .fiche-candidature {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 1.4fr);
    gap: var(--jobcrible-e-5);
    align-items: start;
  }

  .fiche-candidature-colonne {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-4);
  }

  .grille-chiffres {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--jobcrible-e-5);
    /* S4-U2 (revue-ui, écran 01) : `#tableau-de-bord` (app_home.html) enchaîne les cartes de
       chiffres et `.deux-colonnes` sans aucun espacement CSS — la maquette (ecran-01-dashboard)
       en met 24 px, comme `.en-tete-page` le fait déjà pour le bloc au-dessus (margin-block-end
       ci-dessous) plutôt qu'un `gap` porté par un conteneur flex qui n'existe pas ici. */
    margin-block-end: var(--jobcrible-e-5);
  }

  .disposition-app {
    display: flex;
    align-items: stretch;
    min-height: 100vh;
  }

  .contenu-app {
    flex: 1 1 auto;
    min-width: 0;
  }

  .en-tete-page {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--jobcrible-e-4);
    margin-block-end: var(--jobcrible-e-6);
  }

  /* Fiche 02 (S4-U3) : l'en-tête de « Postes en cours »/« Brouillons » colle plus près du
     contenu que sur le tableau de bord (maquettes ecran-02-*, revue mécanique règle c, cible
     20 px desktop/14 px téléphone contre les 32 px par défaut ci-dessus) — modificateur plutôt
     qu'un changement de la règle partagée, qui resterait correcte pour l'écran 01. Marge à 0 :
     l'espace visuel restant (~14-20 px, mesuré par la revue) vient déjà de la hauteur de ligne
     du texte du contexte et du rembourrage du bloc suivant, pas d'une marge supplémentaire.
     Sélecteur à DEUX classes (`.en-tete-page.en-tete-page--serre`, spécificité 0,2,0) : la règle
     de `.en-tete-page` sous `@media (width < 1024px)` plus bas dans la feuille a la MÊME
     spécificité qu'un modificateur à une seule classe et la battrait par ordre source sur petit
     écran — jamais une déclaration forcée pour trancher ce genre d'égalité. */
  .en-tete-page.en-tete-page--serre {
    margin-block-end: 0;
  }

  .en-tete-page-texte {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
  }

  /* Fiche 04 : titre + pastille d'état sur la même ligne — la pastille reste un ÉLÉMENT FRÈRE du
     h1 (jamais un descendant : le texte accessible du titre doit rester le titre seul, pas
     « Développeur Python senior En cours »), ce conteneur les remet côte à côte visuellement. */
  .titre-ligne {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  .titre-ligne h1 {
    margin: 0;
  }

  .en-tete-page .contexte {
    font-size: var(--jobcrible-t-15);
    color: var(--jobcrible-texte-2);
    margin: 0;
  }

  @media (width < 1024px) {
    .contenu {
      padding-inline: var(--jobcrible-e-5);
    }

    .deux-colonnes {
      grid-template-columns: minmax(0, 1fr);
    }

    .grille-chiffres {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (width < 640px) {
    .contenu {
      padding-inline: var(--jobcrible-e-4);
      padding-block-start: var(--jobcrible-e-4);
    }

    /* S4-U2 (revue-ui, écran 01) : la maquette téléphone (ecran-01-dashboard-tel) espace ses
       blocs de 16px (fondations §4, « marges de page sur téléphone »), pas 32px comme sur
       ordinateur (règle c, écart mesuré > 8px). */
    .en-tete-page {
      margin-block-end: var(--jobcrible-e-4);
    }

    .grille-chiffres {
      grid-template-columns: minmax(0, 1fr);
    }

    .grille-champs-2 {
      grid-template-columns: minmax(0, 1fr);
    }

    /* Tableau de bord (spec 12 § B.1, fiche 01) : deux cartes seulement sous 640 px (À
     * traiter, Qualifiés) — les deux autres masquées, côte à côte plutôt qu'empilées comme le
     * réglage générique ci-dessus. */
    .grille-chiffres.grille-chiffres--tableau-de-bord {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .carte-chiffre--secondaire {
      display: none;
    }

    .en-tete-page {
      flex-direction: column;
    }

    /* Fiche 05 (S4-U3) : sur téléphone, le nom du candidat vit SEUL dans la barre mobile
       (`{% block titre_page %}`, `base_app.html`) — maquette `ecran-05-candidature-tel.html`,
       qui pose un en-tête compact hors du contenu (nom, jamais un <h1> à cette largeur : la
       barre en tient lieu) et garde en page la pastille d'état et la date de dépôt seules,
       jamais le nom une seconde fois. `display: none` sur le bloc ENTIER (pas seulement le
       <h1>) : la revue mécanique trouve le titre d'un bloc par `querySelector`, qui ne regarde
       pas la visibilité de ce qu'il trouve — seul un bloc dont la BOÎTE elle-même disparaît
       (0×0) sort de la comparaison (constaté en écrivant cette tranche : masquer le <h1> seul
       laissait « camille rousseau » comme titre du bloc, trouvé quand même à l'intérieur).
       `.contexte-mobile`, son remplaçant compact (pastille + date, aucun titre h1-h3 dedans,
       fidèle à la maquette), est cette fois posé en dehors, pas descendant de ce bloc masqué.
       Modificateurs posés sur CETTE fiche seule (jamais nus, partagés par d'autres écrans qui
       n'ont pas substitué la barre). */
    .masque-mobile {
      display: none;
    }

    .contexte-mobile {
      display: flex;
      align-items: center;
      gap: var(--jobcrible-e-3);
    }

    .carte {
      padding: var(--jobcrible-e-4);
    }

    .menu {
      display: none;
    }

    /* Fiche 03 (S4-U3) : fil d'étapes réduit aux numéros sur téléphone (hauteur ≤ 56px) — le
       libellé reste lisible par un lecteur d'écran (même motif que `.masque-visuellement`, pas
       la classe elle-même : le texte reste dans le flux normal au-delà de ce point de rupture). */
    .fil-etapes li {
      position: relative;
    }

    .fil-etapes li span:last-child {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }

    .barre-boutons {
      flex-wrap: nowrap;
      overflow-x: auto;
    }

    .barre-boutons .bouton {
      flex-shrink: 0;
    }

    /* `.disposition-app` reste une rangée (sidebar + contenu) au-dessus de 640px ; en dessous,
     * la sidebar disparaît (`.menu` ci-dessus) et `.barre`/`.barre-bas` en deviennent les
     * éléments de flux — sans passer en colonne, ils resteraient des éléments de rangée
     * dimensionnés à leur contenu (`flex-basis: auto`), écrasant la largeur de `.contenu-app`
     * au lieu de s'empiler pleine largeur au-dessus et en dessous. */
    .disposition-app {
      flex-direction: column;
    }

    .barre {
      display: flex;
    }

    .barre-bas {
      display: flex;
    }

    body:has(.barre-bas) .contenu {
      padding-block-end: var(--jobcrible-e-6);
    }

    /* Un tableau devient une liste de cartes rendue par le SERVEUR, jamais un second DOM
     * masqué (spec 13 § 4.2) : la même ligne <tr> passe simplement en grille. */
    .tableau thead {
      position: absolute;
      width: 1px;
      height: 1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
    }

    .tableau tbody tr {
      display: grid;
      gap: var(--jobcrible-e-1);
      padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    }

    .tableau td {
      display: flex;
      align-items: baseline;
      justify-content: space-between;
      gap: var(--jobcrible-e-3);
      padding: var(--jobcrible-e-1) 0;
      border-top: 0;
      text-align: left;
    }

    .tableau td::before {
      content: attr(data-libelle);
      font-size: var(--jobcrible-t-13);
      font-weight: 600;
      color: var(--jobcrible-texte-2);
      flex-shrink: 0;
    }

    .bouton {
      min-height: 44px;
    }

    /* Fiches 09/10 : reste à 48 px même sous cette règle (la règle générale ci-dessus voulait
       gagner ici par ORDRE de source malgré la spécificité composée plus haute dans la feuille —
       constaté en écrivant cette tranche) — redéclarée ICI, dans le même bloc, pour ne plus
       dépendre de l'ordre entre deux `@media`. */
    .bouton.bouton--48 {
      min-height: 48px;
    }

    .barre-bas-defile,
    .filtres.defile-x {
      overflow-x: auto;
    }

    .dialogue {
      width: 100%;
    }

    /* Fiche 05 (S4-U3) : les deux colonnes de la fiche candidature s'empilent dans l'ordre du
       DOM (bandeau, puis colonne évaluation, puis colonne candidat/chronologie) — jamais
       réordonnées en CSS, la revue mécanique et le lecteur d'écran doivent voir le même ordre.
       Boutons du bandeau : au moins 48px de haut et pleine largeur (loi de Fitts, cible
       fréquente) plutôt que les 44px génériques ci-dessus — empilés, jamais côte à côte, deux
       boutons à 50% de la largeur de l'écran retombant sous les 300px attendus. Sélecteur
       scopé aux TROIS modificateurs d'état réels (`bandeau-decision--reexamen`/`--attention`/
       `--succes`, posés par `application_detail.html`), jamais `.bandeau-decision-actions` nu :
       cette classe est partagée avec le composant `_bandeau_decision.html` (catalogue de
       démonstration, `bandeau--{{ etat }}` à UN seul tiret, jamais branché ailleurs) — un
       sélecteur nu grandissait aussi SES boutons, gonflant la capture du catalogue sans rapport
       avec cette fiche (constaté en écrivant cette tranche). */
    .fiche-candidature {
      grid-template-columns: minmax(0, 1fr);
    }

    .bandeau-decision--reexamen .bandeau-decision-actions,
    .bandeau-decision--attention .bandeau-decision-actions,
    .bandeau-decision--succes .bandeau-decision-actions {
      flex-direction: column;
    }

    .bandeau-decision--reexamen .bandeau-decision-actions .bouton,
    .bandeau-decision--attention .bandeau-decision-actions .bouton,
    .bandeau-decision--succes .bandeau-decision-actions .bouton {
      min-height: var(--jobcrible-e-7);
      width: 100%;
    }

    /* Fiche 04, carte téléphone (maquette `ecran-04-fiche-poste-tel.html`) : le mot et le
       chiffre de correspondance tiennent sur UNE ligne (« Très bonne correspondance · 86 sur
       100 »), contrairement au tableau ordinateur qui les empile — même donnée, deux mises en
       forme. */
    .correspondance,
    .correspondance-chiffre {
      display: inline;
    }

    .correspondance-chiffre::before {
      content: " · ";
    }

    /* Fiche 04 : « Afficher les N suivantes » remplace le pager complet sur téléphone — SCOPÉ à
       `#candidatures` (constaté en écrivant cette tranche : `.pagination-controles` est une
       classe PARTAGÉE, `components/_pagination.html`, fiche 02 — une règle non scopée masquait
       aussi son propre pager sur l'écran 02). */
    #candidatures .pagination-controles {
      display: none;
    }

    .lien-suivantes-tel {
      display: inline-flex;
      align-items: center;
      min-height: 44px;
    }
  }

  /* Dossier de qualification (base_print.html, fiche 08, S4-U3) : page façon document, largeur
     fixe centrée — jamais fluide, à la différence du reste de l'interface (maquette 794 px,
     docs/ux/maquettes/ecrans/ecran-08-dossier.html). Scopé à `.page-dossier`/`.feuille`, posées
     UNIQUEMENT par `base_print.html` (jamais `base_app.html`) : aucun risque de fuite vers les
     autres écrans. */
  .page-dossier {
    margin: 0;
    background: var(--jobcrible-fond);
  }

  .feuille {
    max-width: 42rem;
    margin-inline: auto;
    padding: var(--jobcrible-e-7) var(--jobcrible-e-6);
    background: var(--jobcrible-surface);
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
  }

  .feuille > header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--jobcrible-e-4);
    padding-bottom: var(--jobcrible-e-4);
    border-bottom: 2px solid var(--jobcrible-texte);
  }

  .dossier-entete-organisation {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-1);
  }

  .dossier-entete-organisation p {
    margin: 0;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }

  .dossier-entete-titre {
    margin: 0;
    font-size: var(--jobcrible-t-13);
    font-weight: 400;
    color: var(--jobcrible-texte-2);
    text-align: right;
    flex-shrink: 0;
  }

  .feuille > main {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
  }

  .feuille > main > section,
  .feuille > main > .dossier-poste,
  .dossier-grille-2 > div {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
  }

  .feuille > main h2 {
    margin: 0;
    font-size: var(--jobcrible-t-17);
    font-weight: 600;
  }

  /* Jamais de capitales forcées par CSS (invariant `test_aucun_titre_en_capitales`, lisibilité/
     RGAA) : la distinction avec les autres h2 passe par la taille et la couleur seules. */
  .dossier-poste h2#h-poste {
    font-size: var(--jobcrible-t-13);
    letter-spacing: 0.02em;
    color: var(--jobcrible-texte-2);
    font-weight: 600;
  }

  .dossier-poste-titre {
    margin: 0;
    font-size: var(--jobcrible-t-32);
    font-weight: 600;
    line-height: 1.2;
  }

  .dossier-grille-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--jobcrible-e-5);
  }

  .feuille table {
    border-collapse: collapse;
    width: 100%;
    font-size: var(--jobcrible-t-13);
  }

  .feuille th {
    text-align: left;
    font-weight: 400;
    color: var(--jobcrible-texte-2);
    padding: var(--jobcrible-e-1) var(--jobcrible-e-3);
  }

  .feuille td {
    padding: var(--jobcrible-e-2) var(--jobcrible-e-3);
    border-top: 1px solid var(--jobcrible-bordure);
    vertical-align: top;
  }

  .feuille main ul {
    margin: 0;
    padding-left: 1.125rem;
    font-size: var(--jobcrible-t-14);
    line-height: 1.6;
  }

  .feuille > footer {
    display: flex;
    justify-content: space-between;
    gap: var(--jobcrible-e-3);
    padding-top: var(--jobcrible-e-3);
    border-top: 1px solid var(--jobcrible-bordure);
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }

  @media (width < 900px) {
    .feuille {
      max-width: 100%;
    }
  }

  /* -- annonce, dépôt, questionnaire et réexamen public (fiches 09/10/11, S4-U3) ----------- */
  /* `:has()` (Baseline largement disponible) : même patron que `body:has(.barre-bas) .contenu`
     plus bas — colonne resserrée pour tous les gabarits candidat public (annonce, dépôt,
     confirmation, questionnaire, réexamen, lien expiré) ; `.questionnaire` ajoutée fiche 11 —
     `.recu` couvre déjà réponses envoyées/lien expiré/réexamen (même classe, même largeur). */
  .contenu:has(.annonce),
  .contenu:has(.depot),
  .contenu:has(.recu),
  .contenu:has(.questionnaire) {
    max-width: 640px;
  }

  .annonce {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
  }

  .depot,
  .recu {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-4);
  }

  /* Fiche 11 (S4-U3) : « La suite » (réponses envoyées) — une coche + une ligne, même patron que
     les repères numérotés de la fiche 09 (`#comment ol li`) mais sans le fond de pastille : ici
     la coche porte déjà le sens (fait), pas une étape à venir. */
  .recu ol {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
  }

  .recu ol li {
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-3);
  }

  .recu ol li > span:first-child {
    flex-shrink: 0;
    color: var(--jobcrible-texte-2);
  }

  @media (width < 640px) {
    .depot .bouton[type="submit"] {
      width: 100%;
    }
  }

  .faits {
    margin: 0;
    color: var(--jobcrible-texte-2);
  }

  .marque {
    display: flex;
    align-items: baseline;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  .marque-tagline {
    color: var(--jobcrible-texte-2);
    font-size: var(--jobcrible-t-14);
  }

  /* Accueil de Jobcrible (domaine de base) : une colonne étroite, une carte du design (`.carte`,
     jamais redéfinie ici) qui porte le titre, la phrase et le seul geste — même largeur resserrée
     que la page d'erreur et les gabarits candidat. Haut de page de 48 px sur ordinateur
     (fondations § 4), marge de page de 16 px sur téléphone (fondations § 7, comme `.contenu`), où le
     geste prend toute la largeur de la carte à la hauteur de 44 px de `.bouton` (fondations § 5). */
  .accueil {
    max-width: 640px;
    padding-block-start: var(--jobcrible-e-7);
  }

  @media (width < 640px) {
    .accueil {
      padding-block-start: var(--jobcrible-e-4);
    }

    .accueil .bouton {
      width: 100%;
    }
  }

  /* Pages d'entrée (tranche connexion-domaine-base, 18/10) : la connexion et les pages d'allauth qui
     l'entourent (mot de passe oublié, réinitialisation…), sur le domaine de base comme sur
     l'adresse d'une organisation. Même colonne étroite que l'accueil et les pages d'erreur ; le
     contenu est dans une `.carte` (`allauth/layouts/base.html`) ; sous 640 px les gestes prennent la
     largeur de la carte, comme celui de l'accueil. Le trait entre les gestes (`hr`) est celui des
     séparateurs du design. */
  .entree {
    max-width: 640px;
  }

  .entree hr {
    margin: 0;
    border: 0;
    border-top: 1px solid var(--jobcrible-separateur);
  }

  @media (width < 640px) {
    .entree .bouton {
      width: 100%;
    }
  }

  .annonce-cta--bas {
    display: none;
  }

  @media (width < 640px) {
    .annonce-cta--haut {
      display: none;
    }

    .annonce-cta--bas {
      display: flex;
      width: 100%;
      justify-content: center;
    }
  }

  .rappel {
    margin: 0;
    color: var(--jobcrible-texte-2);
  }

  .lien-retour {
    display: inline-block;
  }

  /* Fiche 10 : zone de fichier interactive (`fichier()`, jobcrible.js) — jamais la boîte grise native
     du navigateur seule, un bouton stylé déclenche l'input masqué (même patron que le logo,
     fiche 07). */
  .fichier {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  .fichier input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }

  .fichier-etat {
    color: var(--jobcrible-texte-2);
    font-size: var(--jobcrible-t-14);
  }

  .fichier--erreur {
    border: 2px solid var(--jobcrible-danger);
    border-radius: var(--jobcrible-r-controle);
    padding: var(--jobcrible-e-3);
  }

  /* -- questionnaire et réexamen (fiche 11, S4-U3) ----------------------------------------- */
  .contexte {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
  }

  .contexte > span:first-child {
    color: var(--jobcrible-texte-2);
    font-size: var(--jobcrible-t-14);
  }

  .questionnaire {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-5);
  }

  .questionnaire form {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-4);
  }

  /* Ligne (pas colonne) : la barre et « Question N sur M » côte à côte — même agencement que la
     maquette (`flex-grow:1` sur la barre, jamais chacune sur sa propre ligne, constaté en
     écrivant cette tranche : une barre seule sur sa ligne s'étend à 100 % au lieu de partager la
     largeur avec le texte). */
  .progression {
    display: flex;
    align-items: center;
    gap: var(--jobcrible-e-3);
  }

  .progression-barre {
    flex-grow: 1;
    height: 6px;
    border-radius: 3px;
    background: var(--jobcrible-separateur);
    overflow: hidden;
  }

  .progression-barre > div {
    height: 100%;
    background: var(--jobcrible-accent);
    transition: width 0.2s ease;
  }

  .progression > span {
    color: var(--jobcrible-texte-2);
    font-size: var(--jobcrible-t-14);
    white-space: nowrap;
  }

  .question,
  .etape4 {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-3);
  }

  /* Répondue/en cours : le CADRE de carte vit sur ce conteneur `<div>` (repéré comme tel par la
     revue mécanique, `scripts/revue_ui.py::ressembleACarte`, qui ne reconnaît qu'un `<div>` à
     bordure/rayon — jamais un `<button>`). À venir : la maquette rend l'ÉTAT ENTIER comme un
     `<button>` SEUL, sans `<div>` enveloppant — reproduit ici en déplaçant le cadre sur le
     `<button class="question-entete">` lui-même plutôt que sur le conteneur, pour que le compte
     de blocs « carte » (répondue/en cours seulement) corresponde à celui de la maquette (constaté
     en écrivant cette tranche, écran 11 : sinon la comparaison position-à-position glisse d'un
     cran à partir de la troisième question). */
  .question--repondue,
  .question--en-cours,
  .etape4--en-cours {
    border: 1px solid var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    padding: var(--jobcrible-e-4);
  }

  .question--a-venir .question-entete,
  .etape4--a-venir .question-entete {
    width: 100%;
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-3);
    background: var(--jobcrible-fond);
    border: 1px dashed var(--jobcrible-bordure);
    border-radius: var(--jobcrible-r-cadre);
    padding: 0.875rem var(--jobcrible-e-4);
    font: inherit;
    color: var(--jobcrible-texte-2);
    text-align: start;
    cursor: pointer;
  }

  .question--repondue {
    background: var(--jobcrible-fond);
  }

  .question-entete {
    display: flex;
    align-items: baseline;
    gap: var(--jobcrible-e-3);
  }

  .question-numero {
    flex-shrink: 0;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background: var(--jobcrible-accent-pale);
    color: var(--jobcrible-accent);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--jobcrible-t-13);
    font-weight: 700;
  }

  .question--repondue .question-numero {
    background: none;
    color: var(--jobcrible-succes);
  }

  .question-titre {
    font-weight: 600;
  }

  .question-statut,
  .question-resume {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--jobcrible-e-3);
    flex-wrap: wrap;
  }

  /* Alignée sous le TEXTE de la question, pas sous le repère numéroté au-dessus (repère + son
     espacement, 1.5rem + var(--jobcrible-e-3)) — jamais sous l'état en cours, déjà indenté par le
     padding de sa propre carte (`.question--en-cours`). */
  .question-resume {
    padding-left: calc(1.5rem + var(--jobcrible-e-3));
  }

  .question-statut > span,
  .question-resume > span:first-child {
    color: var(--jobcrible-texte-2);
    font-size: var(--jobcrible-t-14);
  }

  .question-resume > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
  }

  /* Fond + bordure haute (jamais `position: sticky` — écran 09, S4-U3 : un CTA sticky mesuré
     hors défilement trie hors ordre dans la revue mécanique, exclusion documentée dans `docs/ux/
     revue.toml`, évitée ici dès le départ) : reconnu comme une « carte » par `ressembleACarte`
     (bordure + fond), au même rang que la maquette — sinon la comparaison position-à-position
     des blocs de la fiche glisse d'un cran (constaté en écrivant cette tranche). */
  .questionnaire-envoi {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-2);
    align-items: flex-start;
    background: var(--jobcrible-fond);
    border-top: 1px solid var(--jobcrible-bordure);
    padding-top: var(--jobcrible-e-4);
  }

  .questionnaire-envoi .bouton[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .motif-rappel {
    display: flex;
    align-items: flex-start;
    gap: var(--jobcrible-e-3);
    background: var(--jobcrible-info-fond);
    color: var(--jobcrible-info);
    border-radius: var(--jobcrible-r-cadre);
    padding: var(--jobcrible-e-3) var(--jobcrible-e-4);
    font-size: var(--jobcrible-t-14);
  }

  /* Impression — dossier de qualification (base_print.html), spec 13 § 4.2 */
  @page {
    size: A4;
    margin: 18mm;
  }

  @media print {
    .carte,
    .tableau tr {
      break-inside: avoid;
    }
  }
}

@layer utilitaires {
  .masque-visuellement {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .defile-x {
    overflow-x: auto;
  }

  .u-tabular-nums {
    font-variant-numeric: tabular-nums;
  }

  .u-succes {
    color: var(--jobcrible-succes);
    font-weight: 600;
  }

  /* Fiche 04 (S4-U3) : formulaire porteur du jeton anti-CSRF seul, ses champs vivant ailleurs
     sur la page (attache HTML `form="reglages"`) — jamais un bloc de plus dans `.pile`
     (`base_app.html`), qui consommerait deux fois son `gap` (avant ET après lui, revue mécanique
     règle c). Un `<form>` `display: none` reste un `<form>` valide : l'attache `form=""` marche
     par `id`, pas par mise en page. */
  .u-invisible {
    display: none;
  }

  /* Fiche 04 (S4-U3), onglet Annonce : un `Announcement.text` porte ses propres sauts de ligne
     (paragraphes de l'annonce) — HTML les ignore par défaut, ce texte n'est ni une saisie
     multi-ligne à styler comme un `<textarea>` ni une zone d'aide, juste un paragraphe qui doit
     rester TEL QUE saisi. */
  .u-texte-preforme {
    white-space: pre-line;
  }

  /* -- page d'erreur 404/403 (fiche 12, S4-U3) -------------------------------------------- */
  /* `_carte_erreur.html`, incluse par `404.html`/`403.html` (`500.html` reste autonome, styles
     embarqués — CLAUDE.md, § « ce que tu ne fais pas » sur les gestionnaires d'erreur). Même
     colonne resserrée que les gabarits candidat (fiches 09/10/11) côté public ; côté `/app/`,
     `.contenu.pile` porte déjà `margin-inline: auto`, la carte reste alignée à gauche du contenu
     (maquette ecran-12-403 : `<main>` en colonne, la carte n'est pas centrée dans la page). */
  .contenu:has(.carte-erreur) {
    max-width: 640px;
  }

  .carte-erreur {
    display: flex;
    flex-direction: column;
    gap: var(--jobcrible-e-4);
    background: var(--jobcrible-surface);
    border: 1px solid var(--jobcrible-bordure);
    border-radius: 6px;
    padding: var(--jobcrible-e-6) var(--jobcrible-e-5);
  }

  .carte-erreur-icone {
    color: var(--jobcrible-texte-2);
  }

  .carte-erreur-icone .icon {
    width: 36px;
    height: 36px;
  }

  .carte-erreur-actions {
    display: flex;
    gap: var(--jobcrible-e-2);
    flex-wrap: wrap;
    margin-top: var(--jobcrible-e-1);
  }

  .note {
    margin: 0;
    font-size: var(--jobcrible-t-13);
    color: var(--jobcrible-texte-2);
  }
}

/* Non calées dans une couche : gagnent toujours sur le reste de la cascade (focus visible,
 * reduced-motion) — spec 13 § 4.2, § 8. */

:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--jobcrible-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --jobcrible-d-etat: 0ms;
    --jobcrible-d-apparition: 0ms;
  }
}
