/*
 * Styles de base et composants partagés, d'après le design system du projet (direction
 * contrastée) : page sur fond gris (canvas), contenus dans des panneaux blancs
 * détachés, kanban sur une bande marine.
 * Toutes les valeurs de couleur, de taille, de rayon et d'ombre viennent de variables.css.
 */

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

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

body {
    margin: 0;
    min-height: 100vh;
    background: var(--canvas);
    color: var(--ink);
    font: var(--text-body);
    overflow-wrap: anywhere;
}

h1,
h2,
h3 {
    margin: 0 0 var(--space-4);
}

h1 {
    font: var(--text-title-1);
    color: var(--navy);
}

h2 {
    font: var(--text-title-2);
}

h3 {
    font: var(--text-title-3);
}

p {
    margin: 0 0 var(--space-4);
}

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

a:hover {
    color: var(--navy-hover);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

/* Texte courant : les liens restent repérables sans la couleur. */
p a:not([class]),
dd a:not([class]),
li a:not([class]) {
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

code,
kbd,
samp,
pre {
    font-family: var(--font-mono);
}

code {
    font: var(--text-mono);
}

hr {
    height: 0;
    margin: var(--space-6) 0;
    border: 0;
    border-top: var(--line-width) solid var(--line);
}

/* Focus clavier : 2 px plein, décalé de 2 px, marine sur tous les fonds clairs. */
:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
    border-radius: var(--radius-sm);
}

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

/* Lien d'évitement : visible au focus clavier */
.skip-link {
    position: absolute;
    top: var(--space-2);
    left: var(--space-4);
    z-index: 10;
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    padding: 0 var(--space-4);
    background: var(--navy);
    color: var(--on-navy);
    border-radius: var(--radius-md);
    font: var(--text-button);
    transform: translateY(-200%);
}

.skip-link:focus {
    transform: none;
    color: var(--on-navy);
}

.text-muted {
    color: var(--ink-muted);
}

/* Mise en page */
.container {
    width: 100%;
    max-width: var(--container-max);
    margin: 0 auto;
    padding-inline: var(--space-5);
}

/*
 * En-tête commun (SiteHeader, lot 151 : templates/layout/_site_header.html.twig) : 52 px, blanc
 * (surface) sur le fond gris de la page, trait fin en bas. Sur une ligne à partir de 1024 px : nom
 * du studio, navigation (avec le menu « Administration »), recherche poussée à droite, menu du
 * compte. Les onglets et les boutons de menu occupent toute la hauteur : le soulignement de
 * l'onglet actif se pose sur le trait de l'en-tête. Faute de place, le nom du studio puis la
 * recherche et le nom de la personne rétrécissent (points de suspension, nom complet en infobulle).
 */
.site-header {
    background: var(--surface);
    border-bottom: var(--line-width) solid var(--line);
}

.site-header__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 0 var(--space-5);
    min-height: var(--header-height);
}

.site-header__brand {
    display: block;
    flex: 0 1 auto;
    min-width: 0;
    max-width: var(--header-brand-max);
    overflow: hidden;
    align-self: center;
    padding-block: var(--space-1);
    color: var(--navy);
    font: var(--text-title-3);
    font-weight: var(--font-weight-bold);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-header__brand:hover {
    color: var(--navy-hover);
}

.site-header__user {
    display: flex;
    flex: none;
    align-items: stretch;
    margin-left: auto;
}

/* La recherche est déjà poussée à droite : le menu du compte la suit. */
.site-search + .site-header__user {
    margin-left: 0;
}

/*
 * Menus de l'en-tête (« Administration », menu du compte) : bloc action-menu (details natif,
 * contrôleur « menu »). Le bouton occupe toute la hauteur de l'en-tête et porte, sur une page de
 * l'une de ses entrées, le soulignement orange de l'onglet actif ; son libellé est dans une
 * pastille de 28 px (fond surface-hover pour « Administration »), suivi d'un chevron décoratif.
 * Liste flottante de 13rem, calée à gauche du bouton (« Administration ») ou à droite (compte).
 */
.site-menu {
    display: flex;
    min-width: 0;
}

.site-menu[open] {
    z-index: 30;
}

.site-menu__toggle {
    display: flex;
    align-items: center;
    min-width: 0;
    min-height: var(--header-height);
    border-bottom: var(--indicator-width) solid transparent;
    cursor: pointer;
}

/* Focus sur la pastille du libellé, pas sur toute la hauteur de l'en-tête. */
.site-menu__toggle:focus-visible {
    outline: none;
}

.site-menu__toggle:focus-visible .site-menu__button {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.site-menu__button {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    min-height: var(--control-size-sm);
    padding: 0 var(--space-3);
    border-radius: var(--radius-md);
    background: var(--surface-hover);
    color: var(--ink);
    font: var(--text-body);
    font-weight: var(--font-weight-medium);
}

.site-menu__button--account {
    padding-left: var(--space-1);
    background: transparent;
}

.site-menu__toggle:hover .site-menu__button {
    background: var(--surface-hover);
    color: var(--navy);
}

.site-nav__link--current .site-menu__button {
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
}

/* Chevron vers le bas, dessiné par deux traits : il dit seulement que le bouton ouvre un menu. */
.site-menu__chevron {
    flex: none;
    width: var(--chevron-size);
    height: var(--chevron-size);
    margin: 0 var(--space-1) var(--space-1);
    border-right: var(--line-width) solid currentColor;
    border-bottom: var(--line-width) solid currentColor;
    transform: rotate(45deg);
}

.site-menu .site-menu__list {
    top: 100%;
    z-index: 30;
    width: var(--site-menu-width);
}

.site-menu--admin .site-menu__list {
    right: auto;
    left: 0;
}

.action-menu__item[aria-current="page"] {
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
}

/* « Se déconnecter » séparé des autres entrées par un trait. */
.site-menu__separated {
    margin-top: var(--space-1);
    padding-top: var(--space-1);
    border-top: var(--line-width) solid var(--line);
}

.site-header__avatar {
    flex: none;
}

.site-header__avatar .avatar__initials {
    width: var(--avatar-size-header);
    height: var(--avatar-size-header);
}

/* Nom court du studio et bouton « Menu » : seulement sous 640 px (lot 152). */
.site-header__short-name,
.site-menu--mobile {
    display: none;
}

/* Nom de la personne : tronqué par des points de suspension au-delà de sa place (nom complet en infobulle et lu). */
.site-header__name {
    min-width: 0;
    max-width: var(--header-name-max);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-main {
    padding-top: var(--space-5);
    padding-bottom: var(--space-7);
}

/*
 * Bande pleine largeur (kanban de la fiche projet), posée par le bloc « band » du gabarit de base
 * hors du conteneur : elle prend toute la largeur de la page sans 100vw. Fond marine (board) ;
 * son contenu est dans un conteneur intérieur, qui lui donne les marges de page (space-8 à partir
 * de 1024 px, space-5 en dessous), et l'anneau de focus passe en blanc (11,9:1 sur board).
 */
.band {
    padding-block: var(--space-5) var(--space-7);
    background: var(--board);
    color: var(--on-board);
}

.band :focus-visible {
    outline-color: var(--on-board);
}

/* Au-dessus de la bande, seule la marge basse de l'en-tête de page (space-6) la sépare du titre. */
.site-main:has(+ .band) {
    padding-bottom: 0;
}

.site-main--after-band {
    padding-top: var(--space-7);
}

.flash-region:empty {
    display: none;
}

.flash-region {
    margin-bottom: var(--space-4);
}

/*
 * Écrans d'accès (connexion, double authentification, enrôlement) : panneau blanc (panel) centré
 * sur le fond gris, à toutes les largeurs ; sa largeur de contenu est narrow-max, la marge
 * intérieure s'y ajoute et le panneau rétrécit sur un petit écran. Pas de bande marine.
 * Pas de navigation, donc pas de point d'orange.
 */
.auth {
    display: flex;
    justify-content: center;
    padding: var(--space-7) var(--space-5);
}

.auth__card {
    flex: 0 1 var(--narrow-max);
    min-width: 0;
    box-sizing: content-box;
}

.auth__card h1 {
    margin-bottom: var(--space-2);
}

.auth__intro {
    margin-bottom: var(--space-6);
    color: var(--ink-muted);
}

.auth__brand {
    margin-bottom: var(--space-6);
    color: var(--navy);
    font: var(--text-title-3);
}

.auth__card .form-field {
    margin-bottom: var(--space-5);
}

.auth__secondary {
    margin-top: var(--space-4);
}

/* « Mot de passe oublié ? » sous le bouton « Se connecter » : lien toujours visible, cible au doigt. */
.auth__forgot {
    margin: var(--space-3) 0 0;
    text-align: center;
}

.auth__forgot a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
}

/*
 * Deux façons de se connecter (mot de passe, lien reçu par email) : deux sections du même
 * panneau, séparées par un trait ; un titre de bloc pour chacune.
 */
.auth__section + .auth__section {
    margin-top: var(--space-6);
    padding-top: var(--space-6);
    border-top: var(--line-width) solid var(--line);
}

.auth__section-title {
    margin: 0 0 var(--space-3);
    color: var(--ink);
    font: var(--text-title-3);
}

.auth__section-intro {
    margin: 0 0 var(--space-4);
    color: var(--ink-muted);
}

/* Demande de studio sur la page de confirmation de l'exploitant (lot 170). Sélecteur renforcé :
   .details, plus loin dans la feuille, remet sa marge à zéro. */
.auth__card .auth__details {
    margin-bottom: var(--space-6);
}

/* « Créer un studio » (lot 169) : en pied du panneau de connexion, après un trait. */
.auth__signup {
    margin: var(--space-6) 0 0;
    padding-top: var(--space-6);
    border-top: var(--line-width) solid var(--line);
    color: var(--ink-muted);
    text-align: center;
}

.auth__signup a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
}

.auth__help {
    margin: var(--space-6) 0 0;
    color: var(--ink-muted);
    font: var(--text-small);
}

/*
 * Lien « Confidentialité » (lot 190) en bas de la connexion, de « Créer un studio » et de
 * « Mon compte » : lien texte souligné (règle des liens du texte courant), centré, cible au doigt.
 */
.legal-link {
    margin: var(--space-6) 0 0;
    font: var(--text-small);
    text-align: center;
}

.legal-link a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
}

/*
 * Politique de confidentialité (lot 190) : même panneau que les écrans d'accès, élargi à une
 * longueur de ligne de lecture ; sections séparées par un trait (auth__section), titrées en h2.
 */
.auth__card--reading {
    flex-basis: var(--measure-max);
}

.privacy .auth__intro {
    margin-bottom: var(--space-2);
}

.privacy__updated {
    margin: 0 0 var(--space-6);
    color: var(--ink-muted);
    font: var(--text-small);
}

.privacy__section p,
.privacy__list,
.privacy__purposes,
.privacy__cookies,
.privacy__address {
    margin: 0 0 var(--space-3);
}

.privacy__section > :last-child {
    margin-bottom: 0;
}

.privacy__list {
    padding-left: var(--space-5);
}

.privacy__list li + li {
    margin-top: var(--space-2);
}

.privacy__address {
    font-style: normal;
}

.privacy__purposes dt,
.privacy__cookies dt {
    font-weight: var(--font-weight-semibold);
}

.privacy__purposes dd,
.privacy__cookies dd {
    margin: 0 0 var(--space-3);
}

/* Nom technique d'un cookie (lot 191) : en Space Mono, coupé plutôt que de déborder à 360 px. */
.privacy__cookie-name {
    font-family: var(--font-mono);
    overflow-wrap: anywhere;
}

/* Adresse de contact et liens : coupés plutôt que de faire défiler la page à 360 px. */
.privacy__section a {
    overflow-wrap: anywhere;
}

@media (min-width: 641px) {
    .auth {
        padding-top: var(--space-8);
    }

    /* Plus spécifique que .panel : un panneau seul à l'écran respire davantage. */
    .auth .auth__card {
        padding: var(--space-7);
    }
}

/*
 * Pages d'erreur (lot 164, variante C) : dans l'outil, un panneau blanc posé sur le fond gris,
 * de la largeur d'un écran d'accès ; sans session et pour la panne, le même contenu dans le
 * panneau centré des écrans d'accès (auth). En tête, le code en grand, en line-strong : grand
 * texte (64 px gras) à 3:1 au moins dans les deux palettes (3,6:1 en clair, 4,3:1 en sombre sur
 * surface) ; le titre (h1) et la phrase portent le message, le code ne fait que le rappeler.
 */
.error-page {
    max-width: var(--narrow-max);
    box-sizing: content-box;
}

.error-page__code {
    margin: 0 0 var(--space-4);
    color: var(--line-strong);
    font: var(--text-error-code);
    letter-spacing: var(--tracking-error-code);
}

.error-page__title {
    margin-bottom: var(--space-2);
}

.error-page__text {
    margin: 0 0 var(--space-6);
}

.error-page__actions {
    margin: 0;
}

/*
 * Étapes numérotées (enrôlement) : numéro en marine dans sa colonne, contenu aligné à côté.
 * Les numéros restent ceux de la liste ordonnée pour les lecteurs d'écran.
 */
.steps {
    margin: 0;
    padding: 0;
    list-style: none;
    counter-reset: step;
}

.steps__item {
    display: grid;
    grid-template-columns: var(--space-6) minmax(0, 1fr);
    column-gap: var(--space-2);
    margin-bottom: var(--space-6);
    counter-increment: step;
}

.steps__item::before {
    content: counter(step) ".";
    color: var(--navy);
    font: var(--text-title-3);
}

.steps__item > * {
    grid-column: 2;
}

.steps__title {
    grid-row: 1;
    margin-bottom: var(--space-1);
    font: var(--text-title-3);
}

.steps__item > p {
    margin-bottom: var(--space-4);
}

.steps__item > :last-child {
    margin-bottom: 0;
}

/* Code QR de l'enrôlement : image à fond blanc dans les deux palettes (modules sombres sur fond
   clair, sinon illisible par une application). */
.qr-code {
    display: block;
    width: 100%;
    max-width: var(--qr-code-max);
    height: auto;
    margin-bottom: var(--space-4);
    border: var(--line-width) solid var(--line);
    border-radius: var(--radius-md);
}

/* Clé secrète lisible et facile à recopier : Space Mono, groupes de 4 caractères, retour à la ligne permis */
.secret-key {
    display: block;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    color: var(--ink);
    font: var(--text-body);
    font-family: var(--font-mono);
    letter-spacing: var(--tracking-code);
    overflow-wrap: anywhere;
    user-select: all;
}

/* Composant Button : 32 px (28 px en --sm) sur ordinateur, 44 px sur mobile et écran tactile */
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    min-height: var(--control-size);
    padding: 0 var(--space-4);
    border: var(--line-width) solid transparent;
    border-radius: var(--radius-md);
    font: var(--text-button);
    text-align: center;
    text-decoration: none;
    /* Un libellé passe à la ligne entre deux mots, jamais au milieu d'un mot. */
    overflow-wrap: normal;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.button:hover {
    text-decoration: none;
}

.button--sm {
    min-height: var(--control-size-sm);
    padding: 0 var(--space-3);
}

.button--primary {
    background: var(--navy);
    color: var(--on-navy);
}

.button--primary:hover {
    background: var(--navy-hover);
    color: var(--on-navy);
}

.button--secondary {
    background: var(--surface);
    color: var(--navy);
    border-color: var(--line-strong);
}

.button--secondary:hover {
    background: var(--surface-hover);
    color: var(--navy);
}

.button--ghost {
    background: transparent;
    color: var(--navy);
}

.button--ghost:hover {
    background: var(--surface-hover);
    color: var(--navy);
}

.button--danger {
    background: var(--danger);
    color: var(--on-danger);
}

/* Triangle d'avertissement devant le libellé (lot 126) : forme qui distingue le bouton sans la couleur. */
.danger-shape {
    flex: none;
    width: var(--shape-size);
    height: var(--shape-size);
}

.button--danger:hover {
    background: var(--danger-hover);
    color: var(--on-danger);
}

.button--block {
    display: flex;
    width: 100%;
}

/* Pendant l'envoi d'un formulaire (Turbo désactive le bouton et marque le formulaire occupé) */
.button:disabled,
.button[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
}

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

.button[aria-busy="true"]::after {
    content: "";
    width: var(--spinner-size);
    height: var(--spinner-size);
    border: var(--indicator-width) solid currentColor;
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: button-spin 0.8s linear infinite;
}

@keyframes button-spin {
    to {
        transform: rotate(360deg);
    }
}

/* Composants FormField, SelectField, TextareaField */
.form-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-width: var(--form-max);
    margin-bottom: var(--space-5);
}

/* Valeur non modifiable présentée comme un champ (rôle d'un contact) : libellé et texte sans marge de paragraphe. */
.form-field > p {
    margin: 0;
}

.form-field__label {
    font: var(--text-label);
    font-weight: var(--font-weight-semibold);
    color: var(--ink);
}

.form-field__input {
    /* Une liste déroulante aux options longues ne dépasse pas de son conteneur. */
    width: 100%;
    min-width: 0;
    max-width: 100%;
    min-height: var(--control-size);
    padding: var(--space-1) var(--space-3);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--field);
    color: var(--ink);
    font: var(--text-input);
}

.form-field__input:focus-visible {
    outline-offset: var(--focus-offset-inset);
    border-color: var(--navy);
}

/* Erreur : bordure de 2 px sans décaler le contenu. */
.form-field__input[aria-invalid="true"] {
    border-color: var(--danger);
    box-shadow: inset 0 0 0 var(--line-width) var(--danger);
}

/* Valeur technique à recopier (référence d'un projet) : Space Mono, à la taille du texte du champ. */
.form-field__input--mono {
    font-family: var(--font-mono);
}

.form-field__select {
    appearance: auto;
}

.form-field__textarea {
    min-height: var(--textarea-min-height);
    padding-block: var(--space-2);
    resize: vertical;
}

.form-field__help {
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.form-field__error {
    display: flex;
    align-items: flex-start;
    gap: var(--space-1);
    margin: 0;
    color: var(--danger);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
}

/* La croix se centre sur la première ligne du message. */
.form-field__error .state-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
    margin-top: calc((1lh - var(--shape-size-sm)) / 2);
}

/* Composant ChoiceField (boutons radio) */
.choice-field {
    min-width: 0;
    max-width: var(--form-max);
    margin: 0 0 var(--space-5);
    padding: 0;
    border: 0;
}

.choice-field legend {
    margin-bottom: var(--space-1);
    padding: 0;
}

.choice-field__option {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    column-gap: var(--space-2);
    min-height: var(--choice-size);
}

.choice-field__input {
    width: var(--choice-input-size);
    height: var(--choice-input-size);
    margin: 0;
    accent-color: var(--navy);
}

/*
 * Le libellé, cliquable, couvre toute la hauteur d'une option (28 px, 44 px au doigt) ; ses marges
 * négatives lui gardent la place d'une ligne de texte pour ne pas écarter l'aide de l'option.
 */
.choice-field__label {
    display: flex;
    align-items: center;
    min-height: var(--choice-size);
    margin-block: calc((1lh - var(--choice-size)) / 2);
    cursor: pointer;
}

.choice-field__help {
    grid-column: 2;
    margin-bottom: var(--space-1);
}

/* Composant ErrorSummary : fond pâle sans cadre, liens soulignés */
.error-summary {
    max-width: var(--form-max);
    margin-bottom: var(--space-5);
    padding: var(--space-4) var(--space-5);
    background: var(--danger-soft);
    border-radius: var(--radius-md);
}

.error-summary:focus {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.error-summary__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-1);
    color: var(--danger);
    font: var(--text-title-3);
}

.error-summary__title .state-shape {
    flex: none;
}

.error-summary__list {
    margin: 0;
    padding-left: var(--space-6);
    font: var(--text-small);
}

.error-summary__list a {
    display: inline-flex;
    align-items: center;
    min-height: var(--target-min);
    color: var(--danger);
    text-decoration: underline;
}

/* Composant Flash : fond pâle, forme et type écrit en tête */
.flash {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin-bottom: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    font: var(--text-small);
}

.flash .state-shape {
    flex: none;
}

.flash__label {
    font-weight: var(--font-weight-semibold);
}

.flash__message {
    color: var(--ink);
}

/* Lien d'un message (« Voir tout le Backlog », lot 149) : souligné, repérable sans la couleur ; cible de 44 px au doigt. */
.flash__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

.flash--success {
    background: var(--success-soft);
    color: var(--success);
}

.flash--error {
    background: var(--danger-soft);
    color: var(--danger);
}

.flash--info {
    background: var(--neutral-soft);
    color: var(--ink);
}

/* Message collé en haut d'une zone (messages du kanban) : seul cas d'ombre d'un Flash. */
.flash--floating {
    box-shadow: var(--shadow-float);
}

/*
 * Recherche rapide de l'en-tête (lot 144, templates/search/_header.html.twig, contrôleur
 * « search ») : champ nommé avec l'indice ⌘K / Ctrl+K (affiché avec JavaScript, masqué au doigt),
 * liste des résultats flottante sous le champ (--shadow-float). L'option active est entourée d'un
 * contour marine plein, pas seulement d'un fond : elle se voit en niveaux de gris. Sous 640 px,
 * un bouton « Rechercher » ouvre la recherche en plein écran (sans JavaScript, il mène à la page
 * « Recherche »).
 */
.site-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 0 10 var(--search-width); /* rétrécit avant le nom du studio */
    min-width: var(--search-min-width);
    margin-left: auto;
}

.site-search__opener,
.site-search__close {
    display: none;
}

.site-search__box {
    position: relative;
    width: 100%;
}

.site-search__form {
    position: relative;
    display: flex;
    align-items: center;
    margin: 0;
}

.site-search__input {
    width: 100%;
    min-width: 0;
    min-height: var(--control-size-sm);
    padding: 0 var(--space-8) 0 var(--space-3);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--field);
    color: var(--ink);
    font: var(--text-input);
}

.site-search__input::placeholder {
    color: var(--ink-muted);
    opacity: 1;
}

.site-search__input:focus-visible {
    outline-offset: var(--focus-offset-inset);
    border-color: var(--navy);
}

.site-search__hint {
    position: absolute;
    right: var(--space-2);
    padding: 0 var(--space-1);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--ink-muted);
    font: var(--text-mono);
    pointer-events: none;
}

@media (pointer: coarse) {
    .site-search__hint {
        display: none;
    }
}

.site-search__results {
    display: none;
}

.site-search--shown .site-search__results {
    position: absolute;
    top: calc(100% + var(--space-1));
    right: 0;
    z-index: 30;
    display: block;
    width: min(var(--search-results-width), calc(100vw - 2 * var(--space-5)));
    max-height: var(--search-results-max-height);
    overflow-y: auto;
    border-radius: var(--radius-md);
    background: var(--surface);
    box-shadow: var(--shadow-float);
}

.site-search__panel {
    padding: var(--space-2);
}

.site-search__group + .site-search__group {
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: var(--line-width) solid var(--line);
}

.site-search__group-title {
    margin: 0;
    padding: var(--space-1) var(--space-2);
    color: var(--ink-muted);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
}

.site-search__message {
    margin: 0;
    padding: var(--space-2);
    color: var(--ink);
    font: var(--text-small);
}

/* Résultat (tâche ou projet), sous le champ comme sur la page « Recherche ». */
.search-result {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-height: var(--control-size);
    padding: var(--space-2);
    border-radius: var(--radius-md);
    color: var(--ink);
    text-decoration: none;
}

.search-result:hover {
    background: var(--surface-hover);
    text-decoration: none;
}

.search-result__main {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    min-width: 0;
}

.search-result__title {
    min-width: 0;
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
    overflow-wrap: anywhere;
}

.search-result__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    color: var(--ink-muted);
    font: var(--text-small);
}

.site-search__option--active {
    background: var(--surface-hover);
    box-shadow: inset 0 0 0 var(--indicator-width) var(--navy);
}

/* Page « Recherche » : nombre de résultats, listes de liens dans des panneaux. */
.search-page__count {
    margin: var(--space-5) 0 0;
    color: var(--ink-muted);
}

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

.search-list__item + .search-list__item {
    border-top: var(--line-width) solid var(--line);
}

.search-list .search-result {
    padding: var(--space-3) var(--space-5);
    border-radius: 0;
}

/*
 * Navigation principale : liens en ink-muted 14/500 ; onglet actif en marine 14/600, souligné de
 * 2 px d'orange (seul orange de l'écran). La graisse et la couleur du texte portent l'information,
 * l'orange ne fait que souligner. Un bouton de menu dont une entrée est la page affichée
 * (site-nav__link--current) porte le même soulignement ; l'entrée porte aria-current="page".
 */
.site-nav {
    display: flex;
    flex: 0 0 auto;
}

.site-nav__list {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.site-nav__list > li {
    display: flex;
}

.site-nav__link {
    display: flex;
    align-items: center;
    min-height: var(--header-height);
    padding: 0 var(--space-1);
    border-bottom: var(--indicator-width) solid transparent;
    color: var(--ink-muted);
    font: var(--text-body);
    font-weight: var(--font-weight-medium);
}

.site-nav__link:hover {
    color: var(--navy);
    text-decoration: none;
}

.site-nav__link[aria-current="page"],
.site-nav__link--current {
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
    border-bottom-color: var(--orange);
}

.site-nav .site-menu__toggle {
    padding: 0;
}

/*
 * En-tête de page (PageHeader) : posé directement sur le fond gris, au-dessus des panneaux ;
 * titre en navy, métadonnées en ink-muted (5:1 sur canvas), actions toujours visibles.
 */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    margin: var(--space-3) 0 var(--space-6);
}

.page-header h1 {
    margin: 0;
}

/* Introduction : ce que la page permet, en une phrase. */
.page-header__intro {
    max-width: var(--measure-max);
    margin: var(--space-2) 0 0;
    color: var(--ink-muted);
}

/* Métadonnées sous le titre (organisation, référence…), séparées par « · » masqué aux lecteurs d'écran. */
.page-header__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: var(--space-2) 0 0;
    color: var(--ink-muted);
    font: var(--text-small);
}

/* Étiquette neutre posée sur le fond gris (état d'un projet, contact principal) : fond blanc, pour rester visible. */
.page-header .badge--neutral {
    background: var(--surface);
}

.narrow {
    max-width: var(--form-max);
}

/* État vide : une phrase sobre et, pour l'équipe, l'action qui le remplit ; du blanc, pas de cadre */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-6) 0;
    color: var(--ink-muted);
}

.empty-state p {
    max-width: var(--form-max);
    margin: 0;
}

/*
 * En-tête de section affirmé : titre title-2 en ink, compteur en pastille (CountPill) à côté,
 * actions de la section à droite. Posé sur le fond gris au-dessus d'un panneau, ou en tête de panneau.
 */
.section-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
}

.section-header h2 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    color: var(--ink);
}

/* Lien de retour vers la page parente */
.back-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
    font: var(--text-small);
}

/*
 * Panneau : bloc blanc détaché du fond gris par l'ombre de carte, sans cadre. Tout contenu s'y
 * range (liste, tableau, formulaire, fiche). --flush pour un tableau qui va jusqu'aux bords.
 */
.panel {
    padding: var(--space-6);
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

/* Panneaux successifs : un panneau posé sous un en-tête de section ne reçoit pas cette marge. */
.panel + .panel {
    margin-top: var(--space-6);
}

.panel > :last-child {
    margin-bottom: 0;
}

.panel--flush {
    padding: 0;
    overflow: hidden;
}

.panel__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    color: var(--ink);
    font: var(--text-title-2);
}

/* Compteur en pastille (CountPill) : nombre en gras, libellé complet pour les lecteurs d'écran. */
.count-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--count-pill-min-width);
    height: var(--count-pill-height);
    padding: 0 var(--space-2);
    border-radius: var(--radius-full);
    background: var(--neutral-soft);
    color: var(--ink);
    font: var(--text-caption);
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

/*
 * Pastille d'initiales (Avatar), toujours suivie du nom écrit : même teinte pour tout le monde,
 * initiales navy (9,5:1 sur avatar). « Non assignée » : pastille vide à contour en pointillés
 * (line-strong, 3,6:1 sur surface), texte ink-muted.
 */
.avatar {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    color: var(--ink);
    font: var(--text-caption);
}

.avatar__initials {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: var(--avatar-size);
    height: var(--avatar-size);
    border-radius: var(--radius-full);
    background: var(--avatar);
    color: var(--navy);
    font: var(--text-initials);
    letter-spacing: var(--tracking-initials);
}

.avatar__name {
    min-width: 0;
    overflow-wrap: anywhere;
}

.avatar--none {
    color: var(--ink-muted);
}

.avatar--none .avatar__initials {
    width: var(--avatar-size-empty);
    height: var(--avatar-size-empty);
    background: transparent;
    border: var(--dash-width) dashed var(--line-strong);
}

.panel form {
    margin: 0;
}

/* Formulaires */
/* Phrase d'introduction d'un formulaire : texte courant, en taille client (15/22) pour un contact. */
.form__intro {
    margin: 0 0 var(--space-5);
    font: var(--text-body);
}

.form__intro--client {
    font: var(--text-body-client);
}

.form__hint {
    margin: 0 0 var(--space-5);
    color: var(--ink-muted);
    font: var(--text-small);
}

/* Actions d'un formulaire, en bas après un trait. */
.form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-4);
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.form-actions__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

/* Composant Badge : étiquette discrète, toujours avec un mot, doublé d'une forme */
.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-tag) var(--space-2);
    border-radius: var(--radius-sm);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
    white-space: nowrap;
    /* Même alignement avec ou sans forme en tête (la forme décalerait la ligne de base). */
    vertical-align: middle;
}

.badge .state-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
}

.badge--neutral {
    background: var(--neutral-soft);
    color: var(--neutral);
}

.badge--success {
    background: var(--success-soft);
    color: var(--success);
}

.badge--warning {
    background: var(--warning-soft);
    color: var(--warning);
}

/* Erreur en aplat foncé : se distingue des autres états par la clarté, pas par la teinte. */
.badge--danger {
    background: var(--danger);
    color: var(--on-danger);
}

/* Statut de tâche : forme dessinée et libellé, sans fond */
.task-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--ink);
    font: var(--text-label);
    white-space: nowrap;
}

.status-shape {
    flex: none;
    width: var(--shape-size);
    height: var(--shape-size);
}

.status-shape--backlog {
    color: var(--status-backlog);
}

.status-shape--todo {
    color: var(--status-todo);
}

.status-shape--active {
    color: var(--status-active);
}

/* Demandes client : « Demande » en pointillés (clarté de « À faire »), « Refusée » barrée (encre). */
.status-shape--request {
    color: var(--status-request);
}

.status-shape--refused {
    color: var(--status-refused);
}

.status-shape__check {
    stroke: var(--surface);
}

/*
 * Priorité : écrite en toutes lettres avec sa forme. Haute en étiquette ambre (6,1:1) avec son
 * triangle ; normale et basse en texte ink-muted (basse avec son chevron).
 */
.task-priority {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--ink-muted);
    font: var(--text-caption);
    white-space: nowrap;
}

.task-priority--high {
    padding: var(--space-tag) var(--space-priority-inline);
    border-radius: var(--radius-sm);
    background: var(--warning-soft);
    color: var(--priority-high);
    font-weight: var(--font-weight-semibold);
}

.priority-shape {
    flex: none;
    width: var(--shape-size-xs);
    height: var(--shape-size-xs);
}

/* Actions groupées de l'en-tête de page (ex. Modifier, Archiver) */
.page-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.page-header__actions form {
    margin: 0;
}

/* Filtre d'une liste, à droite de l'en-tête de section (ex. afficher les projets archivés). */
.list-filter {
    margin: 0;
    font: var(--text-small);
}

.list-filter a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

/*
 * Liste des projets, dans un panneau blanc sans marge intérieure (panel--flush) : lignes aérées
 * séparées par un trait. Le nom du projet est le lien ; il couvre toute la ligne (cible large au
 * doigt), sans autre élément interactif. L'équipe voit l'organisation et la référence à droite
 * (dessous sur mobile) ; « Archivé » en étiquette neutre.
 */
.project-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.project-card {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1) var(--space-4);
    min-width: 0;
    padding: var(--space-3) var(--space-5);
    border-bottom: var(--line-width) solid var(--line);
}

.project-card:last-child {
    border-bottom: 0;
}

.project-card:hover {
    background: var(--surface-hover);
}

.project-card__title {
    min-width: 0;
    margin: 0;
    font: var(--text-title-3);
    overflow-wrap: anywhere;
}

.project-card__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

.project-card__link::after {
    content: "";
    position: absolute;
    inset: 0;
}

.project-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-4);
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-small);
    overflow-wrap: anywhere;
}

.project-card--archived .project-card__link {
    color: var(--ink-muted);
}

/* Propriétés d'un projet sur la ligne de son en-tête : « Atelier Lumière · site-vitrine » (· Archivé). */
.project-properties {
    margin-bottom: 0;
}

.project-properties__item {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    min-width: 0;
}

.project-properties__item + .project-properties__item::before {
    content: "·";
    content: "·" / "";
    margin-right: var(--space-1);
}

.project-properties dd {
    margin: 0;
    overflow-wrap: anywhere;
}

/* Sur mobile, la ligne revient à la ligne : pas de « · » en début de ligne, un blanc plus large suffit. */
@media (max-width: 640px) {
    .project-properties {
        column-gap: var(--space-4);
    }

    .project-properties__item + .project-properties__item::before {
        content: none;
    }
}

/*
 * En-tête du projet (lot 142), posé sur le fond gris : sur une ligne à partir de 1024 px, le nom
 * (h1), les propriétés (organisation, référence en Space Mono, « Archivé » s'il y a lieu) et la
 * pastille du forfait, puis les actions à droite ; en dessous, tout passe à la ligne sans
 * défilement horizontal. La phrase d'un projet archivé prend toute la largeur, sous la ligne.
 */
.project-header {
    align-items: center;
    gap: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
}

.project-header__main {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    min-width: 0;
}

/*
 * À partir de 1024 px, les actions restent sur la ligne du nom : le bloc du nom prend la place
 * qu'elles laissent (base nulle) et, sur un écran étroit, sa pastille passe sous le nom. Il garde
 * une largeur minimale (jalon 153 : à 1100 px, panneau de tâche ouvert, le nom passait à une
 * lettre par ligne) : faute de place, ce sont les actions qui passent dessous.
 */
@media (min-width: 1024px) {
    .project-header__main {
        flex-basis: 0;
        min-width: min(var(--project-title-min), 100%);
    }

    .project-header__actions {
        flex: none;
    }
}

/* Le nom passe à la ligne entre les mots ; un mot plus long que la ligne seul est coupé. */
.project-header__title {
    overflow-wrap: break-word;
}

.project-header__meta,
.project-header__time {
    margin: 0;
}

.project-header__slug {
    color: var(--ink-muted);
}

/* À partir de 768 px, les propriétés restent sur une ligne (chaque propriété peut rétrécir). */
@media (min-width: 768px) {
    .project-header__meta {
        flex-wrap: nowrap;
    }
}

.project-header__actions {
    align-items: center;
}

.project-header__notice {
    flex-basis: 100%;
    margin-top: 0;
}

.project-header__time {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    color: var(--ink-muted);
    font: var(--text-small);
}

/*
 * Sous 768 px, l'en-tête passe sur plusieurs lignes, resserré : le menu « Projet »
 * s'ouvre sous la rangée des actions, calé sur sa largeur, pour ne jamais sortir de l'écran
 * quelle que soit la place du bouton dans la rangée.
 */
@media (max-width: 767px) {
    .project-header {
        gap: var(--space-3);
        margin-top: var(--space-2);
    }

    .project-header__main {
        row-gap: var(--space-1);
    }

    .project-header__main,
    .project-header__actions {
        flex-basis: 100%;
    }

    .project-header__actions {
        position: relative;
    }

    .project-header__actions .action-menu {
        position: static;
    }

    .project-header__actions .action-menu__list {
        left: 0;
        right: auto;
        max-width: 100%;
    }
}

/*
 * Pastille du forfait (lot 142) : phrase écrite sur fond surface (posée sur le gris), trait
 * --line, rayon plein, durées en chiffres tabulaires ; le dépassement reprend l'étiquette
 * d'avertissement (triangle + mot, --warning sur --warning-soft), en pastille. Pas une commande :
 * ni bordure de contrôle, ni cible tactile.
 */
.time-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    max-width: 100%;
    padding: var(--space-tag) var(--space-3);
    border: var(--line-width) solid var(--line);
    border-radius: var(--radius-full);
    background: var(--surface);
    color: var(--ink);
    font: var(--text-label);
    font-variant-numeric: tabular-nums;
    white-space: normal;
}

.time-pill--overrun {
    border-color: var(--warning-soft);
    background: var(--warning-soft);
    color: var(--warning);
    font-weight: var(--font-weight-semibold);
}

/* Contact décideur : total et pastille en texte client (15/22). */
.client-view .project-header__time,
.client-view .time-pill {
    font: var(--text-body-client);
}

.client-view .time-pill--overrun {
    font-weight: var(--font-weight-semibold);
}

.client-time__total {
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

/*
 * Rapport de temps client, page « Temps passé » (lot 173, templates/project/time_report.html.twig) :
 * en-tête sur le fond gris (time-report__heading : titre et « Projet · Organisation »), choix de la
 * période (time-report__period : view-switch « Depuis le début » / « Un mois » pour un forfait
 * global, navigation au mois time-report__months), puis le bloc du forfait dans un panel
 * (time-report__package : titre, étiquette du dépassement, chiffres en phrases, barre de
 * consommation, rappel du forfait mensuel). Les blocs « Semaine par semaine » (lot 175,
 * time-chart) et « Tâche par tâche » (lot 174) se posent dessous, chacun dans son panel ; bouton
 * « Imprimer » (time-report__print) et feuille d'impression (lot 175) à la fin du bloc.
 */
.time-report__heading {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-4);
}

.time-report__context {
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-small);
}

.time-report__period {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4) var(--space-6);
    margin: 0 0 var(--space-6);
}

.time-report__switch .view-switch__list {
    margin: 0;
}

.time-report__switch .state-shape {
    flex: none;
    width: var(--shape-size);
    height: var(--shape-size);
}

/* Navigation au mois : « ‹ Octobre 2026 › », bloc blanc à bordure de contrôle, comme un champ. */
.time-report__months {
    display: inline-grid;
    grid-template-columns: var(--control-size) minmax(0, 1fr) var(--control-size);
    align-items: center;
    background: var(--field);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
}

.time-report__month {
    margin: 0;
    padding: 0 var(--space-4);
    color: var(--ink);
    font-weight: var(--font-weight-bold);
    text-align: center;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.time-report__month-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--control-size);
    height: var(--control-size);
    border-radius: var(--radius-md);
    color: var(--navy);
    font: var(--text-title-2);
    text-decoration: none;
}

.time-report__month-link:hover {
    background: var(--surface-hover);
    color: var(--navy-hover);
    text-decoration: none;
}

@media (max-width: 640px) {
    .time-report__months {
        display: grid;
        width: 100%;
    }
}

/* Bloc du forfait. */
.time-report__package {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.time-report__title-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
}

.time-report__title {
    margin: 0;
    color: var(--ink);
    font: var(--text-title-2);
}

.time-report__figures {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5) var(--space-7);
    margin: 0;
    padding: 0;
    list-style: none;
}

.time-report__figure {
    display: flex;
    flex-direction: column;
}

.time-report__value {
    color: var(--ink);
    font: var(--text-figure);
    font-variant-numeric: tabular-nums;
}

.time-report__value--main {
    color: var(--navy);
}

/* Dépassement : « + 1 h 30 » en ambre, dit aussi par le signe et par « au-delà du forfait ». */
.time-report__value--overrun {
    color: var(--warning);
}

.time-report__caption,
.time-report__scale,
.time-report__note {
    color: var(--ink-muted);
    font: var(--text-small);
}

.time-report__gauge-block {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/*
 * Barre de consommation (SVG, largeurs en attributs) : piste --surface-sunken bordée de
 * --line-strong, partie pleine marine, partie au-delà du forfait hachurée des tokens --warning et
 * --warning-soft (motif répété, seule exception au « pas de dégradé » de la charte), repère du
 * forfait en --ink. En niveaux de gris, les hachures restent distinctes de l'aplat marine.
 */
.time-report__gauge {
    height: var(--gauge-height);
    overflow: hidden;
    background: var(--surface-sunken);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-full);
}

.time-report__gauge-svg {
    display: block;
}

.time-report__gauge-used {
    fill: var(--navy);
}

.time-report__hatch-ground {
    fill: var(--warning-soft);
}

.time-report__hatch-stripe {
    fill: var(--warning);
}

.time-report__gauge-mark {
    fill: var(--ink);
}

.time-report__scale {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    margin: 0;
    font-variant-numeric: tabular-nums;
}

.time-report__note {
    margin: 0;
}

/*
 * Dates choisies (lot 174) : lien « Choisir des dates » à la suite de la navigation au mois (cible
 * de --control-size, 44 px au doigt), période appliquée écrite (time-report__applied), puis le
 * formulaire « Du » / « Au » / « Afficher » dans un panel sur toute la largeur (period-filter de
 * la page de l'équipe, champs à --text-input : 16 px sous 640 px).
 */
.time-report__dates-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    font-weight: var(--font-weight-medium);
}

.time-report__applied {
    flex: 1 1 100%;
    margin: 0;
    color: var(--ink);
    font-weight: var(--font-weight-bold);
}

/* Plus spécifique que « .period-filter », défini plus bas, pour prendre toute la largeur. */
.time-report__period .time-report__dates {
    flex: 1 1 100%;
    max-width: none;
    margin: 0;
}

.time-report__dates .period-filter__fields {
    max-width: var(--form-max);
}

.time-report__dates-help {
    margin: 0 0 var(--space-4);
    color: var(--ink-muted);
    font: var(--text-small);
}

@media (max-width: 640px) {
    .time-report__dates .period-filter__fields {
        flex-direction: column;
    }
}

/*
 * Forfait mensuel lu mois par mois (lot 174) : une ligne par mois, séparée par un trait ; mois en
 * gras, temps passé, puis le reste ou l'étiquette d'avertissement du dépassement (triangle et
 * texte), à droite ; les trois passent à la ligne au besoin.
 */
.time-report__month-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.time-report__month-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-5);
    padding: var(--space-3) 0;
    border-bottom: var(--line-width) solid var(--line);
    font-variant-numeric: tabular-nums;
}

.time-report__month-row:first-child {
    padding-top: 0;
}

.time-report__month-name {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

.time-report__month-balance {
    margin-left: auto;
}

/*
 * Répartition dans le temps (lot 175, templates/project/_time_report_chart.html.twig) : une
 * figure nommée (role="img"), une seule série en --navy, durée écrite sur chaque barre, aucune
 * couleur porteuse de sens. Semaine à venir : barre vide à trait pointillé --line-strong et
 * « à venir » écrit ; mois en cours : contour pointillé --navy sur le fond du panneau et
 * « (en cours) » écrit. Longueurs portées par les attributs width et height du SVG (même
 * pourcentage) ; la disposition fixe l'autre dimension en CSS, qui l'emporte sur l'attribut.
 * - Par défaut, et toujours au-delà de douze barres (time-chart--long) : barres horizontales,
 *   une ligne par barre (libellé, barre sur sa piste --surface-sunken, durée), comme sous 640 px.
 * - Au-delà de 640 px à l'écran, et à l'impression, jusqu'à douze barres : colonnes verticales,
 *   durée au-dessus de la barre, libellé dessous, sur un axe --line-strong.
 */
.time-report__chart {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.time-chart__bars {
    display: grid;
    grid-template-columns: fit-content(var(--chart-label-max)) minmax(0, 1fr) max-content;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.time-chart__item,
.time-chart__plot {
    display: contents;
}

.time-chart__label {
    color: var(--ink-muted);
    font: var(--text-small);
}

.time-chart__track {
    display: block;
    height: var(--chart-bar-thickness);
    overflow: hidden;
    background: var(--surface-sunken);
    border-radius: var(--radius-sm);
}

.time-chart__item--upcoming .time-chart__track {
    background: none;
}

.time-chart__bar {
    display: block;
    flex: none;
    overflow: visible;
}

.time-chart--long .time-chart__bar {
    height: 100%;
}

.time-chart__fill {
    fill: var(--navy);
}

.time-chart__bar--current {
    box-sizing: border-box;
    border: var(--indicator-width) dashed var(--navy);
    border-radius: var(--radius-sm);
}

.time-chart__bar--current .time-chart__fill {
    fill: none;
}

.time-chart__empty {
    display: block;
    box-sizing: border-box;
    height: 100%;
    border: var(--dash-width) dashed var(--line-strong);
    border-radius: var(--radius-sm);
}

.time-chart__value {
    color: var(--ink);
    font: var(--text-small);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

.time-chart__item--upcoming .time-chart__value {
    color: var(--ink-muted);
    font-weight: var(--font-weight-regular);
}

@media screen and (max-width: 640px) {
    .time-chart__bar {
        height: 100%;
    }
}

@media not screen, (width > 640px) {
    .time-chart:not(.time-chart--long) .time-chart__bars {
        grid-template-columns: none;
        grid-template-rows: var(--chart-height) auto;
        grid-auto-columns: minmax(0, 1fr);
        /* dense : chaque libellé (rangée 2) reste sous sa barre (rangée 1), une colonne par barre. */
        grid-auto-flow: column dense;
        align-items: stretch;
        gap: var(--space-2) 0;
    }

    .time-chart:not(.time-chart--long) .time-chart__plot {
        display: flex;
        grid-row: 1;
        flex-direction: column;
        align-items: center;
        justify-content: flex-end;
        gap: var(--space-1);
        box-sizing: border-box;
        height: var(--chart-height);
        padding: var(--space-6) var(--space-2) 0;
        border-bottom: var(--line-width) solid var(--line-strong);
    }

    .time-chart:not(.time-chart--long) .time-chart__track {
        display: contents;
    }

    .time-chart:not(.time-chart--long) .time-chart__bar {
        width: min(100%, var(--chart-bar-width));
    }

    .time-chart:not(.time-chart--long) .time-chart__bar--current {
        border-bottom: 0;
        border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    }

    .time-chart:not(.time-chart--long) .time-chart__empty {
        flex: 1 1 auto;
        width: min(100%, var(--chart-bar-width));
        height: auto;
        border-bottom: 0;
        border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    }

    .time-chart:not(.time-chart--long) .time-chart__value {
        order: -1;
        text-align: center;
    }

    .time-chart:not(.time-chart--long) .time-chart__label {
        grid-row: 2;
        padding: 0 var(--space-1);
        font: var(--text-caption);
        text-align: center;
    }
}

/*
 * Bloc « Tâche par tâche » (lot 174, templates/project/_time_report_tasks.html.twig) : tableau
 * dans un panel, en-têtes de colonnes en --ink-muted, lignes séparées par un trait, temps aligné à
 * droite en chiffres tabulaires ; « Autres travaux » sur --surface-sunken (reconnue par son
 * libellé, le fond n'est qu'un repère de plus) ; total en pied, en gras. Sous 640 px, à l'écran
 * seulement, liste empilée : titre et numéro, statut dessous, temps à droite ; imprimé, le tableau
 * reste déplié (lot 175).
 */
.time-report__tasks {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.time-report__empty {
    margin: 0;
    color: var(--ink-muted);
}

.time-report__table {
    width: 100%;
    border-collapse: collapse;
}

.time-report__table thead th {
    padding: var(--space-2) var(--space-4);
    border-bottom: var(--line-width) solid var(--line);
    color: var(--ink-muted);
    font: var(--text-caption);
    font-weight: var(--font-weight-medium);
    text-align: left;
}

.time-report__table tbody th,
.time-report__table tbody td {
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--line-width) solid var(--line);
    font-weight: var(--font-weight-regular);
    text-align: left;
    vertical-align: middle;
}

.time-report__table th:first-child,
.time-report__table td:first-child {
    padding-left: 0;
}

.time-report__table th:last-child,
.time-report__table td:last-child {
    padding-right: 0;
}

.time-report__table .time-report__time {
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
}

.time-report__table tbody .time-report__time {
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

.time-report__task {
    overflow-wrap: anywhere;
}

.time-report__task-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    font-weight: var(--font-weight-semibold);
    text-decoration: none;
}

.time-report__task-link:hover {
    text-decoration: underline;
}

.time-report__status {
    white-space: nowrap;
}

.time-report__status--none {
    color: var(--ink-muted);
}

.time-report__table .time-report__row--other th,
.time-report__table .time-report__row--other td {
    background: var(--surface-sunken);
}

.time-report__table .time-report__row--other th:first-child {
    padding-left: var(--space-3);
}

.time-report__table .time-report__row--other td:last-child {
    padding-right: var(--space-3);
}

.time-report__other {
    display: block;
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

.time-report__other-detail {
    display: block;
    color: var(--ink-muted);
    font: var(--text-small);
}

.time-report__table tfoot th,
.time-report__table tfoot td {
    padding: var(--space-3) var(--space-4) 0;
    color: var(--ink);
    font-weight: var(--font-weight-bold);
    text-align: left;
}

.time-report__table tfoot .time-report__time {
    text-align: right;
}

@media screen and (max-width: 640px) {
    .time-report__table,
    .time-report__table tbody,
    .time-report__table tfoot {
        display: block;
    }

    .time-report__table thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    .time-report__table tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: var(--space-1) var(--space-3);
        padding: var(--space-3) 0;
        border-bottom: var(--line-width) solid var(--line);
    }

    .time-report__table tbody th,
    .time-report__table tbody td,
    .time-report__table tfoot th,
    .time-report__table tfoot td {
        display: block;
        padding: 0;
        border: 0;
    }

    .time-report__table .time-report__task {
        grid-column: 1;
        grid-row: 1;
    }

    /* Numéro et titre côte à côte : un titre sur deux lignes ne laisse pas le numéro seul. */
    .time-report__table .time-report__row:not(.time-report__row--other) .time-report__task {
        display: flex;
        align-items: baseline;
        gap: var(--space-1);
    }

    .time-report__table .time-report__status {
        grid-column: 1;
        grid-row: 2;
        font: var(--text-small);
    }

    .time-report__table .time-report__time {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: start;
    }

    .time-report__table .time-report__status--none {
        display: none;
    }

    .time-report__table .time-report__row--other {
        padding-inline: var(--space-3);
        background: var(--surface-sunken);
    }

    .time-report__table .time-report__row--other th:first-child,
    .time-report__table .time-report__row--other td:last-child {
        padding-inline: 0;
    }

    .time-report__table tfoot tr {
        padding-bottom: 0;
        border-bottom: 0;
    }

    .time-report__table tfoot th {
        grid-column: 1;
        grid-row: 1;
    }

    .time-report__task-link {
        align-items: flex-start;
    }
}

/*
 * Bouton « Imprimer » (lot 175) : secondaire, à droite du choix de la période (44 px au doigt par
 * --control-size) ; masqué (hidden) tant que le contrôleur « print » ne l'a pas affiché.
 */
.time-report__print {
    margin-left: auto;
}

.time-report__print[hidden] {
    display: none;
}

/* Période écrite en tête de la page : à l'impression seulement. */
.time-report__print-period {
    display: none;
}

/*
 * Feuille d'impression du rapport de temps client (lot 175 ; CDC P0 § 13, « Impression ») : sans
 * l'en-tête du site, ni le lien d'évitement, ni les messages, ni le lien de retour, ni le choix de
 * la période (navigation, liens, formulaire des dates, bouton « Imprimer ») ; en tête, le titre
 * puis « Projet · Organisation · Période ». Palette claire réappliquée dans variables.css ; barres,
 * hachures, pistes et fonds imprimés tels quels (print-color-adjust) ; panneaux bordés d'un trait
 * plutôt que d'une ombre, non coupés entre deux pages quand c'est possible ; titres des tâches en
 * texte, sans l'adresse du lien. Les règles de la page ne visent que le rapport (:has).
 */
@media print {
    body:has(.time-report) {
        background: var(--surface);
    }

    body:has(.time-report) .skip-link,
    body:has(.time-report) .site-header,
    body:has(.time-report) .flash-region,
    .time-report__back,
    .time-report__period {
        display: none;
    }

    .time-report {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    .time-report__print-period {
        display: inline;
    }

    .time-report__context {
        color: var(--ink);
    }

    .time-report .panel {
        border: var(--line-width) solid var(--line);
        box-shadow: none;
        break-inside: avoid;
    }

    .time-report__title {
        break-after: avoid;
    }

    .time-report__table tr {
        break-inside: avoid;
    }

    .time-report__task-link {
        min-height: 0;
        color: var(--ink);
        text-decoration: none;
    }
}

/* Lecture côté client : texte courant en 15/22 (jamais plus grand), mêmes composants. */
.client-view {
    font: var(--text-body-client);
}

/*
 * Liste des studios de l'écran « Choisir un studio » (lot 111), dans un panneau sans marge
 * intérieure (panel--flush) : une ligne par studio, séparée par un trait ; le nom, le rôle écrit
 * et, à droite (dessous sur mobile), le bouton « Ouvrir ». Même présentation pour la liste des
 * invitations en attente (lot 116), dans sa propre section, avec deux boutons à droite.
 */
.studio-list,
.invitation-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.studio-list__item,
.invitation-list__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3) var(--space-5);
    padding: var(--space-4) var(--space-5);
    border-bottom: var(--line-width) solid var(--line);
}

.studio-list__item:last-child,
.invitation-list__item:last-child {
    border-bottom: 0;
}

.studio-list__text,
.invitation-list__text {
    flex: 1 1 0;
    min-width: 0;
}

.studio-list__name,
.invitation-list__name {
    margin: 0;
    color: var(--navy);
    font: var(--text-title-2);
    overflow-wrap: anywhere;
}

.studio-list__meta,
.invitation-list__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    margin: var(--space-1) 0 0;
    color: var(--ink-muted);
}

.studio-list__item form,
.invitation-actions form {
    margin: 0;
}

/* « Accepter l'invitation » et « Refuser » (lot 116) : côte à côte, l'un sous l'autre faute de place. */
.invitation-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

/* Page d'une invitation (lot 116) : rôle proposé en toutes lettres, puis ce qui suit l'acceptation. */
.invitation-summary {
    margin: var(--space-4) 0 0;
}

.invitation-summary dt {
    color: var(--ink-muted);
    font: var(--text-small);
}

.invitation-summary dd {
    margin: var(--space-1) 0 0;
}

.invitation-summary__help {
    display: block;
    margin-top: var(--space-1);
    color: var(--ink-muted);
}

.invitation-summary__next {
    margin: var(--space-4) 0 0;
    max-width: var(--measure-max);
}

/*
 * Tableau de données (DataTable), dans un panneau sans marge intérieure (panel--flush) : lignes
 * aérées séparées par un trait ; cartes empilées sur mobile (paires libellé / valeur), tableau à
 * partir de 768 px avec les en-têtes sur un bandeau surface-sunken. Une personne s'affiche avec
 * sa pastille d'initiales (Avatar), un état avec son étiquette (Badge : forme + mot).
 */
.data-table {
    width: 100%;
    border-collapse: collapse;
}

.data-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.data-table tr {
    display: block;
    padding: var(--space-3) var(--space-5);
    border-bottom: var(--line-width) solid var(--line);
}

.data-table tbody tr:last-child {
    border-bottom: 0;
}

.data-table th,
.data-table td {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    padding: var(--space-1) 0;
    text-align: left;
    font-weight: var(--font-weight-regular);
    /* Une adresse email longue passe à la ligne au lieu d'élargir la page. */
    overflow-wrap: anywhere;
}

.data-table__primary a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    font-weight: var(--font-weight-semibold);
}

/* Personne d'une ligne : pastille et nom à la taille du texte du tableau. */
.data-table .avatar {
    font: inherit;
}

.data-table__primary .avatar {
    font-weight: var(--font-weight-medium);
}

.data-table caption {
    text-align: left;
}

/*
 * Sur mobile, libellé dans une colonne fixe et valeur à côté : une valeur longue (adresse email)
 * passe à la ligne dans sa colonne au lieu de glisser sous son libellé.
 */
.data-table td {
    flex-wrap: nowrap;
    align-items: baseline;
}

.data-table__label {
    flex: none;
    width: var(--table-label-width);
    color: var(--ink-muted);
    font: var(--text-caption);
}

.data-table__actions {
    padding-top: var(--space-2);
}

/*
 * Plusieurs actions de ligne sur mobile : chacune garde son libellé sur une ligne et passe sous
 * la précédente faute de place, au lieu de se couper en deux.
 */
.data-table td.data-table__actions {
    flex-wrap: wrap;
}

.data-table__actions form {
    flex: none;
    max-width: 100%;
}

/* Bouton discret de ligne : son libellé s'aligne sur le texte des autres valeurs. */
.data-table__actions .button--ghost {
    margin-left: calc(-1 * var(--space-3));
}

/* Référence d'un projet dans un tableau (fiche d'une organisation, lot 150) : discrète, comme celle de l'en-tête du projet. */
.data-table__code {
    color: var(--ink-muted);
}

.data-table__row--muted .data-table__primary,
.data-table__row--muted .data-table__primary a,
.data-table__row--muted .data-table__primary .avatar {
    color: var(--ink-muted);
}

.data-table__actions form {
    margin: 0;
}

/*
 * Page du Backlog (data-table) : case de sélection du passage groupé (cible de 28 px, 44 px au
 * doigt), rang, et par ligne la poignée du glisser-déposer avec « Monter » / « Descendre ».
 * Sous 768 px, la case occupe une colonne à gauche de la carte de la tâche.
 */
/* Tâche invisible du client (équipe seulement) : étiquette sous le titre. */
.backlog-table__visibility {
    display: flex;
    width: fit-content;
    margin-top: var(--space-1);
}

.backlog-table__choice {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--choice-size);
    min-height: var(--choice-size);
    cursor: pointer;
}

.backlog-table__checkbox {
    width: var(--choice-input-size);
    height: var(--choice-input-size);
    margin: 0;
    accent-color: var(--navy);
    cursor: pointer;
}

.backlog-table__rank {
    font-variant-numeric: tabular-nums;
}

/* En-tête « Rang » sur une ligne : la colonne, étroite, ne coupe pas le mot. */
.data-table th.backlog-table__rank {
    white-space: nowrap;
}

.data-table td.backlog-table__order {
    flex-wrap: wrap;
    align-items: center;
}

.backlog-table__order form {
    display: inline-block;
    vertical-align: middle;
}

.backlog-table__handle {
    display: inline-block;
    vertical-align: middle;
}

.backlog-table__row--ghost {
    background: var(--navy-soft);
    outline: var(--focus-width) dashed var(--navy);
    outline-offset: calc(-1 * var(--focus-width));
}

.backlog-table__row--chosen {
    background: var(--surface);
    box-shadow: var(--shadow-float);
}

.backlog-table__row[aria-busy="true"] {
    color: var(--ink-muted);
}

/*
 * Écran « Archives » d'un projet (lot 129) : recherche par titre dans un panneau (champ, bouton
 * « Rechercher » et lien pour effacer, côte à côte dès que la place le permet), liste des tâches
 * archivées (data-table) puis pagination « Précédent » / « Page N sur M » / « Suivant ».
 */
.archive-search {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3) var(--space-4);
}

.archive-search .form-field {
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
}

.archive-search__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-4);
}

.archive-search__clear,
.pagination__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

.pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3) var(--space-5);
    margin-top: var(--space-5);
}

.pagination__current {
    margin: 0;
    color: var(--ink-muted);
}

/* « Suivant » reste à droite, même sans « Précédent ». */
.pagination__link[rel="next"] {
    margin-left: auto;
}

/*
 * Matrice des permissions (page « Permissions » de l'Admin), en lecture seule : vrai tableau à
 * toutes les tailles, qui défile dans son conteneur (région focalisable au clavier), jamais la
 * page ; la colonne des permissions reste fixe pendant le défilement. Une case se lit par son mot :
 * « Oui » et « Toutes » précédés d'une coche et en gras, « Non » sans forme et atténué.
 */
.matrix-scroll {
    overflow-x: auto;
}

.matrix-scroll:focus-visible {
    /* Anneau dessiné à l'intérieur : le panneau sans marge coupe ce qui dépasse. */
    outline-offset: calc(-1 * var(--focus-width));
}

.matrix-table {
    min-width: 100%;
    border-collapse: separate;
    border-spacing: 0;
}

.matrix-table th,
.matrix-table td {
    padding: var(--space-3) var(--space-4);
    border-bottom: var(--line-width) solid var(--line);
    text-align: left;
    vertical-align: top;
    white-space: nowrap;
}

.matrix-table thead th {
    background: var(--surface-sunken);
    color: var(--ink-muted);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
}

.matrix-table tbody tr:last-child th,
.matrix-table tbody tr:last-child td {
    border-bottom: 0;
}

.matrix-table .matrix-table__permission {
    position: sticky;
    left: 0;
    z-index: 1;
    width: var(--matrix-permission-width);
    min-width: var(--matrix-permission-width);
    background: var(--surface);
    border-right: var(--line-width) solid var(--line);
    white-space: normal;
}

.matrix-table tbody .matrix-table__permission {
    font-weight: var(--font-weight-regular);
}

.matrix-table thead .matrix-table__permission {
    background: var(--surface-sunken);
}

.matrix-table__cell--full {
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

.matrix-table__cell--full .state-shape {
    margin-right: var(--space-1);
    vertical-align: -2px;
}

.matrix-table__cell--none {
    color: var(--ink-muted);
}

.matrix-notes {
    padding: var(--space-4) var(--space-5);
    border-top: var(--line-width) solid var(--line);
    color: var(--ink-muted);
    font: var(--text-caption);
}

.matrix-notes p {
    max-width: var(--measure-max);
    margin: 0;
}

.matrix-notes p + p {
    margin-top: var(--space-2);
}

@media (min-width: 768px) {
    .matrix-table .matrix-table__permission {
        width: var(--matrix-permission-width-wide);
        min-width: var(--matrix-permission-width-wide);
    }
}

/*
 * Page « Temps » d'un projet : panneau de la période avec le total en premier, en grand, séparé
 * par un trait du filtre « Du » / « Au » (côte à côte, même à 360 px) et de son bouton dessous.
 */
.period-total {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-3);
    margin: 0 0 var(--space-5);
    padding-bottom: var(--space-5);
    border-bottom: var(--line-width) solid var(--line);
}

.period-total__label {
    color: var(--ink-muted);
}

.period-total__value {
    color: var(--ink);
    font: var(--text-title-1);
}

.period-filter {
    max-width: var(--form-max);
}

.period-filter__fields {
    display: flex;
    gap: var(--space-3);
}

.period-filter__fields .form-field {
    flex: 1 1 0;
    min-width: 0;
    margin-bottom: 0;
}

.period-filter__fields .form-field__input {
    min-width: 0;
}

.period-filter__actions {
    margin-top: var(--space-4);
}

/* Tableau des entrées : date d'un bloc ; lien de tâche à la taille d'une cible ; une note longue passe à la ligne. */
.time-table__date {
    white-space: nowrap;
}

.time-table__task a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

.time-table__note {
    overflow-wrap: anywhere;
}

/* Sur mobile, une cellule sans valeur (pas de note, pas d'action) n'affiche pas son seul libellé. */
.data-table td.time-table__cell--empty {
    display: none;
}

/*
 * Section d'une page sous l'en-tête (projets actifs, collaborateurs affectés d'un projet) : titre
 * de section posé sur le fond gris, contenu dans ses panneaux.
 */
.page-section {
    margin-top: var(--space-7);
}

/*
 * Encart « Pour commencer » de l'accueil de l'Admin (lot 171) : panneau blanc en tête de page,
 * titre et bouton « Fermer » sur une ligne (section-header), liste ordonnée des trois étapes,
 * chacune avec sa forme (cercle vide à faire, cercle plein coché faite), son lien et son état écrit.
 * Liens et bouton de control-size-sm : 44 px au doigt.
 */
.getting-started__header {
    margin-bottom: var(--space-2);
}

.getting-started__intro {
    margin: 0 0 var(--space-3);
    color: var(--ink-muted);
}

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

.getting-started__step {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    padding: var(--space-1) 0;
}

.getting-started__step + .getting-started__step {
    border-top: var(--line-width) solid var(--line);
}

.getting-started__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size-sm);
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
}

.getting-started__state {
    color: var(--ink-muted);
    font: var(--text-small);
}

.getting-started__step--done .getting-started__state {
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

/* Titre de la page, qui reçoit le focus à la fermeture de l'encart (tabindex="-1") : anneau seulement au clavier. */
.getting-started__page-title:focus {
    outline: none;
}

.getting-started__page-title:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/* Message de la fermeture, annoncé (role="status") : zone vide dès le chargement, sans display: none. */
.getting-started__feedback .flash {
    margin-bottom: 0;
}

/* Juste sous l'en-tête de page ou en tête de la zone sous la bande : la marge de ce qui précède suffit. */
.page-header + .page-section,
.site-main--after-band > .page-section:first-child {
    margin-top: 0;
}

.page-section__intro {
    max-width: var(--measure-max);
    color: var(--ink-muted);
}

/*
 * Kanban d'un projet, sur la bande marine : listes arrondies grises (list, radius-xl, shadow-list),
 * cartes blanches détachées (surface, radius-lg, shadow-card). Listes empilées sur mobile (ou en
 * onglets avec JavaScript, sous 768 px), deux à partir de 768 px, quatre à partir de 1024 px ;
 * jamais de défilement horizontal de la page.
 * Focus : anneau blanc sur le marine (règle de .band), navy dans les listes et le menu.
 */
.kanban {
    position: relative;
}

.kanban__column :focus-visible {
    outline-color: var(--focus-ring);
}

/* Titre « Tâches · 4 » en blanc (11,9:1 sur board), total et aide en on-board-muted (8:1). */
.kanban__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-4);
}

.kanban__header h2 {
    margin: 0;
    color: var(--on-board);
    font: var(--text-board-title);
}

.kanban__total,
.kanban__help {
    color: var(--on-board-muted);
    font-weight: var(--font-weight-regular);
    font-variant-numeric: tabular-nums;
}

.kanban__help {
    margin: 0;
    font: var(--text-caption);
}

/*
 * Barre de filtres du kanban (lot 140), posée sur le fond gris (canvas) entre l'en-tête du projet
 * et la bande marine (lot 141), en pastilles nommées qui écrivent leur valeur (« Assignée :
 * toutes »). Pastille au repos : fond surface, trait line-strong (3:1 sur canvas), texte ink.
 * Pastille active : fond navy plein, texte on-navy (11,9:1), coche devant la valeur : la forme et
 * le mot la distinguent, pas la teinte. Les pastilles passent à la ligne, jamais en défilement de
 * page ; sous 768 px, avec JavaScript, la barre est repliée derrière le bouton « Filtres ».
 */
.kanban-filters {
    margin-bottom: var(--space-5);
}

.kanban-filters__toggle,
.kanban-filters__submit[hidden] {
    display: none;
}

.kanban-filters__body {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.kanban-filters__pill {
    position: relative;
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    min-width: 0;
    min-height: var(--control-size);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-full);
    background: var(--surface);
    color: var(--ink);
}

.kanban-filters__pill--active {
    border-color: var(--navy);
    background: var(--navy);
    color: var(--on-navy);
}

.kanban-filters__pill > .state-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
    pointer-events: none;
}

/*
 * Pastille d'une liste (lot 154) : « Nom : valeur » puis le chevron, à --space-2 du texte ; la
 * liste native couvre toute la pastille, invisible, et reste le champ (clic, clavier, lecteurs
 * d'écran). La pastille prend la largeur du texte affiché, pas celle de la plus longue option.
 */
.kanban-filters__pill:has(.kanban-filters__select) {
    gap: var(--space-2);
    padding: 0 var(--space-4);
}

.kanban-filters__shown {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-width: 0;
    font: var(--text-label);
    white-space: nowrap;
    pointer-events: none;
}

.kanban-filters__value {
    overflow: hidden;
    max-width: 16rem;
    font-weight: var(--font-weight-semibold);
    text-overflow: ellipsis;
}

.kanban-filters__chevron {
    flex: none;
    margin-left: calc(var(--space-2) - var(--space-1));
}

.kanban-filters__select {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    opacity: 0;
    appearance: none;
    font: var(--text-label);
    cursor: pointer;
}

/* Contraste élevé : le fond marine disparaît, un contour épais marque le filtre actif. */
@media (forced-colors: active) {
    .kanban-filters__pill--active {
        border: calc(2 * var(--line-width)) solid Highlight;
    }
}

/* Liste ouverte : options sur fond clair, quelle que soit la pastille. */
.kanban-filters__select option {
    background: var(--surface);
    color: var(--ink);
}

.kanban-filters__pill--check {
    gap: var(--space-2);
    padding: 0 var(--space-4);
    cursor: pointer;
}

.kanban-filters__pill:has(:focus-visible) {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

.kanban-filters__pill :focus-visible {
    outline: none;
}

/* « Mes tâches » : bouton qui s'allume ; la case native reste le champ, masquée sur la pastille. */
.kanban-filters__checkbox {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.kanban-filters__check-label {
    font: var(--text-label);
    font-weight: var(--font-weight-semibold);
}

.kanban-filters__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
    min-height: var(--control-size);
    margin-left: var(--space-2);
}

.kanban-filters__summary {
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.kanban-filters__clear {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    font: var(--text-label);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

@media (max-width: 767px) {
    .kanban-filters--enhanced .kanban-filters__toggle {
        display: inline-flex;
    }

    .kanban-filters--enhanced:not(.kanban-filters--open) .kanban-filters__body {
        display: none;
    }

    .kanban-filters--enhanced .kanban-filters__body {
        margin-top: var(--space-3);
    }

    .kanban-filters__actions {
        margin-left: 0;
    }
}

/* Messages du glisser-déposer : restent visibles pendant le défilement du kanban. */
.kanban__feedback,
.backlog__feedback {
    position: sticky;
    top: var(--space-2);
    z-index: 4;
}

/* Régions annoncées : toujours rendues (jamais display: none), sans hauteur quand elles sont vides. */
.kanban__message .flash,
.backlog__message .flash {
    margin-bottom: var(--space-2);
}

.kanban__close[hidden],
.backlog__close[hidden] {
    display: none;
}

.kanban__close,
.backlog__close {
    display: block;
    min-height: var(--control-size-sm);
    margin: 0 0 var(--space-4) auto;
    padding: 0 var(--space-3);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--navy);
    font: var(--text-button);
    cursor: pointer;
}

.kanban__close:hover,
.backlog__close:hover {
    background: var(--surface-hover);
}

.kanban__columns {
    display: grid;
    gap: var(--space-4);
    align-items: start;
}

.kanban__column {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
    padding: var(--space-2) var(--space-2) var(--space-3);
    border-radius: var(--radius-xl);
    background: var(--list);
    box-shadow: var(--shadow-list);
}

/* « En cours » : bandeau list-active, texte navy (9,5:1), compteur navy plein. */
.kanban__column--active .kanban__title {
    background: var(--list-active);
    color: var(--navy);
}

.kanban__column--active .kanban__title .task-status {
    color: var(--navy);
}

.kanban__column--active .kanban__count {
    background: var(--navy);
    color: var(--on-navy);
}

/* « Terminé » : liste un cran plus foncée, titre ink-done (5,4:1 sur list-done). */
.kanban__column--done {
    background: var(--list-done);
}

.kanban__column--done .kanban__title,
.kanban__column--done .kanban__title .task-status {
    color: var(--ink-done);
}

/* Liste survolée pendant le glisser-déposer : contour blanc en pointillés, visible sur le marine. */
.kanban__column--over {
    outline: var(--focus-width) dashed var(--on-board);
    outline-offset: var(--focus-offset);
}

.kanban__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    padding: var(--space-2);
    border-radius: var(--radius-md);
    color: var(--ink);
    font: var(--text-column-title);
}

.kanban__title .task-status {
    font: var(--text-column-title);
}

.kanban__counter {
    display: inline-flex;
    margin-left: auto;
}

/* Compteur d'une liste : pastille blanche (ink gras 12,3:1). */
.kanban__count {
    background: var(--count-pill);
}

/*
 * Bouton du Backlog replié : masqué sans JavaScript et sous 768 px (onglet de colonne) ; voir la
 * requête « min-width: 768px » plus bas.
 */
.kanban__fold {
    display: none;
}

.kanban__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* Zone de dépôt d'une liste vide, pour le glisser-déposer. */
.kanban__list[data-kanban-target] {
    min-height: var(--control-height-sm);
}

.kanban__empty {
    margin: 0;
    padding: var(--space-2);
    color: var(--ink-muted);
    font: var(--text-caption);
}

/* « Voir tout le Backlog (N tâches) » : lien sous les premières cartes du Backlog. */
.kanban__more {
    display: flex;
    align-items: center;
    min-height: var(--control-size);
    padding: 0 var(--space-2);
    font: var(--text-button);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

.kanban__more[hidden] {
    display: none;
}

/* « + Ajouter une tâche » en bas d'« À faire » : lien discret, pleine largeur de la liste. */
.kanban__add {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-size);
    padding: 0 var(--space-2);
    border-radius: var(--radius-md);
    color: var(--ink);
    font: var(--text-button);
}

.kanban__add:hover {
    background: var(--list-hover);
    color: var(--ink);
    text-decoration: none;
}

.plus-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
}

.task-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
    padding: var(--space-3);
    background: var(--card);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

/* Priorité haute : filet gauche ambre de 3 px (seule bordure gauche colorée admise). */
.task-card--priority-high {
    border-left: var(--priority-rule-width) solid var(--priority-high);
    padding-left: calc(var(--space-3) - var(--priority-rule-width));
}

/* Tâche terminée : fond card-done, titre ink-done barré (6,1:1 en clair, 4,9:1 en sombre). */
.task-card--done {
    background: var(--card-done);
}

.task-card--done .task-card__title {
    color: var(--ink-done);
    font-weight: var(--font-weight-medium);
    text-decoration: line-through;
    text-decoration-color: var(--line-strong);
}

.task-card[aria-busy="true"] {
    opacity: 0.7;
    cursor: progress;
}

/* Carte de la tâche ouverte dans le panneau (charte de la phase 9) : contour marine plein, doublé
   de aria-current sur son lien ; l'anneau de focus du lien, décalé, reste visible par-dessus. */
.task-card:has(.task-card__title[aria-current="true"]) {
    outline: var(--focus-width) solid var(--navy);
    outline-offset: 0;
}

/* Emplacement de la carte pendant le glisser-déposer. */
.task-card--ghost {
    background: var(--navy-soft);
    box-shadow: none;
    outline: var(--focus-width) dashed var(--navy);
    outline-offset: calc(-1 * var(--focus-width));
}

/* Carte prise et glissée : elle flotte. */
.task-card--chosen {
    box-shadow: var(--shadow-float);
}

.task-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-2);
}

/* Numéro court (lot 147) au-dessus du titre, sur sa propre ligne discrète. */
.task-card__name {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.task-card__title {
    display: inline-flex;
    align-items: center;
    min-height: var(--target-min);
    color: var(--navy);
    font: var(--text-card-title);
    overflow-wrap: anywhere;
}

/* La carte entière ouvre le panneau : le lien du titre est étendu à toute la carte. */
.task-card__title::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: var(--radius-lg);
}

/* Poignée au-dessus du lien étendu : elle reste saisissable. */
.task-card__handle {
    position: relative;
    z-index: 1;
}

/*
 * Poignée de glisser-déposer (équipe seulement) : six points, 24 px sur ordinateur, 44 px au doigt.
 * Le rembourrage centre la zone des points dans la cible, quelle que soit sa taille.
 */
.task-card__handle {
    --handle-size: var(--target-min);
    flex: none;
    width: var(--handle-size);
    height: var(--handle-size);
    padding: calc((var(--handle-size) - var(--handle-dots-height)) / 2) calc((var(--handle-size) - var(--handle-dots-width)) / 2);
    border-radius: var(--radius-sm);
    color: var(--line-strong);
    background-image: radial-gradient(circle, currentColor var(--handle-dot-radius), transparent var(--handle-dot-fade));
    background-size: var(--handle-dot-step) var(--handle-dot-step);
    background-origin: content-box;
    background-clip: content-box;
    cursor: grab;
    touch-action: none;
}

.task-card__handle:hover {
    background-color: var(--list);
}

.task-card__handle:active {
    cursor: grabbing;
}

/* Priorité haute seulement (les autres se lisent dans le panneau), sur sa propre ligne. */
.task-card > .task-priority {
    align-self: flex-start;
}

/* Tâche invisible du client (équipe seulement), sur sa propre ligne. */
.task-card > .task-card__visibility {
    align-self: flex-start;
}

/*
 * Pied de la carte compacte (lot 141) : pastille d'initiales seule (nom lu et en infobulle),
 * étiquettes, puis nombre de pièces jointes à droite (texte ink-muted, 5,5:1 sur surface).
 */
.task-card__footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.task-card__assignee {
    display: flex;
    flex: none;
    margin: 0;
}

.task-card__labels {
    min-width: 0;
}

.task-card__attachments {
    margin: 0 0 0 auto;
    color: var(--ink-muted);
    font: var(--text-caption);
    white-space: nowrap;
}

/* Carte qui ne peut aller nulle part : pas de poignée. */
.task-card__handle[hidden] {
    display: none;
}

/* Onglets de colonnes : masqués sans JavaScript et à partir de 768 px (voir la requête plus bas). */
.kanban__tabs {
    display: none;
}

/* position: relative : le libellé masqué du nombre reste dans la rangée qui défile (pas de débordement de la page). */
.kanban__tab {
    position: relative;
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--touch-target);
    padding: 0 var(--space-4);
    border: 0;
    border-bottom: var(--indicator-width) solid transparent;
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    background: transparent;
    color: var(--on-board-muted);
    font: var(--text-title-3);
    white-space: nowrap;
    scroll-snap-align: start;
    cursor: pointer;
}

.kanban__tab:hover {
    color: var(--on-board);
}

/* Onglet actif : fond clair et texte navy (la clarté), trait navy dessous ; jamais d'orange. */
.kanban__tab[aria-selected="true"] {
    background: var(--list);
    color: var(--navy);
    border-bottom-color: var(--navy);
}

.kanban__tab .status-shape {
    flex: none;
    width: var(--shape-size);
    height: var(--shape-size);
    color: currentColor;
}

.kanban__tab-count {
    background: var(--count-pill);
}

/*
 * Panneau de tâche (lot 134) : cadre Turbo « task-panel » de la fiche projet
 * (templates/task/_panel_frame.html.twig) et son panneau blanc (templates/task/_panel.html.twig).
 * - Sous 768 px : le panneau occupe tout l'écran ; l'en-tête du site et le reste de la page sont
 *   masqués tant qu'il est ouvert, « Retour au kanban » en tête (44 px au doigt), pas de croix.
 * - De 768 à 1023 px : panneau fixe à droite (shadow-panel : liseré et ombre vers la gauche, lot 154), sur toute la hauteur, qui recouvre la
 *   droite du kanban ; il défile seul.
 * - À partir de 1024 px : main passe en grille, le contenu de la page à gauche et le panneau à
 *   droite (task-panel-width) ; le panneau colle au haut de l'écran pendant le défilement et
 *   défile seul ; les listes du kanban rétréci gardent une largeur minimale et défilent dans le
 *   kanban, jamais la page.
 * Contenu en une colonne : sections séparées par un trait (task-panel__section, titre h3).
 * Courte animation d'entrée à l'ouverture depuis une carte (task-panel--opening, posée par le
 * contrôleur), coupée par prefers-reduced-motion.
 */
.task-panel-frame {
    display: block;
}

.task-panel {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    min-width: 0;
    padding: var(--space-5) var(--space-6) var(--space-7);
    background: var(--surface);
}

.task-panel--opening {
    animation: task-panel-in var(--motion-panel) ease-out;
}

@keyframes task-panel-in {
    from {
        opacity: 0;
        transform: translateX(var(--space-5));
    }
}

/*
 * Numéro court d'une tâche (lot 147, composant TaskNumber) : « #12 » en Space Mono, discret.
 * Dans un lien, il reste en --ink-muted : le titre porte la couleur du lien.
 */
.task-number {
    color: var(--ink-muted);
    font: var(--text-mono);
    white-space: nowrap;
}

.task-panel__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2) var(--space-4);
}

.task-panel__back {
    display: none;
}

/* Fil d'Ariane « Projet › #12 » (lot 147), à gauche de la barre ; les actions restent à droite. */
.task-panel__crumb {
    min-width: 0;
    margin: 0 auto 0 0;
    color: var(--ink-muted);
    font: var(--text-caption);
    overflow-wrap: anywhere;
}

.task-panel__crumb-separator {
    margin: 0 var(--space-1);
}

/* Indice « Échap pour fermer » : seulement avec JavaScript, au clavier (masqué au doigt). */
.task-panel__hint {
    display: none;
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.task-panel-frame--enhanced .task-panel__hint {
    display: block;
}

.task-panel__close {
    gap: var(--space-1);
}

/*
 * Menu « Plus d'actions » de la barre du panneau (lot 136) : bouton secondaire au libellé écrit
 * (summary d'un details natif), jamais caché au survol ; liste flottante (shadow-float) d'entrées
 * de 32 px (44 px au doigt), calée à droite du bouton.
 */
.action-menu {
    position: relative;
}

.action-menu[open] {
    z-index: 4;
}

.action-menu > summary {
    list-style: none;
}

.action-menu > summary::-webkit-details-marker {
    display: none;
}

.action-menu__toggle {
    cursor: pointer;
}

.action-menu__list {
    position: absolute;
    top: calc(100% + var(--space-1));
    right: 0;
    width: var(--action-menu-width);
    max-width: calc(100vw - 2 * var(--space-5));
    margin: 0;
    padding: var(--space-1);
    list-style: none;
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
}

.action-menu__item {
    display: flex;
    align-items: center;
    min-height: var(--control-size);
    padding: 0 var(--space-2);
    border-radius: var(--radius-sm);
    color: var(--ink);
    font: var(--text-small);
    text-decoration: none;
}

.action-menu__item:hover {
    background: var(--surface-hover);
}

/* Entrée qui envoie un formulaire (« Archiver le projet ») : même aspect qu'un lien du menu. */
.action-menu__form {
    margin: 0;
}

button.action-menu__item {
    width: 100%;
    border: 0;
    background: none;
    text-align: left;
    cursor: pointer;
}

/*
 * Création d'une tâche dans le panneau (lot 143, task/_create_panel.html.twig) : le formulaire
 * de la page « Créer une tâche », sans bloc blanc autour (le panneau en est déjà un).
 */
.task-create__body {
    min-width: 0;
}

/*
 * Raccourcis clavier (lot 143). Indice de touche sur « Créer une tâche » (shortcut-hint, lettre
 * écrite depuis data-key, hors du nom du lien) : trait de la couleur du texte du bouton, masqué au
 * doigt et aux lecteurs d'écran (aria-keyshortcuts).
 * Aide de l'en-tête du kanban (shortcuts, project/_shortcuts_help.html.twig) : même bloc que les
 * menus nommés (action-menu), liste de touches (kbd) suivies de leur effet écrit.
 */
.shortcut-hint {
    margin-left: var(--space-2);
    padding: 0 var(--space-1);
    border: var(--line-width) solid currentColor;
    border-radius: var(--radius-sm);
    font: var(--text-mono);
}

.shortcut-hint::before {
    content: attr(data-key);
}

@media (pointer: coarse) {
    .shortcut-hint {
        display: none;
    }
}

.shortcuts {
    margin-left: auto;
}

/* Touches à gauche, effet à droite, alignés en deux colonnes. */
.shortcuts__list {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: baseline;
    gap: var(--space-2) var(--space-3);
    width: var(--shortcuts-width);
    padding: var(--space-3);
}

.shortcuts__item {
    display: contents;
}

.shortcuts__item[hidden] {
    display: none;
}

.shortcuts__keys {
    flex: none;
    color: var(--ink-muted);
    font: var(--text-small);
}

.shortcuts__key {
    display: inline-block;
    padding: 0 var(--space-1);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
    color: var(--ink);
    font: var(--text-mono);
}

.shortcuts__effect {
    margin: 0;
    color: var(--ink);
    font: var(--text-small);
}

/* Introduction d'une étape chargée dans le panneau (fusion). */
.task-panel__intro {
    max-width: var(--measure-max);
    margin: 0;
    color: var(--ink-muted);
}

/* Refus ouvert depuis « Plus d'actions » : bouton de confirmation puis « Annuler ». */
.task-rejection__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
}

.task-panel__header {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
}

.task-panel__title {
    margin: 0;
    color: var(--ink);
    font: var(--text-title-2);
    overflow-wrap: anywhere;
}

.task-panel__meta {
    margin: 0;
}

.task-panel .flash-region {
    margin-bottom: 0;
}

/*
 * Titre et description modifiables sur place (lot 137) : « Modifier le titre » ou « Modifier la
 * description » (summary d'un details natif) ouvre le champ à la place du texte, qui est masqué
 * tant qu'il est ouvert ; « Enregistrer » et « Annuler » en dessous. Le titre et le texte de la
 * description prennent surface-hover au survol (un clic les ouvre aussi) ; le clavier passe par
 * le bouton nommé. Sans JavaScript, le details s'ouvre nativement.
 */
.property--title {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    width: 100%;
}

.task-panel__title--editable {
    margin-left: calc(-1 * var(--space-2));
    padding: 0 var(--space-2);
    border-radius: var(--radius-md);
    cursor: text;
}

.task-panel__title--editable:hover {
    background: var(--surface-hover);
}

.property--title:has(> .inline-edit[open]) > .task-panel__title,
.property--description:has(> .inline-edit[open]) > .task-description {
    display: none;
}

.inline-edit {
    width: 100%;
    min-width: 0;
}

.inline-edit > summary {
    list-style: none;
}

.inline-edit > summary::-webkit-details-marker {
    display: none;
}

.inline-edit[open] > summary {
    display: none;
}

.inline-edit__form {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
}

.inline-edit__form .form-field {
    margin: 0;
}

.inline-edit__form .property-edit__help {
    margin: 0;
}

.inline-edit__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.property--description {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
}

/* Description sur surface-sunken ; ses blocs de code et citations passent sur surface. */
.task-description {
    width: 100%;
    min-width: 0;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    overflow-wrap: anywhere;
}

.task-description > :last-child,
.task-description .markdown > :last-child {
    margin-bottom: 0;
}

.task-description .markdown code,
.task-description .markdown pre,
.task-description .markdown blockquote {
    background: var(--surface);
}

.task-description .markdown pre code {
    background: none;
}

.task-description--editable {
    cursor: text;
}

.task-description--editable:hover {
    background: var(--surface-hover);
}

/*
 * Barre de l'éditeur dans le panneau : les boutons de mise en forme tiennent sur une ligne qui
 * défile dans son propre conteneur (la flèche ou le focus y amène le bouton suivant), « Markdown
 * brut » restant à côté ; jamais de défilement horizontal de la page.
 */
.task-panel .markdown-editor__bar {
    flex-wrap: nowrap;
    align-items: center;
}

.task-panel .markdown-editor__toolbar {
    flex: 1 1 auto;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: thin;
    /* Place pour l'anneau de focus, que le défilement couperait. */
    margin-block: calc(-1 * (var(--focus-width) + var(--focus-offset)));
    padding: calc(var(--focus-width) + var(--focus-offset));
}

.task-panel .markdown-editor__toolbar > .button,
.task-panel .markdown-editor__raw {
    flex: none;
}

/* La pull request garde son lien ; « Modifier » vient à côté. */
.property__value {
    display: block;
    min-width: 0;
}

.task-panel__section {
    min-width: 0;
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.task-panel__section > :last-child {
    margin-bottom: 0;
}

.task-panel__section form {
    margin: 0;
}

.task-panel__section-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-4);
    color: var(--ink);
    font: var(--text-title-3);
}

/*
 * Onglets « Commentaires », « Historique », « Temps » du panneau (lot 139, task/_tabs.html.twig,
 * contrôleur « task-tabs »). Sans JavaScript, la rangée est masquée et les sections s'empilent,
 * titrées. Avec JavaScript (task-tabs--active), la rangée est sous un trait, une seule section
 * affichée, son titre h3 lu par les lecteurs d'écran seulement (l'onglet le porte à l'écran).
 * Onglet choisi : texte marine en gras et trait marine dessous (forme et clarté, jamais la teinte
 * seule) ; les autres en texte courant gris. La rangée défile dans son propre conteneur à 360 px.
 */
.task-tabs--active {
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.task-tabs__list {
    display: flex;
    gap: var(--space-1);
    margin: 0 0 var(--space-4);
    overflow-x: auto;
    border-bottom: var(--line-width) solid var(--line);
    scrollbar-width: none;
}

.task-tabs__list[hidden],
.task-tabs__panel[hidden] {
    display: none;
}

.task-tabs__tab {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-size);
    padding: 0 var(--space-3);
    border: 0;
    border-bottom: var(--indicator-width) solid transparent;
    background: transparent;
    color: var(--ink-muted);
    font: var(--text-body);
    white-space: nowrap;
    cursor: pointer;
}

.task-tabs__tab:hover {
    color: var(--ink);
}

/* Anneau à l'intérieur de l'onglet : la rangée qui défile le couperait au-dehors. */
.task-tabs__tab:focus-visible {
    outline-offset: calc(-1 * var(--focus-width));
}

.task-tabs__tab[aria-selected="true"] {
    border-bottom-color: var(--navy);
    color: var(--navy);
    font: var(--text-title-3);
    font-weight: var(--font-weight-bold);
}

.task-tabs--active .task-tabs__panel {
    padding-top: 0;
    border-top: 0;
}

.task-tabs--active .task-tabs__heading {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/*
 * Formulaires repliés du panneau (lot 139, contrôleur « compose ») : commentaire derrière une
 * ligne « Écrire un commentaire… » à l'aspect de champ, saisie du temps derrière « + Saisir ».
 * « Annuler » n'existe qu'avec JavaScript ; sans lui, les formulaires restent dépliés.
 */
.compose [hidden] {
    display: none;
}

.compose:not(.compose--enhanced) .compose__cancel {
    display: none;
}

.compose__opener--line {
    display: block;
    width: 100%;
    min-height: var(--control-size);
    padding: 0 var(--space-3);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--field);
    color: var(--ink-muted);
    font: var(--text-body);
    text-align: left;
    cursor: text;
}

.compose__opener--line:hover {
    background: var(--surface-hover);
}

/* Temps total des propriétés, suivi de « + Saisir ». */
.property-time {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-3);
}

/* Modification ou confirmation de suppression d'une entrée, chargée dans l'onglet « Temps ». */
.time-action {
    display: block;
}

.time-action:not(:empty) {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}

.time-action__title:focus {
    outline: none;
}

.time-action__title:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

@media (max-width: 767px) {
    body:has(.task-panel) .site-header,
    main:has(> .task-panel-frame .task-panel) > :not(.task-panel-frame) {
        display: none;
    }

    .task-panel {
        min-height: 100dvh;
        padding: var(--space-4) var(--space-5) var(--space-7);
    }

    .task-panel__back {
        display: inline-flex;
        min-height: var(--touch-target);
    }

    .task-panel__close,
    .task-panel-frame--enhanced .task-panel__hint {
        display: none;
    }
}

@media (pointer: coarse) {
    .task-panel-frame--enhanced .task-panel__hint {
        display: none;
    }
}

@media (min-width: 768px) and (max-width: 1023px) {
    .task-panel {
        position: fixed;
        inset: 0 0 0 auto;
        z-index: 20;
        width: min(var(--task-panel-width), 100%);
        overflow-y: auto;
        overscroll-behavior: contain;
        box-shadow: var(--shadow-panel);
    }
}

@media (min-width: 1024px) {
    main:has(> .task-panel-frame .task-panel) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) var(--task-panel-width);
        grid-template-rows: auto auto 1fr;
    }

    main:has(> .task-panel-frame .task-panel) > * {
        grid-column: 1;
        min-width: 0;
    }

    main:has(> .task-panel-frame .task-panel) > .band {
        grid-row: 2;
    }

    main:has(> .task-panel-frame .task-panel) > .site-main--after-band {
        grid-row: 3;
    }

    main > .task-panel-frame:has(.task-panel) {
        grid-column: 2;
        grid-row: 1 / -1;
    }

    /*
     * Panneau ouvert : l'en-tête du site colle en haut de l'écran et le panneau se cale dessous,
     * sur toute la hauteur visible restante (jalon 146 : son bas passait sous l'écran de la hauteur
     * de l'en-tête). --site-header-offset est la hauteur réelle de l'en-tête (une ou deux lignes),
     * mesurée par le contrôleur du panneau ; sans JavaScript, la hauteur d'une ligne.
     */
    body:has(.task-panel) .site-header {
        position: sticky;
        top: 0;
        z-index: 30;
    }

    .task-panel {
        position: sticky;
        top: var(--site-header-offset, var(--header-height));
        z-index: 5;
        height: calc(100dvh - var(--site-header-offset, var(--header-height)));
        overflow-y: auto;
        overscroll-behavior: contain;
        box-shadow: var(--shadow-panel);
    }

    /* position: relative : les textes masqués (position absolue) des listes restent dans le défilement du kanban. */
    main:has(> .task-panel-frame .task-panel) .kanban__columns {
        position: relative;
        grid-template-columns: repeat(5, minmax(var(--kanban-column-min), 1fr));
        padding-bottom: var(--space-2);
        overflow-x: auto;
        overscroll-behavior-x: contain;
    }

    main:has(> .task-panel-frame .task-panel) .kanban__columns:has(> .kanban__column--folded) {
        grid-template-columns: max-content repeat(4, minmax(var(--kanban-column-min), 1fr));
    }
}

.task-status-current {
    margin: 0;
}

/*
 * État d'une demande client (panneau « Statut ») : phrase d'explication, motif d'un refus en texte
 * brut (retours à la ligne conservés), et, pour l'Admin, acceptation puis formulaire de refus,
 * séparés du statut par un trait. Texte courant du lecteur (15/22 côté client, client-view).
 */
.request-state {
    margin-top: var(--space-4);
}

.request-state__note {
    margin: 0;
}

.request-state__title {
    margin: var(--space-4) 0 var(--space-1);
    font: var(--text-title-3);
}

.request-state__reason {
    margin: 0;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Après un refus, invitation du contact à envoyer une nouvelle demande. */
.request-state__next {
    margin: var(--space-4) 0 0;
}

.request-decision {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.request-decision__refuse {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    padding-top: var(--space-4);
    border-top: var(--line-width) solid var(--line);
}

.request-decision__refuse .form-field {
    align-self: stretch;
    margin-bottom: 0;
}

/*
 * Refus d'une tâche (lot 082), dans le panneau « Statut » : formulaire replié sous le changement
 * de statut, séparé par un trait (details natif, son triangle dit s'il est ouvert) ; réouverture
 * d'une tâche refusée sous son motif.
 */
.task-rejection {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: var(--line-width) solid var(--line);
}

.task-rejection__toggle {
    display: list-item;
    align-content: center;
    min-height: var(--control-size-sm);
    color: var(--ink);
    font: var(--text-title-3);
    cursor: pointer;
}

.task-rejection__form {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.task-rejection__form .form-field {
    align-self: stretch;
    margin-bottom: 0;
}

/*
 * Actions du contact décideur (lot 085), dans le panneau « Statut » d'une tâche issue d'une
 * demande : phrase d'explication, puis l'action du statut (« Valider la livraison » en bouton
 * principal, « Renvoyer au Backlog » en secondaire), séparées du statut par un trait ; le refus
 * replié reprend le bloc task-rejection.
 */
.task-decision {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.task-decision__note {
    margin: 0;
}

.task-decision__action {
    margin: 0;
}

.task-decision .task-rejection {
    align-self: stretch;
    margin-top: 0;
}

/*
 * Messages des actions du décideur dans le panneau (lot 145), sous les propriétés : zones
 * annoncées vides au chargement, remplies par le flux (coche ou croix, puis la phrase), en texte
 * client 15/22. Vides, elles ne prennent pas de place.
 */
.task-decision-feedback .property-feedback {
    margin-top: 0;
    font: var(--text-body-client);
}

/* Ligne « Écrire un commentaire… » du contact : même texte client que le reste du panneau. */
.client-view .compose__opener--line {
    font: var(--text-body-client);
}

.task-decision-feedback .property-feedback:not(:empty) {
    margin-top: var(--space-3);
}

.task-decision-feedback .property-feedback--error {
    font-weight: var(--font-weight-semibold);
}

.task-reopen {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: var(--line-width) solid var(--line);
}

.task-reopen__help {
    max-width: var(--measure-max);
    margin: 0;
    color: var(--ink-muted);
}

/*
 * Fusion de deux tâches (lot 083). Choix : une option par tâche, titre puis statut (forme +
 * libellé) et « Invisible du client » sous le titre, séparées par un trait ; cible de 44 px au doigt
 * (--choice-size). Confirmation : titres des deux tâches, liste de ce qui passe sur la principale.
 */
.merge-choice__list {
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
}

.merge-choice__option {
    padding: var(--space-2) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.merge-choice__option:last-child {
    border-bottom: 0;
}

.merge-choice__title {
    /* Titre sur plusieurs lignes : pas de marge négative, qui ferait chevaucher le statut. */
    margin-block: 0;
    overflow-wrap: anywhere;
}

.merge-choice__meta,
.merge-confirm__task-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
}

.merge-choice__request {
    max-width: var(--measure-max);
    margin: 0 0 var(--space-5);
}

.merge-confirm__task-title {
    display: block;
    margin-bottom: var(--space-1);
    color: var(--navy);
    font-weight: var(--font-weight-semibold);
}

.merge-confirm__list {
    margin: 0;
    padding-left: var(--space-5);
}

.merge-confirm__list li + li {
    margin-top: var(--space-1);
}

.merge-confirm__note {
    max-width: var(--measure-max);
    margin: var(--space-4) 0 0;
    color: var(--ink-muted);
}

.merge-confirm__visibility {
    margin: 0 0 var(--space-3);
}

/* Avertissement : commentaires d'une tâche invisible qui deviendront visibles du client. */
.merge-confirm__warning {
    max-width: var(--measure-max);
    margin: var(--space-3) 0 0;
}

.merge-confirm__warning .badge {
    margin-right: var(--space-1);
}

/* Panneau « Visibilité client » de la fiche tâche : état, phrase d'explication, bouton. */
.task-visibility__state {
    margin: 0;
}

.task-visibility__help {
    max-width: var(--measure-max);
    margin: var(--space-3) 0 var(--space-4);
    color: var(--ink-muted);
}

/* Propriétés de la fiche tâche : libellé au-dessus de la valeur, séparées par un trait. */
.details {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
}

.details__item {
    min-width: 0;
    padding: var(--space-3) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.details__item:first-child {
    padding-top: 0;
}

.details__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.details dt {
    margin-bottom: var(--space-1);
    color: var(--ink-muted);
    font: var(--text-caption);
}

.details dd {
    margin: 0;
    overflow-wrap: anywhere;
}

/* Personne assignée : nom à la taille du texte courant, pas en méta. */
.details .avatar {
    font: inherit;
}

/*
 * Propriétés du panneau de tâche (lot 135) : libellé à gauche (ink-muted, 5,5:1 sur surface),
 * valeur à droite ; libellé au-dessus de la valeur sous 480 px (voir plus bas).
 */
.details--properties .details__item {
    display: grid;
    grid-template-columns: var(--table-label-width) minmax(0, 1fr);
    align-items: start;
    gap: var(--space-3);
}

.details--properties dt {
    margin-bottom: 0;
    padding-top: var(--space-1);
}

.details--properties .task-status-current {
    padding-top: var(--space-1);
}

.task-panel__meta:empty {
    display: none;
}

/*
 * Propriété modifiable sur place : la valeur est un bouton (summary d'un details natif) sans cadre,
 * fond surface-hover au survol et au focus, focus visible ; la liste des choix flotte
 * (shadow-float), le champ des étiquettes s'ouvre sous la valeur. Pendant l'envoi, le formulaire
 * porte aria-busy (Turbo) : curseur d'attente.
 */
.property {
    min-width: 0;
}

.property-menu {
    position: relative;
}

.property-menu[open] {
    z-index: 3;
}

.property-menu > summary {
    list-style: none;
}

.property-menu > summary::-webkit-details-marker {
    display: none;
}

.property-menu__toggle {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    max-width: 100%;
    min-height: var(--control-size-sm);
    margin-left: calc(-1 * var(--space-2));
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-md);
    cursor: pointer;
}

.property-menu__toggle:hover,
.property-menu__toggle:focus-visible,
.property-menu[open] > .property-menu__toggle {
    background: var(--surface-hover);
}

.property-menu__list {
    position: absolute;
    top: calc(100% + var(--space-1));
    left: calc(-1 * var(--space-2));
    width: var(--property-menu-width);
    max-width: calc(100vw - 2 * var(--space-5));
    max-height: var(--property-menu-max-height);
    overflow-y: auto;
    padding: var(--space-1);
    background: var(--surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
}

.property-menu__group {
    display: flex;
    flex-direction: column;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.property-menu__caption {
    margin: var(--space-1) var(--space-2) var(--space-2);
    padding: 0;
    color: var(--ink-muted);
    font: var(--text-tag);
    font-weight: var(--font-weight-semibold);
}

.property-menu__choices {
    display: flex;
    flex-direction: column;
}

.property-menu__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
    width: 100%;
    min-height: var(--menu-item-height);
    padding: 0 var(--space-2);
    border: 0;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--ink);
    font: var(--text-small);
    text-align: left;
    cursor: pointer;
}

.property-menu__item:hover:not(:disabled) {
    background: var(--surface-hover);
}

/* Valeur actuelle : désactivée, signalée par « (actuelle) » en ink-muted (5,5:1). */
.property-menu__item:disabled {
    cursor: default;
}

.property-menu__current {
    color: var(--ink-muted);
}

.property-menu form[aria-busy="true"],
.property form[aria-busy="true"] {
    cursor: progress;
}

/* Champ des étiquettes, ouvert sous la valeur. */
.property-edit {
    margin-top: var(--space-2);
}

.property-edit__label {
    display: block;
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
}

.property-edit__help {
    margin: 0 0 var(--space-2);
    color: var(--ink-muted);
    font: var(--text-caption);
}

.property-edit__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.property-edit__row .form-field__input {
    flex: 1 1 12rem;
    min-width: 0;
}

/*
 * Confirmation (coche + « Enregistré ») et refus (croix + « Erreur : » + message), près de la valeur.
 * Zones annoncées présentes dès le chargement : vides, sans hauteur, jamais en display: none.
 */
.property-feedback {
    display: flex;
    align-items: flex-start;
    gap: var(--space-1);
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.property-feedback .state-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
    margin-top: calc((1lh - var(--shape-size-sm)) / 2);
}

.property-feedback--error {
    margin-top: var(--space-1);
    color: var(--danger);
    font-weight: var(--font-weight-semibold);
}

.property-feedback__label {
    font-weight: var(--font-weight-semibold);
}

@media (max-width: 480px) {
    .details--properties .details__item {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--space-1);
    }

    .details--properties dt,
    .details--properties .task-status-current {
        padding-top: 0;
    }
}

@media (max-width: 640px), (pointer: coarse) {
    .action-menu__item,
    .property-menu__toggle,
    .property-menu__item {
        min-height: var(--touch-target);
    }
}

/*
 * Adresse de la pull request : lien souligné, cible d'au moins 28 px (44 px au doigt) même sur
 * deux lignes ; une adresse longue passe à la ligne n'importe où, sans défilement horizontal.
 */
.details__link {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    min-height: var(--control-size-sm);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
}

/*
 * Tâches liées de la fiche tâche (dans .details) : une ligne par tâche, titre en lien souligné
 * (repérable sans la couleur) suivi de son statut (forme + libellé) ; le statut passe sous le titre
 * quand la place manque, un titre long passe à la ligne sans défilement horizontal. Cible d'au
 * moins 28 px (44 px au doigt).
 */
.task-links__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.task-links__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0 var(--space-3);
    min-width: 0;
}

.task-links__link {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    max-width: 100%;
    min-height: var(--control-size-sm);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
    overflow-wrap: anywhere;
}

/* Tokens API : consigne en gras avant le secret, résumé du token avant les actions. */
.api-token-warning {
    font-weight: var(--font-weight-semibold);
}

.api-token-details {
    margin-bottom: var(--space-5);
}

/*
 * Connexions du connecteur dans « Mon compte » (lot 181, templates/account/_connector.html.twig) :
 * une connexion par bloc séparé d'un trait, titrée par son studio ; actions à la suite, qui passent
 * à la ligne ; adresse du connecteur en Space Mono, coupée au besoin à 360 px.
 */
.connection-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.connection-list__item {
    padding: var(--space-5) 0;
    border-top: var(--line-width) solid var(--line);
}

.connection-list__item:first-child {
    padding-top: 0;
    border-top: 0;
}

.connection-list__studio {
    margin: 0 0 var(--space-3);
    color: var(--ink);
    font: var(--text-body);
    font-weight: var(--font-weight-bold);
    overflow-wrap: anywhere;
}

.connection-list__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.connection-empty p {
    margin: 0 0 var(--space-3);
}

.connection-empty__address {
    font: var(--text-mono);
    overflow-wrap: anywhere;
}

.connection-note {
    margin: var(--space-5) 0 0;
}

/* Retrait d'une personne du studio (lot 115) : ce qui est retiré, puis ce qui est conservé, en listes à puces ; un nom long passe à la ligne. */
.removal__title {
    overflow-wrap: anywhere;
}

.removal__list {
    margin: 0 0 var(--space-5);
    padding-left: var(--space-5);
    overflow-wrap: anywhere;
}

.removal__list li + li {
    margin-top: var(--space-2);
}

/*
 * Secret d'un token, montré une fois : Space Mono, en lecture seule, passe à la ligne n'importe
 * où (jamais de défilement horizontal) ; hauteur de trois lignes, sans poignée de redimensionnement.
 */
.api-token-secret {
    min-height: 0;
    padding-block: var(--space-2);
    font-family: var(--font-mono);
    overflow-wrap: anywhere;
    word-break: break-all;
    resize: none;
}

/*
 * Historique des statuts d'une tâche, du plus récent au plus ancien : pastille d'initiales à
 * gauche, changement et méta à côté ; lignes séparées par un trait.
 */
.status-history {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.status-history__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    column-gap: var(--space-3);
    padding: var(--space-4) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.status-history__item:first-child {
    padding-top: 0;
}

.status-history__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.status-history__change,
.status-history__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: 0;
}

.status-history__arrow {
    color: var(--ink-muted);
}

.status-history__meta {
    margin-top: var(--space-1);
    color: var(--ink-muted);
    font: var(--text-caption);
    overflow-wrap: anywhere;
}

/*
 * Fil de commentaires d'une tâche, du plus ancien au plus récent : pastille d'initiales à gauche,
 * méta (auteur, date, étiquettes) puis contenu Markdown ; lignes séparées par un trait. Le
 * contenu ne déborde jamais du panneau (longue URL coupée, bloc de code défilant dans son cadre).
 */
.comment-thread {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.comment-thread__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    column-gap: var(--space-3);
    padding: var(--space-4) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.comment-thread__item:first-child {
    padding-top: 0;
}

.comment-thread__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.comment-thread__content {
    min-width: 0;
}

.comment-thread__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: 0 0 var(--space-2);
    color: var(--ink-muted);
    font: var(--text-caption);
    overflow-wrap: anywhere;
}

.comment-thread__author {
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

/*
 * Formulaire de commentaire de l'équipe, sous le fil dans le même panneau, séparé par un trait :
 * messages annoncés, zone de texte, case « Interne », bouton « Commenter ».
 */
.comment-compose {
    margin-top: var(--space-5);
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

/* Fichiers joints d'un commentaire, sous son contenu, séparés de lui par un trait. */
.comment-thread__attachments {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: var(--line-width) solid var(--line);
}

.comment-thread__attachments-title {
    margin: 0 0 var(--space-2);
    color: var(--ink-muted);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
}

.comment-form__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* Durées (filtre « duration ») : chiffres tabulaires, alignés d'une ligne à l'autre. */
.duration {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/*
 * Panneau « Temps » de la fiche tâche : total en tête, séparé de la liste par un trait ; une
 * ligne par entrée (personne et durée, puis date et type, puis note), séparées par un trait ;
 * chaque ligne garde à droite la place de ses actions (time-entries__actions).
 */
.time-total {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    margin: 0 0 var(--space-4);
    padding-bottom: var(--space-4);
    border-bottom: var(--line-width) solid var(--line);
}

.time-total__label {
    color: var(--ink-muted);
    font: var(--text-small);
}

.time-total__value {
    color: var(--ink);
    font: var(--text-title-2);
}

.time-entries__empty {
    margin: 0;
}

.time-entries {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.time-entries__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
        "main actions"
        "meta actions"
        "note note";
    align-items: start;
    padding: var(--space-3) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.time-entries__item:first-child {
    padding-top: 0;
}

.time-entries__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.time-entries__main {
    grid-area: main;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1) var(--space-3);
    min-width: 0;
}

.time-entries__person {
    font: var(--text-body);
}

.time-entries__duration {
    color: var(--ink);
    font-weight: var(--font-weight-semibold);
}

.time-entries__meta {
    grid-area: meta;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: var(--space-1) 0 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

/* « Modifier » et « Supprimer » de la ligne, à droite ; l'un sous l'autre si la place manque. */
.time-entries__actions {
    grid-area: actions;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--space-1);
    margin-left: var(--space-3);
}

.time-entries__note {
    grid-area: note;
    margin: var(--space-2) 0 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Saisie du temps, en tête de l'onglet « Temps » (lot 139), avant la liste. */
.time-compose {
    margin-bottom: var(--space-5);
}

.time-compose__title {
    margin: 0 0 var(--space-4);
    color: var(--ink);
    font: var(--text-title-3);
}

.time-form__duration {
    min-width: 0;
    margin: 0 0 var(--space-5);
    padding: 0;
    border: 0;
}

.time-form__duration > legend {
    margin-bottom: var(--space-2);
    padding: 0;
}

/* « Heures » et « Minutes » côte à côte, même à 360 px. */
.time-form__duration-fields {
    display: flex;
    gap: var(--space-3);
}

.time-form__duration-fields .form-field {
    flex: 1 1 0;
    min-width: 0;
    margin-bottom: 0;
}

.time-form .form-field__textarea {
    min-height: 0;
}

.time-form__duration-fields .form-field__label {
    font-weight: var(--font-weight-regular);
}

.time-form__duration .form-field__error {
    margin-top: var(--space-2);
}

.time-form__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-4);
}

/*
 * Historique du temps, en bas du panneau « Temps », séparé par un trait : replié par défaut
 * (details natif, son triangle dit s'il est ouvert) ; un événement par ligne, comme l'historique
 * des statuts : pastille d'initiales, action, méta (date, type d'acteur), puis valeurs.
 */
.time-history-disclosure {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: var(--line-width) solid var(--line);
}

.time-history-disclosure__toggle {
    display: list-item;
    align-content: center;
    min-height: var(--control-size-sm);
    color: var(--ink);
    font: var(--text-title-3);
    cursor: pointer;
}

.time-history-disclosure[open] > .time-history-disclosure__toggle {
    margin-bottom: var(--space-3);
}

.time-history__empty {
    margin: 0;
}

.time-history {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.time-history__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    column-gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.time-history__item:first-child {
    padding-top: 0;
}

.time-history__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.time-history__action {
    margin: 0;
    overflow-wrap: anywhere;
}

.time-history__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-2);
    margin: var(--space-1) 0 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.time-history__values {
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
    font: var(--text-small);
}

.time-history__value {
    overflow-wrap: anywhere;
}

.time-history__field {
    color: var(--ink-muted);
}

.time-history__arrow {
    color: var(--ink-muted);
}

.time-history__note {
    white-space: pre-line;
}

/* Pages « Modifier le temps » et de confirmation de suppression : rappel de l'entrée avant le formulaire. */
.time-entry-edit__task {
    overflow-wrap: anywhere;
}

.time-entry-edit__intro {
    margin: 0 0 var(--space-4);
}

.time-entry-details {
    margin-bottom: var(--space-5);
}

.time-entry-details__note {
    white-space: pre-line;
}

/*
 * Pièces jointes de la fiche tâche : une ligne par fichier, séparées par un trait ; nom en lien
 * souligné (repérable sans la couleur), qui passe à la ligne n'importe où ; méta (type, taille,
 * auteur en pastille d'initiales, date) en légende ; « Supprimer » à droite. Cibles d'au moins 28 px (44 px au doigt).
 */
.attachment-list {
    display: flex;
    flex-direction: column;
    margin: 0;
    padding: 0;
    list-style: none;
}

.attachment-list__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-3) 0;
    border-bottom: var(--line-width) solid var(--line);
}

.attachment-list__item:first-child {
    padding-top: 0;
}

.attachment-list__item:last-child {
    padding-bottom: 0;
    border-bottom: 0;
}

.attachment-list__main {
    flex: 1 1 0;
    min-width: 0;
}

.attachment-list__name {
    display: inline-flex;
    align-items: center;
    max-width: 100%;
    min-height: var(--control-size-sm);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
    overflow-wrap: anywhere;
}

.attachment-list__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-3);
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.attachment-list__delete {
    flex: none;
}

/*
 * Pièces jointes de la description en vignettes (lot 138), dans le panneau de tâche : grille qui
 * passe à la ligne, la liste en « display: contents » pour que la case « Joindre » suive la
 * dernière vignette. Une vignette : aperçu de l'image réduit (object-fit) ou type écrit en toutes
 * lettres sur fond --surface-sunken (aucune couleur par type), nom souligné sur deux lignes au
 * plus, taille en légende, « Supprimer » toujours visible. Le lien entier est la cible (focus
 * visible autour de l'aperçu et du nom). Cibles de 28 px, 44 px au doigt.
 */
.attachment-grid {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-4) var(--space-3);
}

.attachment-grid__list {
    display: contents;
}

.attachment-tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    width: var(--attachment-tile-width);
    min-width: 0;
}

.attachment-tile__link {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    border-radius: var(--radius-md);
    color: var(--navy);
    text-decoration: none;
}

.attachment-tile__preview {
    display: flex;
    align-items: center;
    justify-content: center;
    height: var(--attachment-tile-height);
    overflow: hidden;
    border: var(--line-width) solid var(--line);
    border-radius: var(--radius-md);
    background: var(--surface-sunken);
}

.attachment-tile__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.attachment-tile__type {
    padding: var(--space-1) var(--space-2);
    color: var(--ink);
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
    text-align: center;
    overflow-wrap: anywhere;
}

.attachment-tile__name {
    display: -webkit-box;
    overflow: hidden;
    font: var(--text-caption);
    font-weight: var(--font-weight-semibold);
    text-decoration: underline;
    text-underline-offset: var(--underline-offset);
    overflow-wrap: anywhere;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}

.attachment-tile__link:hover .attachment-tile__preview {
    border-color: var(--line-strong);
}

.attachment-tile__meta {
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-caption);
}

.attachment-tile__delete {
    align-self: flex-start;
}

/*
 * Ajout : sans JavaScript, formulaire sur toute la largeur sous les vignettes (libellé, champ de
 * fichiers, bouton « Joindre ») ; avec JavaScript (attachment-grid--enhanced), seule la case
 * « + Joindre » reste, à la taille d'un aperçu, en pointillés --line-strong (3:1) ; elle passe en
 * trait plein, sur fond --surface-hover, quand des fichiers la survolent pendant un glisser-déposer.
 */
.attachment-add {
    flex: 1 0 100%;
}

.attachment-add__field {
    margin-bottom: var(--space-3);
}

.attachment-add__case {
    display: none;
}

.attachment-grid--enhanced .attachment-add {
    flex: none;
}

.attachment-grid--enhanced .attachment-add__field,
.attachment-grid--enhanced .attachment-add__actions {
    display: none;
}

.attachment-grid--enhanced .attachment-add__case {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    width: var(--attachment-tile-width);
    height: var(--attachment-tile-height);
    border: var(--dash-width) dashed var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--navy);
    font: var(--text-button);
    cursor: pointer;
}

.attachment-add__case:hover,
.attachment-add__case:focus-visible {
    background: var(--surface-hover);
}

.attachment-add__case--over {
    border-style: solid;
    background: var(--surface-hover);
}

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

/* Envoi en cours : indicateur à la place du « + ». */
.attachment-add__case[aria-busy="true"] .plus-shape {
    display: none;
}

.attachment-add__case[aria-busy="true"]::before {
    content: "";
    width: var(--spinner-size);
    height: var(--spinner-size);
    border: var(--indicator-width) solid currentColor;
    border-right-color: transparent;
    border-radius: var(--radius-full);
    animation: button-spin 0.8s linear infinite;
}

.attachment-grid__help {
    margin: var(--space-3) 0 0;
}

/* Zones annoncées de la section : vides sans place ; confirmation et refus en messages Flash. */
.attachment-feedback:empty {
    display: none;
}

.attachment-feedback {
    margin-top: var(--space-3);
}

.attachment-feedback .flash {
    margin-bottom: 0;
}

.attachment-feedback__errors {
    align-items: flex-start;
}

.attachment-feedback__errors .state-shape {
    margin-top: calc((1lh - var(--shape-size)) / 2);
}

.attachment-feedback__body {
    flex: 1 1 0;
    min-width: 0;
}

.attachment-feedback__body p,
.attachment-feedback__body ul {
    margin: 0;
}

.attachment-feedback__body ul {
    padding-left: var(--space-5);
    overflow-wrap: anywhere;
}

/*
 * Champ de fichiers (pièces jointes de la description et d'un commentaire) : bouton de sélection
 * du navigateur présenté comme un bouton secondaire, erreurs du dernier envoi en liste, rappel
 * des fichiers à choisir à nouveau précédé du cercle « i ».
 */
.file-field__input {
    padding-block: var(--space-1);
    cursor: pointer;
}

.file-field__input::file-selector-button {
    min-height: var(--control-size-sm);
    margin-right: var(--space-3);
    padding: 0 var(--space-3);
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--surface);
    color: var(--navy);
    font: var(--text-button);
    cursor: pointer;
}

.file-field__input:hover::file-selector-button {
    background: var(--surface-hover);
}

.file-field__errors p,
.file-field__errors ul {
    margin: 0;
}

/* Rappel : même présentation qu'une erreur de champ, en texte courant, cercle « i » centré sur la première ligne. */
.file-field__reminder {
    display: flex;
    align-items: flex-start;
    gap: var(--space-1);
    color: var(--ink);
}

.file-field__reminder .state-shape {
    flex: none;
    width: var(--shape-size-sm);
    height: var(--shape-size-sm);
    margin-top: calc((1lh - var(--shape-size-sm)) / 2);
}

.file-field__errors ul {
    padding-left: var(--space-5);
    overflow-wrap: anywhere;
}

.attachment-add__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* Confirmation de suppression : un nom de fichier long passe à la ligne ; résumé du fichier avant l'avertissement. */
.attachment-delete__title {
    overflow-wrap: anywhere;
}

.attachment-delete__details {
    margin-bottom: var(--space-5);
}

/* Étiquettes libres d'une tâche, posées sur un panneau blanc ou une carte (list : 1,2:1 sur surface, texte ink-done 6,1:1). */
.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.tag {
    padding: var(--space-tag-sm) var(--space-2);
    border-radius: var(--radius-sm);
    background: var(--list);
    color: var(--ink-done);
    font: var(--text-tag);
    overflow-wrap: anywhere;
}

/* Contenu Markdown rendu (description d'une tâche) */
.markdown {
    overflow-wrap: anywhere;
}

.markdown > :last-child {
    margin-bottom: 0;
}

.markdown h1,
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
    margin: var(--space-5) 0 var(--space-2);
    color: var(--ink);
    font: var(--text-title-3);
}

/* « Titre » (##) plus grand que « Sous-titre » (###) ; un # écrit en Markdown brut reste au niveau d'un titre. */
.markdown h1,
.markdown h2 {
    font: var(--text-title-2);
}

.markdown > :first-child {
    margin-top: 0;
}

.markdown li > p {
    margin-bottom: var(--space-2);
}

.markdown blockquote > :last-child,
.markdown li > :last-child {
    margin-bottom: 0;
}

/* Liste serrée dans l'éditeur (« - a » puis « - b », sans ligne vide) : pas d'espace entre les éléments. */
.markdown [data-tight="true"] p {
    margin-bottom: 0;
}

.markdown code {
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background: var(--surface-sunken);
}

.markdown pre code {
    padding: 0;
    background: none;
}

.markdown ul,
.markdown ol {
    margin: 0 0 var(--space-4);
    padding-left: var(--space-6);
}

.markdown pre {
    max-width: 100%;
    overflow-x: auto;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
}

.markdown img {
    max-width: 100%;
    height: auto;
}

.markdown blockquote {
    margin: 0 0 var(--space-4);
    padding: var(--space-2) var(--space-4);
    background: var(--surface-sunken);
    border-radius: var(--radius-md);
    color: var(--ink-muted);
}

.markdown table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
}

.markdown th,
.markdown td {
    padding: var(--space-1) var(--space-3);
    border-bottom: var(--line-width) solid var(--line);
    text-align: left;
}

/*
 * Cases à cocher d'une liste (« - [ ] », « - [x] »), non modifiables sur la fiche : à la place de
 * la puce, case vide bordée (line-strong 3,6:1) ou pleine en marine avec une coche blanche
 * (11,9:1) ; cochée et non cochée se distinguent par la forme et la clarté, pas par la teinte.
 */
.markdown li:has(> input[type="checkbox"]:first-child),
.markdown li:has(> p:first-child > input[type="checkbox"]:first-child),
.markdown-editor__task {
    list-style: none;
}

.markdown input[type="checkbox"] {
    appearance: none;
    display: inline-grid;
    place-content: center;
    width: var(--choice-input-size);
    height: var(--choice-input-size);
    margin: 0 var(--space-2) 0 calc(-1 * (var(--choice-input-size) + var(--space-2)));
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--surface);
    vertical-align: text-bottom;
    opacity: 1;
}

.markdown input[type="checkbox"]::before {
    content: "";
    width: var(--shape-size-xs);
    height: var(--shape-size-xs);
    background: var(--on-navy);
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0, 43% 62%);
    visibility: hidden;
}

.markdown input[type="checkbox"]:checked {
    border-color: var(--navy);
    background: var(--navy);
}

.markdown input[type="checkbox"]:checked::before {
    visibility: visible;
}

/*
 * Éditeur visuel Markdown (TextareaField avec editor, contrôleur markdown-editor) : un cadre de
 * champ (line-strong, rayon md) qui porte la barre d'outils sur surface-sunken, puis le texte mis
 * en forme. Boutons à libellé écrit, compacts sur ordinateur et de 44 px au doigt ; un bouton
 * actif (aria-pressed) passe en aplat marine, texte blanc : distinct par la clarté en niveaux de
 * gris. La barre passe à la ligne sur un petit écran, sans défilement horizontal.
 */
.markdown-editor {
    display: flex;
    flex-direction: column;
    min-width: 0;
    border: var(--line-width) solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--field);
}

.markdown-editor [hidden] {
    display: none;
}

.markdown-editor--invalid {
    border-color: var(--danger);
    box-shadow: inset 0 0 0 var(--line-width) var(--danger);
}

.markdown-editor__bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
    background: var(--surface-sunken);
}

.markdown-editor__bar {
    border-bottom: var(--line-width) solid var(--line);
}

/* En Markdown brut, le cadre ne garde que la barre, la zone de texte vient dessous. */
.markdown-editor--raw .markdown-editor__bar {
    border-bottom: 0;
    border-radius: var(--radius-md);
}

.markdown-editor__toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    min-width: 0;
}

.markdown-editor__button[aria-pressed="true"],
.markdown-editor__raw[aria-pressed="true"] {
    border-color: var(--navy);
    background: var(--navy);
    color: var(--on-navy);
}

.markdown-editor__button[aria-pressed="true"]:hover,
.markdown-editor__raw[aria-pressed="true"]:hover {
    background: var(--navy-hover);
    color: var(--on-navy);
}

.markdown-editor__link {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3);
    border-bottom: var(--line-width) solid var(--line);
}

.markdown-editor__link .form-field__label,
.markdown-editor__link .form-field__help,
.markdown-editor__link .form-field__error {
    margin: 0;
}

.markdown-editor__link-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.markdown-editor__content {
    min-height: var(--textarea-min-height);
    padding: var(--space-2) var(--space-3);
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    color: var(--ink);
    font: var(--text-input);
    white-space: pre-wrap;
    word-wrap: break-word;
}

.markdown-editor__content:focus-visible {
    outline-offset: calc(-1 * var(--focus-width));
}

.markdown-editor__task {
    display: flex;
    align-items: flex-start;
}

.markdown-editor__check {
    display: flex;
    flex: none;
    margin-top: calc((1lh - var(--choice-input-size)) / 2);
    cursor: pointer;
}

.markdown-editor__check > input[type="checkbox"] {
    cursor: pointer;
}

.markdown-editor__task-content {
    flex: 1;
    min-width: 0;
}

.markdown-editor__note:not(:empty) {
    margin-top: var(--space-2);
}

/*
 * Images collées ou glissées : aide sous le champ, puis état d'envoi (role="status") et refus
 * (role="alert"), vides au repos. Pendant l'envoi, une marque en pointillés, au texte écrit,
 * tient la place de l'image dans l'éditeur visuel.
 */
.markdown-editor__images {
    margin-top: var(--space-2);
}

.markdown-editor__images .flash {
    margin: 0;
}

.markdown-editor__image-status:not(:empty),
.markdown-editor__image-alert:not(:empty) {
    margin-top: var(--space-2);
}

.markdown-editor__placeholder {
    display: inline-block;
    padding: 0 var(--space-2);
    border: var(--dash-width) dashed var(--line-strong);
    border-radius: var(--radius-sm);
    color: var(--ink-muted);
    font: var(--text-small);
    white-space: nowrap;
}

/*
 * En-tête à partir de 1024 px (lot 151) : une seule ligne ; faute de place, le nom du studio, la
 * recherche et le nom de la personne rétrécissent, jamais la navigation.
 */
@media (min-width: 1024px) {
    .site-header__inner {
        flex-wrap: nowrap;
    }

    .site-header__brand {
        min-width: var(--header-brand-min);
    }
}

/*
 * En-tête sous 1024 px : le nom du studio, la recherche et le menu du compte sur la première
 * ligne, la navigation dessous, sur une ligne qui revient à la ligne si besoin (jamais de
 * défilement de la page). Onglets de 44 px au doigt (--control-size).
 */
@media (max-width: 1023px) {
    .site-header__inner {
        gap: 0 var(--space-4);
    }

    /* Première ligne : le nom du studio prend la place libre, la recherche rétrécit avant de passer à la ligne. */
    .site-header__brand {
        flex: 1 1 0;
        min-width: var(--header-brand-min);
    }

    .site-search {
        flex: 1 1 var(--search-min-width);
        max-width: var(--search-width);
    }

    .site-nav {
        flex-basis: 100%;
        order: 3;
    }

    .site-nav__link,
    .site-nav .site-menu__toggle {
        min-height: var(--control-size);
    }
}

@media (max-width: 640px) {
    .band {
        padding-block: var(--space-4) var(--space-6);
    }

    .panel {
        padding: var(--space-5);
    }

    .panel--flush {
        padding: 0;
    }

    /*
     * En-tête sous 640 px (lot 152) : une rangée de 56 px. Dans un studio ouvert
     * (site-header--compact) : nom court du studio (« RPW »), « Projets », « Rechercher » et
     * « Menu », boutons de 44 px ; « Organisations », « Administration » et le menu du compte
     * passent dans « Menu ». Sur une page commune : nom de l'outil (sur plusieurs lignes au besoin)
     * et menu du compte, nom de la personne raccourci.
     */
    .site-header {
        position: relative;
    }

    .site-header__inner {
        flex-wrap: nowrap;
        align-items: center;
        gap: 0 var(--space-3);
        min-height: var(--header-height-sm);
    }

    .site-header__brand {
        flex: 1 1 0;
        min-width: 0;
        max-width: none;
        display: flex;
        align-items: center;
        min-height: var(--touch-target);
        overflow-wrap: anywhere;
        white-space: normal;
    }

    .site-menu__toggle,
    .site-nav__link,
    .site-nav .site-menu__toggle {
        min-height: var(--header-height-sm);
    }

    .site-header__name {
        max-width: var(--header-name-max-sm);
    }

    .site-header--compact .site-header__brand,
    .site-header--compact .site-header__user,
    .site-nav__list > .site-nav__item--wide {
        display: none;
    }

    /* Nom court du studio : lien vers l'accueil de 44 px, nom complet lu et en infobulle. */
    .site-header__short-name {
        display: flex;
        flex: 0 1 auto;
        align-items: center;
        min-width: var(--touch-target);
        max-width: var(--header-short-name-max);
        min-height: var(--touch-target);
        color: var(--navy);
        font: var(--text-brand-short);
    }

    .site-header__short-name > [aria-hidden="true"] {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .site-header__short-name:hover {
        color: var(--navy-hover);
        text-decoration: none;
    }

    /* « Projets » seul dans la navigation, à côté du nom court. */
    .site-nav {
        flex: none;
        flex-basis: auto;
        order: 0;
    }

    /*
     * Bouton « Menu » : 44 px, bordure de contrôle, libellé écrit et chevron décoratif ; le
     * soulignement de l'onglet actif se pose sur le trait de l'en-tête quand l'une de ses entrées
     * est la page affichée. Sa liste occupe toute la largeur sous l'en-tête.
     */
    .site-menu--mobile {
        position: static;
        display: flex;
        flex: none;
    }

    .site-menu__button--mobile {
        min-height: var(--touch-target);
        font: var(--text-button);
        border: var(--line-width) solid var(--line-strong);
        background: var(--surface);
    }

    .site-menu--mobile .site-menu__list {
        top: 100%;
        right: 0;
        left: 0;
        width: auto;
        max-width: none;
        padding: var(--space-2) var(--space-5);
        border-radius: 0 0 var(--radius-md) var(--radius-md);
    }

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

    .site-menu__group + .site-menu__group {
        margin-top: var(--space-1);
        padding-top: var(--space-1);
        border-top: var(--line-width) solid var(--line);
    }

    .site-menu--mobile .action-menu__item {
        font: var(--text-body);
    }

    .kanban-filters__select,
    .kanban-filters__shown,
    .kanban-filters__check-label {
        font-size: var(--input-font-size-mobile);
    }

    /*
     * Recherche (lot 144) : un bouton « Rechercher » sur la première rangée, à côté de « Se
     * déconnecter » (l'en-tête ne s'allonge pas) ; ouverte, la recherche occupe tout l'écran,
     * résultats compris, avec « Fermer la recherche ». Cibles de 44 px.
     */
    .site-search {
        flex: none;
        min-width: 0;
        margin-left: auto;
    }

    .site-search__opener {
        display: inline-flex;
        min-height: var(--touch-target);
    }

    .site-search__box {
        display: none;
    }

    .site-search--open .site-search__box {
        position: fixed;
        inset: 0;
        z-index: 30;
        display: flex;
        flex-direction: column;
        gap: var(--space-3);
        padding: var(--space-4) var(--space-5);
        background: var(--surface);
    }

    .site-search--open .site-search__form {
        gap: var(--space-2);
    }

    .site-search--open .site-search__input {
        min-height: var(--touch-target);
        padding-right: var(--space-3);
    }

    .site-search--open .site-search__close {
        display: inline-flex;
        flex: none;
        min-height: var(--touch-target);
    }

    .site-search--open .site-search__hint {
        display: none;
    }

    .site-search--shown .site-search__results {
        position: static;
        flex: 1 1 auto;
        width: auto;
        max-height: none;
        box-shadow: none;
    }

    .search-result {
        min-height: var(--touch-target);
    }

    /* Studios empilés : le bouton « Ouvrir » passe sous le nom et le rôle. */
    .studio-list__item,
    .invitation-list__item {
        flex-direction: column;
        align-items: flex-start;
    }

    .studio-list__text,
    .invitation-list__text {
        flex: none;
        max-width: 100%;
    }
}

/* Au doigt : poignée et titre des cartes à 44 px. */
@media (max-width: 640px), (pointer: coarse) {
    .task-card__handle {
        --handle-size: var(--touch-target);
        margin: calc(-1 * var(--space-3)) calc(-1 * var(--space-3)) 0 0;
    }

    .task-card__title {
        min-height: var(--touch-target);
    }

    .error-summary__list a {
        min-height: var(--touch-target);
    }
}

/*
 * Kanban sous 768 px, avec JavaScript : le contrôleur « column-tabs » pose .kanban--tabs et
 * hidden sur les listes non affichées. Les onglets défilent dans leur propre rangée (accroche par
 * onglet, sans barre visible) ; la page ne défile jamais en largeur. Le titre de la liste
 * affichée est repris par l'onglet actif : il reste lisible par les lecteurs d'écran seulement.
 */
@media (max-width: 767px) {
    .kanban--tabs .kanban__tabs {
        display: flex;
        gap: var(--space-2);
        margin: 0 0 var(--space-4);
        padding: var(--space-tag) var(--space-tag) var(--space-1);
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
    }

    .kanban--tabs .kanban__tabs::-webkit-scrollbar {
        display: none;
    }

    .kanban--tabs .kanban__column[hidden] {
        display: none;
    }

    .kanban--tabs .kanban__title {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }

    /* Page du Backlog : la case de sélection à gauche, le reste de la ligne empilé à côté. */
    .backlog-table--selectable tbody tr {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        column-gap: var(--space-3);
    }

    .backlog-table--selectable tbody tr > * {
        grid-column: 2;
    }

    .backlog-table--selectable tbody .backlog-table__select {
        grid-column: 1;
        grid-row: 1 / span 6;
        align-self: start;
    }

    .backlog-table:not(.backlog-table--selectable) tbody tr {
        display: flex;
        flex-direction: column;
    }

    /* Le titre de la tâche en tête de sa carte, le rang dessous. */
    .backlog-table tbody th {
        order: -1;
    }
}

@media (min-width: 768px) {
    .kanban__columns {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /*
     * Backlog replié (lot 141) : bandeau vertical étroit sur toute la hauteur des listes, qui garde
     * la forme du statut, son nom et son nombre de tâches, dans le bouton « Déplier le Backlog » ;
     * ses cartes, son lien et « Ajouter une tâche » sont masqués, sa liste reste une zone de dépôt
     * (la carte y va en bas du Backlog). De 768 à 1023 px, deux listes à côté du bandeau.
     */
    .kanban__fold:not([hidden]) {
        display: inline-flex;
        flex: none;
        align-items: center;
        justify-content: center;
        min-width: var(--control-size-sm);
        min-height: var(--control-size-sm);
        padding: 0 var(--space-2);
        border: 0;
        border-radius: var(--radius-md);
        background: transparent;
        color: var(--navy);
        font: var(--text-button);
        cursor: pointer;
    }

    .kanban__fold:hover {
        background: var(--list-hover);
    }

    .kanban__fold-unfold {
        display: none;
    }

    /* Backlog déplié avec son bouton : titre et « Replier » sur une ligne, le reste dessous. */
    .kanban__column--backlog:not(.kanban__column--folded):has(> .kanban__fold:not([hidden])) {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-content: start;
        align-items: center;
    }

    .kanban__column--backlog:not(.kanban__column--folded):has(> .kanban__fold:not([hidden])) > :not(.kanban__title, .kanban__fold) {
        grid-column: 1 / -1;
    }

    .kanban__columns:has(> .kanban__column--folded) {
        grid-template-columns: max-content repeat(2, minmax(0, 1fr));
    }

    .kanban__column.kanban__column--folded {
        display: flex;
        grid-row: span 2;
        align-self: stretch;
        padding-inline: var(--space-1);
    }

    .kanban__column--folded .kanban__title,
    .kanban__column--folded .kanban__fold-fold,
    .kanban__column--folded .task-card,
    .kanban__column--folded .kanban__empty,
    .kanban__column--folded .kanban__more,
    .kanban__column--folded .kanban__add {
        display: none;
    }

    .kanban__column--folded .kanban__fold {
        width: 100%;
        padding: var(--space-3) var(--space-1);
        color: var(--ink);
    }

    .kanban__column--folded .kanban__fold-unfold {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: var(--space-2);
    }

    .kanban__fold-unfold .status-shape {
        flex: none;
        width: var(--shape-size);
        height: var(--shape-size);
    }

    .kanban__fold-name {
        font: var(--text-column-title);
        writing-mode: vertical-rl;
    }

    /* Compteur du bandeau : pastille blanche, comme celui des listes. */
    .kanban__fold-count {
        background: var(--count-pill);
    }

    .kanban__column--folded .kanban__list {
        flex: 1 1 auto;
    }

    .data-table thead {
        position: static;
        width: auto;
        height: auto;
        overflow: visible;
        clip: auto;
        white-space: normal;
    }

    .data-table thead th {
        display: table-cell;
        padding: var(--space-3) var(--space-5);
        background: var(--surface-sunken);
        border-bottom: var(--line-width) solid var(--line);
        color: var(--ink-muted);
        font: var(--text-caption);
        font-weight: var(--font-weight-semibold);
    }

    .data-table tr {
        display: table-row;
        padding: 0;
        border: 0;
    }

    .data-table tbody th,
    .data-table tbody td {
        display: table-cell;
        padding: var(--space-4) var(--space-5);
        vertical-align: middle;
        border-bottom: var(--line-width) solid var(--line);
    }

    .data-table tbody tr:last-child th,
    .data-table tbody tr:last-child td {
        border-bottom: 0;
    }

    .data-table tbody tr:hover {
        background: var(--surface-hover);
    }

    .data-table__label {
        display: none;
    }

    /* Plus spécifique que « .data-table td » pour aligner les actions de ligne à droite. */
    .data-table td.data-table__actions {
        text-align: right;
        white-space: nowrap;
    }

    .data-table__actions .button--ghost {
        margin-left: 0;
    }

    .data-table td.time-table__cell--empty {
        display: table-cell;
    }

    .data-table .time-table__duration {
        text-align: right;
    }

    /* Nom et étiquettes d'une cellule principale restent sur une ligne quand la place le permet. */
    .data-table tbody th > * {
        vertical-align: middle;
    }

    .data-table tbody th > * + * {
        margin-left: var(--space-2);
    }
}

@media (min-width: 1024px) {
    .container {
        padding-inline: var(--space-8);
    }

    .kanban__columns {
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }

    /* Backlog replié : bandeau étroit, quatre listes à côté. */
    .kanban__columns:has(> .kanban__column--folded) {
        grid-template-columns: max-content repeat(4, minmax(0, 1fr));
    }

    .kanban__column.kanban__column--folded {
        grid-row: auto;
    }

}


@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition: none;
        animation: none;
    }
}

/*
 * Section « Demandes » de la fiche projet, dans un panneau sans marge intérieure (panel--flush) :
 * une ligne par demande, séparées par un trait. Le titre est le lien et couvre toute la ligne
 * (cible large au doigt) ; type et statut (forme + libellé) à droite, dessous sur mobile.
 */
.request-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.request-list__item {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1) var(--space-4);
    min-width: 0;
    padding: var(--space-3) var(--space-5);
    border-bottom: var(--line-width) solid var(--line);
}

.request-list__item:last-child {
    border-bottom: 0;
}

.request-list__item:hover {
    background: var(--surface-hover);
}

.request-list__title {
    min-width: 0;
    margin: 0;
    font: var(--text-title-3);
    overflow-wrap: anywhere;
}

.request-list__link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
}

.request-list__link::after {
    content: "";
    position: absolute;
    inset: 0;
}

/*
 * Focus clavier : l'anneau entoure toute la ligne, cible réelle du lien, à l'intérieur du panneau
 * (qui coupe ce qui déborde) ; le lien lui-même n'en porte pas en plus.
 */
.request-list__link:focus-visible {
    outline: none;
}

.request-list__item:has(.request-list__link:focus-visible) {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: calc(-1 * var(--focus-width));
    border-radius: var(--radius-lg);
}

/*
 * Page « Demandes » d'un projet (lot 155, templates/project/requests.html.twig) : choix de la vue
 * (view-switch) posé sur le fond gris, puis la liste (request-list, ci-dessus) dans un panneau.
 * Vue affichée (aria-current="page") : texte marine en gras et soulignement marine, jamais la
 * teinte seule ; l'autre vue en --ink-muted (5:1 sur --canvas), soulignement transparent. Cibles
 * de --control-size (44 px au doigt). Les deux liens passent à la ligne au besoin, sans
 * défilement horizontal.
 */
.view-switch__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-5);
    margin: 0 0 var(--space-5);
    padding: 0;
    list-style: none;
    border-bottom: var(--line-width) solid var(--line);
}

.view-switch__link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-size);
    margin-bottom: calc(-1 * var(--line-width));
    border-bottom: var(--indicator-width) solid transparent;
    color: var(--ink-muted);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
}

.view-switch__link:hover {
    color: var(--navy);
    text-decoration: none;
}

.view-switch__link[aria-current="page"] {
    border-bottom-color: var(--navy);
    color: var(--navy);
    font-weight: var(--font-weight-bold);
}

.requests-page__title {
    margin: 0 0 var(--space-3);
    font: var(--text-title-2);
}

.requests-page__title:focus {
    outline: none;
}

.requests-page__title:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/*
 * Page « Tâches refusées » d'un projet (lot 156, templates/project/refused_tasks.html.twig) :
 * titre de page suivi du nombre en pastille (CountPill), qui passe à la ligne au besoin. Le titre
 * reçoit le focus à la fermeture du panneau quand la tâche a quitté la liste (tabindex="-1") :
 * anneau seulement au clavier.
 */
.refused-page__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

.refused-page__title:focus {
    outline: none;
}

.refused-page__title:focus-visible {
    outline: var(--focus-width) solid var(--focus-ring);
    outline-offset: var(--focus-offset);
}

/* Compteur du bouton « Demandes » de l'en-tête du projet (lot 155) : à la suite du libellé. */
.project-header__requests {
    gap: var(--space-2);
}

/*
 * Livraisons qui attendent la validation du contact décideur (lot 085), en tête de la section
 * « Demandes » : une phrase, puis un lien par livraison vers sa fiche (cible de 44 px au doigt).
 */
.request-review {
    margin-bottom: var(--space-4);
}

.request-review__intro {
    margin: 0 0 var(--space-2);
}

.request-review__list {
    margin: 0;
    padding-left: var(--space-5);
}

.request-review__list a {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-size);
    overflow-wrap: anywhere;
}

/* Motif résumé d'une tâche refusée (page « Tâches refusées »), sur toute la largeur de la ligne. */
.refused-list__reason {
    flex-basis: 100%;
    min-width: 0;
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-small);
    overflow-wrap: anywhere;
}

.request-list__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1) var(--space-4);
    margin: 0;
    color: var(--ink-muted);
    font: var(--text-small);
}

/*
 * Page d'accord du connecteur (lot 179, templates/oauth/authorize.html.twig) : un seul panneau,
 * sections séparées par un trait ; listes des droits en puces ; « Afficher les projets » sous le
 * choix du studio.
 */
.oauth-consent__section + .oauth-consent__section {
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: var(--line-width) solid var(--line);
}

.oauth-consent__section > :last-child {
    margin-bottom: 0;
}

.oauth-consent__studio {
    font-weight: var(--font-weight-semibold);
}

.oauth-consent__show {
    margin-top: var(--space-3);
}

.oauth-consent__subtitle {
    margin: var(--space-5) 0 var(--space-2);
    color: var(--ink);
    font: var(--text-body);
    font-weight: var(--font-weight-bold);
}

.oauth-consent__list {
    margin: 0;
    padding-left: var(--space-5);
}

.oauth-consent__list > li + li {
    margin-top: var(--space-2);
}
