@layer theme, base, components, utilities;

/* Cursor pointer on all interactive elements */
a,
button,
[role="button"],
input[type="submit"],
input[type="button"],
input[type="reset"],
select,
summary,
label[for] {
  cursor: pointer;
}

/* Focus clavier uniforme — contour 2px du design system, au clavier
   seulement (:focus-visible, rien au clic souris), champs et cases compris.
   La couleur --focus-ring tient 3:1 dans les deux thèmes (accent 600 en
   clair, 400 en sombre ; QA UX 2026-10-21, R-15). En @layer base et sous
   :where() (spécificité nulle) : les focus explicites gardent la main, qu'ils
   soient en couche components (.form-input), hors couche (.btn-primary,
   .btn-secondary, .radio-pill) ou en utilitaires (focus:outline-none,
   focus-visible:ring-*). Tous reprennent ce même contour. */
@layer base {
  :where(a, button, summary, input, select, textarea, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
  }
}

/* Texte d'un ton sémantique (badges) : la couleur du ton tient mal 4,5:1 sur
   sa propre teinte (3,1:1 en clair). Elle se fonce en clair et s'éclaircit en
   sombre, le ton restant reconnaissable (QA UX 2026-10-21, R-15). */
.text-ton-success { color: color-mix(in srgb, var(--color-success) 60%, black); }
.text-ton-warning { color: color-mix(in srgb, var(--color-warning) 60%, black); }
.text-ton-error { color: color-mix(in srgb, var(--color-error) 60%, black); }
.text-ton-info { color: color-mix(in srgb, var(--color-info) 60%, black); }
.dark .text-ton-success { color: color-mix(in srgb, var(--color-success) 60%, white); }
.dark .text-ton-warning { color: color-mix(in srgb, var(--color-warning) 60%, white); }
.dark .text-ton-error { color: color-mix(in srgb, var(--color-error) 60%, white); }
.dark .text-ton-info { color: color-mix(in srgb, var(--color-info) 60%, white); }

/* Card — rayon lg du design system */
.card {
  @apply bg-white dark:bg-surface-dark border border-black/[0.06] dark:border-white/10;
  border-radius: var(--radius-2xl);
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.04), 0 1px 2px -1px rgba(0, 0, 0, 0.03);
}

.dark .card {
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.3);
}

/* Opt-in hover elevation (Margette feel) */
.hover-lift {
  @apply transition-all duration-200 ease-out;
}

.hover-lift:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.04);
}

/* Densité des lignes dans les widgets priorités / aujourd'hui */
/* Padding réduit — work_item et task ont data-work-sortable-target, rappel non */
.density-compact [data-work-sortable-target="item"],
.density-compact [id$="_priority_row"] {
  padding-top: 0.125rem;
  padding-bottom: 0.125rem;
}
/* Sous-titres masqués (entité liée, délégation, contextes)
   Pas de > : les work_items ont un niveau d'imbrication supplémentaire */
.density-compact .min-w-0.flex-1 p.text-xs,
.density-compact .min-w-0.flex-1 .flex.flex-wrap.gap-1 {
  display: none;
}

/* Garde-fou du téléphone et de la tablette (sous 1024 px ; le bureau ne
   change pas) : la page ne part jamais de côté. Sur un vrai téléphone, un
   élément trop large faisait glisser tout l'écran (et le dézoomait, d'où un
   grand vide sous le pied) au lieu de la seule liste (QA mobile 2026-10-25).
   - main ne défile plus de côté ;
   - un tableau défile dans son propre cadre (le parent qui le contient) ;
   - une rangée de formulaire en flex passe à la ligne. */
@media (max-width: 1023px) {
  /* Le document non plus : un vrai téléphone dézoome dès que la page se
     déclare plus large que l'écran, même sans défilement possible. */
  html,
  body {
    overflow-x: hidden;
  }
  /* main positionné : un élément en position absolue sans ancêtre
     positionné (le libellé sr-only « Actions » d'un en-tête de tableau)
     se plaçait par rapport au document, hors de la zone qui défile, et le
     téléphone élargissait puis dézoomait la page (signalements : 940 px). */
  main {
    position: relative;
    overflow-x: hidden;
  }
  main :where(*):has(> table) {
    position: relative;
    overflow-x: auto;
  }
  main form.flex {
    flex-wrap: wrap;
  }
  /* Une adresse ou un mot sans espace (lien collé dans une note) se coupe. */
  main :where(.prose, .prose-sm) {
    overflow-wrap: anywhere;
  }
}

/* Pied des assistants de création au téléphone : Annuler, Précédent et
   Suivant tiennent sur une ligne (Suivant passait seul à la ligne). */
@media (max-width: 639px) {
  .assistant-pied > :is(.btn-primary, .btn-secondary) {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }
}

/* Tableau à en-tête collant (TableComponent) : sa hauteur n'est bornée qu'à
   partir de 640 px ; au téléphone, c'est la page qui défile. */
@media (min-width: 640px) {
  .table-hauteur-bornee {
    max-height: var(--table-hauteur-max);
  }
}

/* Tableau → cartes au téléphone (sous 640 px), sur le modèle de la ligne de
   Mon travail : un rail de couleur à gauche, le titre en gras, une ligne
   d'infos, des détails « libellé / valeur » deux par ligne, puis les actions.
   Le gabarit choisit ce qu'une carte montre, cellule par cellule ; une
   cellule sans rôle est masquée au téléphone. Un seul DOM : le défilement
   infini et les flux Turbo ajoutent ou remplacent des lignes déjà annotées.
     <table class="… tableau-cartes">
     data-carte="case"     case à cocher (sélection en lot), avant le titre
     data-carte="titre"    le nom, en gras
     data-carte="pastille" l'état, à droite du titre
     data-carte="meta"     une info courte, sur la ligne sous le titre
     data-carte="detail"   un détail ; son libellé : data-libelle="…"
     data-carte="actions"  la rangée d'actions, en bas
   Le rail : data-rail="succes|alerte|erreur|info|neutre" sur la ligne. */
@media (max-width: 639px) {
  table.tableau-cartes,
  table.tableau-cartes > tbody {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
  }
  table.tableau-cartes > thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  table.tableau-cartes > tbody > tr {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: 0.75rem;
    row-gap: 0.375rem;
    padding: 0.875rem 1rem 0.875rem 1rem;
    border-left: 4px solid var(--carte-rail, color-mix(in srgb, var(--color-primary) 55%, transparent));
    /* Pas de fond imposé : la carte qui contient le tableau a le sien, et le
       fond d'une ligne (bg-*, ex. « le client rappellera ») doit rester. */
  }
  table.tableau-cartes > tbody > tr + tr {
    border-top: 1px solid color-mix(in srgb, currentColor 8%, transparent);
  }
  table.tableau-cartes > tbody > tr[data-rail="succes"] { --carte-rail: var(--color-success); }
  table.tableau-cartes > tbody > tr[data-rail="alerte"] { --carte-rail: var(--color-warning); }
  table.tableau-cartes > tbody > tr[data-rail="erreur"] { --carte-rail: var(--color-error); }
  table.tableau-cartes > tbody > tr[data-rail="info"]   { --carte-rail: var(--color-info); }
  table.tableau-cartes > tbody > tr[data-rail="neutre"] { --carte-rail: color-mix(in srgb, currentColor 25%, transparent); }
  /* Saut de ligne après le titre et sa pastille. */
  table.tableau-cartes > tbody > tr::after {
    content: "";
    order: 3;
    flex-basis: 100%;
    height: 0;
  }
  table.tableau-cartes > tbody > tr > td {
    display: none;
    padding: 0 !important;
    border: 0 !important;
    position: static !important;
    background: transparent !important;
    box-shadow: none !important;
    text-align: left !important;
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
  }
  table.tableau-cartes > tbody > tr > td[data-carte] {
    display: block;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="case"] {
    order: 0;
    flex: none;
    padding-top: 0.125rem !important;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="titre"] {
    order: 1;
    flex: 1 1 0;
    font-size: 1rem;
    font-weight: 700;
    line-height: 1.35;
    white-space: normal !important;
    overflow-wrap: anywhere;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="pastille"] {
    order: 2;
    flex: none;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="meta"] {
    order: 4;
    flex: 0 1 auto;
    font-size: 0.8125rem;
    color: var(--color-muted);
    white-space: normal !important;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="detail"] {
    order: 5;
    flex: 1 1 calc(50% - 0.75rem);
    font-size: 0.875rem;
    white-space: normal !important;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="detail"]::before {
    content: attr(data-libelle);
    display: block;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-muted);
  }
  table.tableau-cartes > tbody > tr > td[data-carte="actions"] {
    order: 6;
    flex-basis: 100%;
    padding-top: 0.25rem !important;
  }
  table.tableau-cartes > tbody > tr > td[data-carte="actions"] > * {
    justify-content: flex-start !important;
  }
  /* Les actions sont à gauche de la carte : leurs menus s'ouvrent vers la droite. */
  table.tableau-cartes > tbody > tr > td[data-carte="actions"] .absolute.right-0 {
    right: auto;
    left: 0;
  }
  /* Avec une case, le reste de la carte s'aligne sur le titre. */
  table.tableau-cartes > tbody > tr:has(> td[data-carte="case"]) > td:is([data-carte="meta"], [data-carte="detail"], [data-carte="actions"]):not(:first-child) {
    margin-left: 1.75rem;
  }
  table.tableau-cartes > tbody > tr:has(> td[data-carte="case"]) > td[data-carte="detail"] {
    flex-basis: calc(50% - 1.75rem);
  }
  /* Une ligne ou une cellule cachée (classe hidden d'un filtre, d'un repli,
     de la ligne d'ajout) le reste : ces règles, hors couche, l'emportent
     sinon sur les utilitaires de Tailwind. */
  table.tableau-cartes > tbody > tr:is(.hidden, [hidden]),
  table.tableau-cartes > tbody > tr > td:is(.hidden, [hidden]) {
    display: none !important;
  }
  /* Une ligne sans rôle (message « aucun résultat », pied de tableau) reste lisible. */
  table.tableau-cartes > tbody > tr:not(:has(> td[data-carte])) > td {
    display: block;
    flex-basis: 100%;
  }
}

/* Lignes de travail (work item, tâche, rappel) au téléphone : la case, six
   boutons et la pastille de type ne laissaient au titre aucune largeur (carte
   « Aujourd'hui » du tableau de bord, QA mobile du 2026-10-25). Le titre prend
   la première ligne, les actions passent dessous. La page Mon travail
   (.priorities-page) a sa propre mise en page, qui prime là où elle le dit. */
@media (max-width: 639px) {
  [id^="work_item_"][data-work-item-id],
  [id^="priority_row_task_"],
  [id^="priority_row_rappel_"] {
    flex-wrap: wrap;
    row-gap: 0.25rem;
  }
  [id^="work_item_"][data-work-item-id] > div.flex-1.min-w-0,
  [id^="priority_row_task_"] > div.flex-1.min-w-0,
  [id^="priority_row_rappel_"] > div.flex-1.min-w-0 {
    flex-basis: calc(100% - 2rem);
  }
  /* Deuxième ligne : la pastille du type à gauche, sous le crochet ; les
     boutons à droite (demande de Martin, 2026-10-25). */
  [id^="work_item_"][data-work-item-id] > *,
  [id^="priority_row_task_"] > *,
  [id^="priority_row_rappel_"] > * {
    order: 2;
  }
  [id^="work_item_"][data-work-item-id] > :first-child,
  [id^="work_item_"][data-work-item-id] > div.flex-1.min-w-0,
  [id^="priority_row_task_"] > :first-child,
  [id^="priority_row_task_"] > div.flex-1.min-w-0,
  [id^="priority_row_rappel_"] > :first-child,
  [id^="priority_row_rappel_"] > div.flex-1.min-w-0 {
    order: 0;
  }
  [id^="work_item_"][data-work-item-id] > [data-controller~="work-item-kind-picker"],
  [id^="priority_row_task_"] > div:has(> span.badge),
  [id^="priority_row_rappel_"] > div:has(> span.badge) {
    order: 1;
    margin-right: auto;
  }
}

/* Form fields — single source of truth for input styling across the app.
   Wrapped in @layer components so Tailwind utilities (in the later `utilities`
   layer) compose and override naturally: `form-input pl-10` for a search icon,
   `form-input bg-black/5` for readonly, etc. — no `!important` needed. */
@layer components {
  .form-input {
    @apply w-full px-4 py-1.5 text-sm transition-all duration-150;
    background: var(--surface);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    --tw-border-style: solid;
    border-style: solid;
    min-height: 2rem;
  }

  .form-input::placeholder {
    color: var(--text-muted);
  }

  .form-input:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
    border-color: var(--focus-ring);
  }

  select.form-input {
    height: calc(1.25rem + 0.75rem + 2px); /* 34px — aligned with text inputs */
  }

  .form-input:disabled {
    background: var(--surface-2);
    color: var(--text-muted);
    opacity: 0.55;
    cursor: not-allowed;
  }

  .form-input-error,
  .field_with_errors .form-input,
  .form-input[aria-invalid="true"] {
    border-color: var(--color-error);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 15%, transparent);
  }

  /* Compact variant for table cells / inline filters */
  .form-input-sm {
    @apply w-full px-3 py-1.5 text-sm transition-all duration-150;
    background: var(--surface);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    --tw-border-style: solid;
    border-style: solid;
    height: 2.25rem;
  }

  .form-input-sm:focus {
    outline: 2px solid var(--focus-ring);
    outline-offset: 1px;
    border-color: var(--focus-ring);
  }

  /* Libellé et case à cocher — source unique de FormFieldComponent,
     SelectFieldComponent et CheckboxFieldComponent, et des vues qui posent
     ces classes à la main. En mode sombre, dark_mode.css force la teinte
     secondaire de .form-label, comme pour text-black/70. */
  .form-label {
    @apply block text-sm font-medium text-black/70 dark:text-white/70 mb-1;
  }

  .form-checkbox {
    @apply rounded border-black/20 dark:border-white/20 text-primary;
  }
}

/* Page Title — Geologica semibold, soulignement copper. */
.page-title {
  @apply relative pb-3 tracking-tight;
  font-family: var(--font-display);
  font-size: 1.75rem; /* 28px — h1 */
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: -0.02em;
}

.page-title::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 2.25rem;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
}

/* Breadcrumb */
.breadcrumb {
  @apply flex items-center gap-2 text-sm text-black/60 dark:text-white/60 mb-1;
}

/* Badge — pill shape, hauteur fixe, look premium */
.badge {
  @apply inline-flex items-center justify-center gap-1 h-6 min-h-6 px-2.5 text-[11px] font-semibold leading-none tracking-wide rounded-full whitespace-nowrap;
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04);
}

.badge-fixed {
  @apply min-w-[5.5rem] text-center;
}

/* Page Header Layout — titre et actions côte à côte seulement en grand écran :
   de 640 à 1024 px (tablette, zoom à 200 %), les actions passaient sous le
   bord droit (QA UX itération 2, N-08). Elles passent dessous, et à la ligne. */
.page-header-layout {
  @apply flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4;
}

/* Alert Error */
.alert-error {
  @apply p-4 rounded-lg;
  background: color-mix(in srgb, var(--error) 8%, transparent);
  border-left: 4px solid var(--error);
}

/* Primary Button — copper plein, --on-accent au repos, blanc au hover/active. */
.btn-primary {
  @apply inline-flex items-center justify-center gap-2 px-5 py-1.5 text-sm font-semibold transition-all duration-150 cursor-pointer;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 14px -4px rgba(0, 0, 0, 0.25), 0 1px 2px 0 rgba(0, 0, 0, 0.08);
}

.btn-primary:hover {
  background: var(--accent-600);
  color: var(--on-accent-strong);
  transform: translateY(-1px);
}

.btn-primary:active {
  background: var(--accent-800);
  color: var(--on-accent-strong);
  transform: scale(0.98);
}

.btn-primary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.btn-primary:disabled,
.btn-primary[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  transform: none;
  pointer-events: none;
}

/* Fix for submit buttons in dark mode — couleur pilotée par les tokens */
.dark input[type="submit"].btn-primary,
.dark button[type="submit"].btn-primary {
  background-color: var(--accent) !important;
  color: var(--on-accent) !important;
}

.dark input[type="submit"].btn-primary:hover,
.dark button[type="submit"].btn-primary:hover {
  background-color: var(--accent-600) !important;
  color: var(--on-accent-strong) !important;
}

/* Secondary Button — contour */
.btn-secondary {
  @apply inline-flex items-center justify-center gap-2 px-5 py-1.5 text-sm font-medium transition-all duration-150;
  color: var(--text-primary);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.btn-secondary:hover {
  background: var(--surface-2);
}

.btn-secondary:active {
  background: var(--surface-2);
  border-color: var(--accent);
  transform: scale(0.98);
}

.btn-secondary:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.btn-secondary:disabled,
.btn-secondary[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* Soft semantic buttons — error & success tokens du design system */
.btn-error-soft {
  background: color-mix(in srgb, var(--color-error) 12%, transparent);
  color: var(--color-error);
}
.btn-error-soft:hover {
  background: color-mix(in srgb, var(--color-error) 22%, transparent);
}

.btn-success-soft {
  background: color-mix(in srgb, var(--color-success) 12%, transparent);
  color: var(--color-success);
}
.btn-success-soft:hover {
  background: color-mix(in srgb, var(--color-success) 22%, transparent);
}

/* Petite taille de bouton — hors couche exprès : .btn-primary et .btn-secondary
   sont hors couche, ils battraient les utilitaires de taille (px-3 py-1 text-xs)
   de ButtonComponent(size: :sm). Placée après eux pour l'emporter à
   spécificité égale. */
.btn-sm {
  @apply px-3 py-1 text-xs gap-1.5;
}

/* Icon Button */
.icon-button {
  @apply p-2 text-black/60 dark:text-white/60 hover:text-primary hover:bg-primary/10 rounded-lg active:scale-95 transition-all duration-150;
}

/* Card Header */
.card-header {
  @apply px-5 py-4 border-b border-black/5 dark:border-white/5;
}

/* Sticky column edges — box-shadow simulates borders that survive
   border-collapse + sticky horizontal scroll. */
.sticky-col-end {
  box-shadow: 1px 0 0 0 rgb(0 0 0 / 0.1);
}
.dark .sticky-col-end {
  box-shadow: 1px 0 0 0 rgb(255 255 255 / 0.1);
}
.sticky-col-start {
  box-shadow: -1px 0 0 0 rgb(0 0 0 / 0.1);
}
.dark .sticky-col-start {
  box-shadow: -1px 0 0 0 rgb(255 255 255 / 0.1);
}

/* Table styles — airier vertical rhythm.
   Dans @layer components pour la même raison que .form-input : hors couche,
   ces règles battaient les utilitaires, et `table-header-cell text-right`,
   `table-cell py-8` ou `table-cell text-black/60` restaient sans effet.
   Les variantes .table-compact plus bas restent hors couche exprès : elles
   doivent battre les utilitaires des boutons, badges et icônes. */
@layer components {
  .table-header-cell {
    @apply px-6 py-1.5 text-left text-xs font-medium text-black/50 dark:text-white/50;
  }

  .table-row {
    @apply transition-colors hover:bg-black/[0.02] dark:hover:bg-white/[0.05];
  }

  .table-cell {
    @apply px-6 py-1.5 text-sm text-black/90 dark:text-white;
  }

  .table-cell-secondary {
    @apply px-6 py-1.5 text-sm text-black/60 dark:text-white/60;
  }

  .table-actions {
    @apply flex items-center justify-end gap-2;
  }
}

/* Variante compacte — pour les tables qui affichent beaucoup de lignes à la
   fois (liste des tâches d'une enveloppe). La hauteur d'une ligne n'est pas
   dictée par le texte mais par les boutons d'action (p-1.5 + icône 16px) et
   les badges (h-6) : on réduit les trois ensemble, sinon rien ne bouge. */
.table-comfortable .table-header-cell {
  @apply py-2.5;
}
.table-comfortable .table-cell {
  @apply py-2.5;
}

.table-compact .table-header-cell {
  @apply px-2 py-0.5 text-[10px] leading-tight;
}

.table-compact .table-cell {
  @apply px-2 py-0.5 text-xs leading-tight;
}

.table-compact .table-cell-secondary {
  @apply px-2 py-0.5 text-[11px] leading-tight;
}

.table-compact .badge {
  @apply h-[18px] min-h-[18px] px-1.5 text-[10px];
}

.table-compact .badge-fixed {
  @apply min-w-[3.75rem];
}

.table-compact :is(a, button).rounded-md {
  @apply p-0.5;
}

.table-compact td svg,
.table-compact th svg {
  @apply w-3 h-3;
}

/* Édition inline : sans ça, passer une cellule en édition ferait bondir la
   ligne (hauteur fixe de .form-input-sm à 2.25rem). */
.table-compact .form-input-sm {
  @apply py-0 px-1.5 text-[11px];
  height: 1.5rem;
}

/* Badge variants */
.badge-success {
  @apply inline-flex items-center justify-center gap-1 h-6 min-h-6 min-w-[5.5rem] px-2.5 text-[11px] font-semibold leading-none tracking-wide rounded-full whitespace-nowrap text-center bg-success/12 text-success border border-success/30;
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04);
}

.badge-neutral {
  @apply inline-flex items-center justify-center gap-1 h-6 min-h-6 min-w-[5.5rem] px-2.5 text-[11px] font-semibold leading-none tracking-wide rounded-full whitespace-nowrap text-center bg-surface-2 text-muted border border-border;
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04);
}

/* Danger Button (delete) */
.btn-danger {
  @apply p-2 text-black/60 dark:text-white/60 hover:text-error hover:bg-error/12 rounded-lg transition-colors;
}

/* Modal Overlay */
.modal-overlay {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 50;
  align-items: center;
  justify-content: center;
  background-color: rgb(0 0 0 / 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.modal-overlay.hidden {
  display: none;
}

/* Boîte de confirmation (lib/confirmation.js) — <dialog> natif */
.confirmation-dialog {
  padding: 0;
  border: none;
  background: transparent;
  margin: auto;
  width: calc(100% - 2rem);
  max-width: 28rem;
  overflow: visible;
}

.confirmation-dialog::backdrop {
  background-color: rgb(0 0 0 / 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

/* Card footer */
.card-footer {
  @apply px-6 py-1.5 border-t border-black/5 dark:border-white/5 bg-surface-2;
  border-bottom-left-radius: var(--radius-2xl);
  border-bottom-right-radius: var(--radius-2xl);
}

/* WorkItem tabs (Priorisation widget) */
.work-tab {
  @apply border-black/10 dark:border-white/10 text-black/70 dark:text-white/70 hover:text-primary hover:border-primary/40;
}

.work-tab-active {
  @apply bg-primary/10 text-primary border-primary/40;
}

/* Radio pill group — segmented filter control */
.radio-pill-group {
  @apply inline-flex items-center rounded-lg border border-black/10 dark:border-white/10 bg-black/[0.03] dark:bg-white/[0.05] p-0.5 gap-0.5;
}

.radio-pill-text {
  @apply block px-3 py-1.5 text-sm font-medium rounded-md cursor-pointer transition-all text-black/55 dark:text-white/55 select-none;
}

.radio-pill:hover .radio-pill-text {
  @apply text-black/80 dark:text-white/80;
}

.radio-pill input:checked + .radio-pill-text {
  @apply bg-white dark:bg-surface-dark text-primary shadow-sm;
}

.radio-pill input:focus-visible + .radio-pill-text {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Même filtre en liens ou en boutons (shared/_segmented_links, contextes des
   priorités) : l'option active prend le rendu d'un radio coché. Le survol
   exclut l'option active, sans quoi a.radio-pill-text:hover (plus spécifique)
   lui retirerait son texte cuivré. */
.radio-pill-text.is-active {
  @apply bg-white dark:bg-surface-dark text-primary shadow-sm;
}

a.radio-pill-text:not(.is-active):hover,
button.radio-pill-text:not(.is-active):hover {
  @apply text-black/80 dark:text-white/80;
}

/* ────────────────────────────────────────────────────────────────────
   MOBILE — Priorities page
   Spectacular touch-first treatment activated below lg breakpoint.
   ──────────────────────────────────────────────────────────────────── */

/* Mobile pill (filter strip in priorisation widget) — when active,
   gets a stronger fill and a subtle ring glow for tactile feedback. */
.mobile-pill.work-tab-active {
  @apply bg-primary text-on-accent border-primary;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 35%, transparent);
}
.mobile-pill.work-tab-active span {
  @apply text-white opacity-100;
}

/* Hide the native scrollbar for the mobile pill strip — keeps it clean. */
.mobile-pill-scroll {
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.mobile-pill-scroll::-webkit-scrollbar {
  display: none;
}

/* Bottom-sheet quick-add: kind selector buttons */
.mobile-kind-btn {
  @apply border-black/10 dark:border-white/10 text-black/65 dark:text-white/65;
}
.mobile-kind-active {
  @apply bg-primary/10 dark:bg-primary/15 border-primary/40 text-primary;
}

/* ─── Mobile section visibility ─── */
/* On lg+, both sections are always visible regardless of any `hidden`
   class the mobile controller may toggle — Tailwind's `display: flex`
   from `flex` is reasserted so the desktop two-column layout never
   collapses. */
@media (min-width: 1024px) {
  .mobile-section {
    display: flex !important;
  }
}

/* ─── Hero (warm cream) ─── */
.mobile-hero {
  background: linear-gradient(180deg, rgb(254 243 226) 0%, rgb(254 248 240) 100%);
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.dark .mobile-hero {
  background: linear-gradient(180deg, rgb(35 28 22) 0%, rgb(28 24 20) 100%);
  border-bottom-color: rgba(255, 255, 255, 0.06);
}
.mobile-hero-title {
  text-transform: none;
  letter-spacing: -0.02em;
}

/* ─── Bottom navigation (mobile only) ─── */
.mobile-bottom-nav {
  /* Subtle elevation away from content */
  box-shadow: 0 -4px 24px -8px rgba(0, 0, 0, 0.12);
  background-color: rgb(254 250 245 / 0.95) !important;
}
.dark .mobile-bottom-nav {
  box-shadow: 0 -4px 24px -8px rgba(0, 0, 0, 0.5);
  background-color: rgb(28 24 20 / 0.95) !important;
}
/* iPhone home-bar safe-area cushion */
.mobile-bottom-nav-safe {
  height: env(safe-area-inset-bottom, 0px);
}
.mobile-nav-tab {
  @apply text-black/55 dark:text-white/55;
}
.mobile-nav-tab .mobile-nav-icon-wrap {
  position: relative;
  padding: 0.25rem 0.625rem;
  border-radius: 0.625rem;
  transition: background-color 200ms;
}
.mobile-nav-active {
  color: rgb(234 88 12); /* orange-600 */
}
.dark .mobile-nav-active {
  color: rgb(251 146 60); /* orange-400 */
}
.mobile-nav-active .mobile-nav-icon-wrap {
  background: rgb(254 215 170); /* orange-200 */
}
.dark .mobile-nav-active .mobile-nav-icon-wrap {
  background: rgb(154 52 18 / 0.4); /* orange-900 tinted */
}
.mobile-nav-active .mobile-nav-indicator {
  display: none; /* indicator replaced by the rounded highlight bg */
}

/* FAB sits above the bottom-nav (≈ 64px) plus iPhone safe-area inset. */
.mobile-fab {
  bottom: calc(5rem + env(safe-area-inset-bottom, 0px));
}

/* Mobile-only refinements scoped to the priorities page.
   Premium card treatment: borderless + soft elevation + stagger fade-in. */
@media (max-width: 1023px) {
  .priorities-page #today_widget,
  .priorities-page #prioritization_widget {
    @apply border-0;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px -8px rgba(0, 0, 0, 0.08);
  }
  .dark .priorities-page #today_widget,
  .dark .priorities-page #prioritization_widget {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -8px rgba(0, 0, 0, 0.5);
  }

  /* The desktop inline quick-add is redundant on mobile (FAB handles it).
     Force-hide regardless of work-tabs controller state. */
  .priorities-page [data-work-tabs-target="quickAdd"] {
    display: none !important;
  }

  /* Bottom-pad scrollable areas so the bottom-nav (≈64px) + FAB don't
     cover the last row. Includes iPhone safe-area inset. */
  .priorities-page #today_widget > .overflow-y-auto,
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"] {
    padding-bottom: calc(7rem + env(safe-area-inset-bottom, 0px));
  }

  /* Container — keep the existing `divide-y` hairlines (they're clean)
     but ensure backgrounds and padding are right for the rail look. */
  .priorities-page #today_widget > .divide-y,
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"].divide-y,
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"] > .divide-y {
    background: white;
  }
  .dark .priorities-page #today_widget > .divide-y,
  .dark .priorities-page #prioritization_widget [data-work-tabs-target="panel"].divide-y,
  .dark .priorities-page #prioritization_widget [data-work-tabs-target="panel"] > .divide-y {
    background: var(--color-surface-dark);
  }

  /* Each item is a continuous "rail" row — flat, no individual card
     chrome, hairline divider between (provided by partial's divide-y).
     The colored left edge IS the rail; it spans full row height and
     reads as a continuous chromatic ribbon from top to bottom. */
  .priorities-page [id^="work_item_"],
  .priorities-page [id^="priority_row_task_"] {
    flex-wrap: wrap !important;
    align-items: flex-start !important;
    column-gap: 0.5rem !important;
    row-gap: 0.625rem !important;
    padding: 1rem 1rem 1rem 1.25rem !important;
    border-left: 5px solid rgb(148 163 184); /* slate-400 fallback */
    background: white;
    position: relative;
  }
  .dark .priorities-page [id^="work_item_"],
  .dark .priorities-page [id^="priority_row_task_"] {
    background: var(--color-surface-dark);
  }

  /* Kind-coded rails. Pure color, no fill — the rail itself is the
     statement. */
  .priorities-page [data-kind="todo"]       { border-left-color: rgb(59 130 246); }
  .priorities-page [data-kind="follow_up"]  { border-left-color: rgb(249 115 22); }
  .priorities-page [data-kind="commitment"] { border-left-color: rgb(168 85 247); }
  .priorities-page [data-kind="task"]       { border-left-color: rgb(16 185 129); }

  /* Mode compact sur mobile : la page impose ses marges en !important, il
     faut donc le redire ici. Une seule ligne par élément — case, titre,
     aujourd'hui, priorité ; échéance, délégation, lien, notes et type restent
     en mode standard. */
  .priorities-page .density-compact [id^="work_item_"],
  .priorities-page .density-compact [id^="priority_row_task_"],
  .priorities-page .density-compact [id^="priority_row_rappel_"] {
    flex-wrap: nowrap !important;
    align-items: center !important;
    row-gap: 0 !important;
    padding: 0.5rem 0.75rem 0.5rem 1rem !important;
  }
  .priorities-page .density-compact [data-action~="work-item-date-modal#open"],
  .priorities-page .density-compact [data-action~="work-item-delegate-modal#open"],
  .priorities-page .density-compact [data-action~="work-item-link-modal#open"],
  .priorities-page .density-compact [data-action~="notes-modal#open"],
  .priorities-page .density-compact [data-controller~="work-item-kind-picker"] {
    display: none !important;
  }
  .priorities-page .density-compact [id^="work_item_"] [data-inline-edit-target="display"] > div > button.truncate,
  .priorities-page .density-compact [id^="priority_row_task_"] a.truncate {
    font-size: 0.9375rem !important;
  }

  /* Title — bigger, bolder, mixed-case (override Megabyte uppercase). */
  .priorities-page [id^="work_item_"] [data-inline-edit-target="display"] > div > button.truncate,
  .priorities-page [id^="priority_row_task_"] a.truncate {
    font-size: 1rem !important;
    font-weight: 700 !important;
    letter-spacing: -0.005em;
  }

  /* Convert the kind chip pill into inline caps text — same idea as
     the reference: "TÂCHE · subject" without the rounded background. */
  .priorities-page [id^="work_item_"] > div[data-controller*="work-item-kind-picker"] > button.badge,
  .priorities-page [id^="priority_row_task_"] > span.badge {
    background: transparent !important;
    border: 0 !important;
    padding: 0 !important;
    min-width: 0 !important;
    font-family: 'Megabyte', sans-serif !important;
    font-size: 0.6875rem !important;
    font-weight: 700 !important;
    letter-spacing: 0.12em !important;
    text-transform: uppercase !important;
  }
  .priorities-page [id^="work_item_"] > div[data-controller*="work-item-kind-picker"] > button.badge svg,
  .priorities-page [id^="priority_row_task_"] > span.badge svg {
    display: none !important;
  }
  /* Color the caps text in the kind hue. */
  .priorities-page [data-kind="todo"] > div[data-controller*="work-item-kind-picker"] > button.badge       { color: rgb(37 99 235); }
  .priorities-page [data-kind="follow_up"] > div[data-controller*="work-item-kind-picker"] > button.badge  { color: rgb(194 65 12); }
  .priorities-page [data-kind="commitment"] > div[data-controller*="work-item-kind-picker"] > button.badge { color: rgb(126 34 206); }
  .priorities-page [data-kind="task"] > span.badge { color: rgb(4 120 87); }
  .dark .priorities-page [data-kind="todo"] > div[data-controller*="work-item-kind-picker"] > button.badge       { color: rgb(96 165 250); }
  .dark .priorities-page [data-kind="follow_up"] > div[data-controller*="work-item-kind-picker"] > button.badge  { color: rgb(251 146 60); }
  .dark .priorities-page [data-kind="commitment"] > div[data-controller*="work-item-kind-picker"] > button.badge { color: rgb(192 132 252); }
  .dark .priorities-page [data-kind="task"] > span.badge { color: rgb(52 211 153); }
  /* Title column claims ~all remaining width, pushing siblings to row 2. */
  .priorities-page [id^="work_item_"] > div.flex-1.min-w-0,
  .priorities-page [id^="priority_row_task_"] > div.flex-1.min-w-0 {
    flex: 1 1 calc(100% - 2rem) !important;
    min-width: 0;
  }
  /* Allow row titles to wrap on 2 lines (override `truncate` from the
     shared partial) so users can read the full content on a phone. */
  .priorities-page [id^="work_item_"] [data-inline-edit-target="display"] > div > button.truncate,
  .priorities-page [id^="priority_row_task_"] a.truncate {
    display: -webkit-box !important;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    white-space: normal !important;
    overflow: hidden !important;
    text-overflow: initial !important;
    line-height: 1.35;
    font-size: 0.95rem;
  }

  /* Hide rarely-used action buttons on mobile: deleguer, lier, et les
     spacers correspondants dans les rows de tâches. Decongèle la rangée
     d'actions pour ne laisser que ce qui est utilisé fréquemment au
     pouce : aujourd'hui (☀), prioritaire (🚩), date (📅), notes, type. */
  .priorities-page [id^="work_item_"] > button[title="Déléguer"],
  .priorities-page [id^="work_item_"] > button[title^="Délégué à"],
  .priorities-page [id^="work_item_"] > button[title^="Reçu de"],
  .priorities-page [id^="work_item_"] > button[title="Lier à une entité"],
  .priorities-page [id^="work_item_"] > button[title^="Lié à"],
  .priorities-page [id^="priority_row_task_"] > button[title="Déléguer"],
  .priorities-page [id^="priority_row_task_"] > button[title^="Assignée à"],
  .priorities-page [id^="priority_row_task_"] > span.shrink-0.w-6.h-6 {
    display: none !important;
  }

  /* Indent the action row so it sits flush with the title (skip the
     checkbox column). The 3rd direct child is always the first
     element of row 2 — checkbox/leading-link is 1st, title block is
     2nd. Margin matches the checkbox width + first column-gap. */
  .priorities-page [id^="work_item_"] > *:nth-child(3),
  .priorities-page [id^="priority_row_task_"] > *:nth-child(3) {
    margin-left: 1.75rem !important;
  }

  /* Hide the scrollbar inside the scrollable widget panes — content
     remains scrollable but the chrome stays clean. */
  .priorities-page #today_widget > .overflow-y-auto,
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"] {
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .priorities-page #today_widget > .overflow-y-auto::-webkit-scrollbar,
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
  }

  /* Stagger fade-in of items on initial paint — first ~5 visible rows. */
  .priorities-page #today_widget > div > [id],
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]:not(.hidden) > div > [id] {
    animation: priority-row-in 420ms cubic-bezier(.21,.61,.35,1) both;
  }
  .priorities-page #today_widget > div > [id]:nth-child(2),
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]:not(.hidden) > div > [id]:nth-child(2) { animation-delay: 50ms; }
  .priorities-page #today_widget > div > [id]:nth-child(3),
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]:not(.hidden) > div > [id]:nth-child(3) { animation-delay: 100ms; }
  .priorities-page #today_widget > div > [id]:nth-child(4),
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]:not(.hidden) > div > [id]:nth-child(4) { animation-delay: 150ms; }
  .priorities-page #today_widget > div > [id]:nth-child(n+5),
  .priorities-page #prioritization_widget [data-work-tabs-target="panel"]:not(.hidden) > div > [id]:nth-child(n+5) { animation-delay: 200ms; }
}

@keyframes priority-row-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Normalize select to match text inputs */
select.form-input,
select.form-input-sm {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' viewBox='0 0 24 24' stroke='%236b7280' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M19 9l-7 7-7-7'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  padding-right: 2.25rem;
}
select.form-input {
  @apply h-[34px];
}

/* Time tracking styles */
@keyframes timer-pulse {
  0%, 100% {
    border-color: rgb(34 197 94);
    background-color: rgb(240 253 244);
  }
  50% {
    border-color: rgb(22 163 74);
    background-color: rgb(220 252 231);
  }
}

@keyframes timer-pulse-dark {
  0%, 100% {
    border-color: rgb(34 197 94);
    background-color: rgb(34 197 94 / 0.1);
  }
  50% {
    border-color: rgb(22 163 74);
    background-color: rgb(34 197 94 / 0.15);
  }
}

.timer-running {
  @apply border-l-4;
  animation: timer-pulse 2s ease-in-out infinite;
}

.dark .timer-running {
  animation: timer-pulse-dark 2s ease-in-out infinite;
}

/* Timer spinning icon */
@keyframes timer-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.timer-spin {
  animation: timer-spin 3s linear infinite;
  transform-origin: center;
}

.time-cell {
  @apply w-full px-1 py-1 text-center text-sm tabular-nums bg-transparent border border-transparent rounded
         hover:border-black/10 dark:hover:border-white/10
         focus:border-primary focus:ring-1 focus:ring-primary focus:outline-none
         text-black/90 dark:text-white;
  font-family: var(--font-mono);
}

.week-grid-day-col {
  @apply w-20 min-w-[5rem] max-w-[5rem] px-2 py-1.5 text-center align-middle;
}

.week-grid-total-col {
  @apply w-24 min-w-[6rem] max-w-[6rem] px-2 py-1.5 text-center align-middle;
}

.week-grid-day-header {
  @apply px-2 py-1.5 text-center text-xs font-medium text-black/50 dark:text-white/50 align-middle;
}

.week-grid-num {
  @apply text-sm tabular-nums text-black/90 dark:text-white;
  font-family: var(--font-mono);
}

.time-cell::-webkit-inner-spin-button,
.time-cell::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.time-cell[type=number] {
  -moz-appearance: textfield;
}

.week-day-cell {
  @apply px-3 py-1.5 text-center rounded-md transition-colors;
}

.week-day-cell.is-selected {
  @apply bg-white dark:bg-surface-dark shadow-sm;
}

.week-day-cell.is-today {
  @apply text-primary font-medium;
}

/* ── Contrôles désactivés ────────────────────────────────────────────────────

   Un contrôle désactivé doit SE VOIR désactivé. Sans ces règles, un bouton mort
   gardait sa couleur pleine, son ombre, son curseur en main et son soulèvement
   au survol : le seul retour au clic était l'absence de retour, et l'écran
   passait pour cassé alors qu'il attendait simplement quelque chose.

   Le signal qui compte le plus est le CURSEUR, parce qu'il arrive avant le clic.
   La règle du haut de ce fichier pose `cursor: pointer` sur tous les `button`,
   `select` et `a` — désactivés compris : elle promettait un clic qui n'arrivait
   jamais. C'est cette promesse qu'on retire ici.

   Rien ne touche à la couleur de fond : `.btn-primary` la pose en `!important`
   en mode sombre, et l'opacité éteint l'ensemble sans entrer dans cette
   bataille.

   `[aria-disabled="true"]` accompagne `[disabled]` : ce qui ne peut pas porter
   l'attribut natif (un lien, un `div` en rôle bouton) annonce son état ainsi, et
   le style doit suivre l'intention annoncée, pas seulement l'attribut HTML. */
[disabled],
[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.5;
  box-shadow: none;
}

/* Un `fieldset` désactivé porte DÉJÀ l'estompage pour tout ce qu'il contient :
   on ne réclame ici que le curseur. Estomper aussi les enfants multiplierait les
   deux opacités (0,5 × 0,5) et rendrait le bloc illisible. */
fieldset[disabled] :where(button, input, select, textarea) {
  cursor: not-allowed;
}

/* Le survol ne doit RIEN promettre : ni soulèvement, ni enfoncement au clic.
   Ces deux règles arrivent après `.btn-primary:hover` et pèsent autant, donc
   elles l'emportent — c'est voulu, ne pas les remonter dans le fichier. */
[disabled]:hover,
[disabled]:active,
[aria-disabled="true"]:hover,
[aria-disabled="true"]:active {
  transform: none;
}

/* Les champs de saisie font exception à l'estompage : le texte déjà saisi doit
   rester LISIBLE (un identifiant, un montant reporté d'ailleurs). On garde donc
   l'opacité pleine et on marque l'inertie par le fond — le même traitement que
   `FormFieldComponent` applique déjà à ses champs en lecture seule. */
.form-input:disabled,
.form-input[readonly],
.form-input-sm:disabled,
.form-input-sm[readonly] {
  @apply bg-black/5 dark:bg-white/5 text-black/50 dark:text-white/50;
  opacity: 1;
  cursor: not-allowed;
}

/* Bouton "définir comme défaut" sur les cellules cible — visible au hover du td */
td .set-default-btn { opacity: 0; transition: opacity 0.15s; }
td:hover .set-default-btn { opacity: 1; }

/* <turbo-frame> est un élément custom (inline par défaut) : en bloc, sinon
   les paddings/marges verticaux des frames-onglets (pt-8…) sont sans effet. */
turbo-frame { display: block; }
turbo-frame[hidden], turbo-frame.hidden { display: none; }

/* Sur papier, la navigation ne sert à rien (le reste de l'interface se retire
   dans le gabarit, par print:hidden). */
@media print {
  .breadcrumb { display: none; }
}

/* Questionnaire imprimé, comme la v2.4 : chaque question garde seulement le
   choix retenu, écrit en clair (le fond du choix coché ne sort pas sur papier,
   et son texte blanc disparaîtrait) ; les champs restés vides s'effacent. */
@media print {
  #questionnaire-formulaire [role="radiogroup"] {
    display: block;
    max-width: none;
    border: 0;
  }
  #questionnaire-formulaire [role="radiogroup"] > label:not(:has(input:checked)),
  #questionnaire-formulaire input:placeholder-shown {
    display: none;
  }
  #questionnaire-formulaire [role="radiogroup"] > label:has(input:checked) {
    display: block;
    width: fit-content;
    text-align: left;
    color: var(--text-primary);
    background: none;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
  }
}
